static void Main(string[] args) { int errorCode = 0; TextRecognizer.InitTextRecognizer(); InitParameters(); //foreach (var file in Directory.EnumerateFiles(@"D:\Imagini ANPR auto\1", "*.jpg")) foreach (var file in Directory.EnumerateFiles(@"D:\Imagini ANPR auto\5", "2*.png")) { Stopwatch watch = Stopwatch.StartNew(); // time the detection process Mat imgOriginal = new Mat(file); Mat imgGrayScale = new Mat(); Mat imgThresh = new Mat(); List <KeyValuePair <string, bool> > licensePlateNumber = new List <KeyValuePair <string, bool> >(); ImageProcess.Preprocess(imgOriginal, ref imgGrayScale, ref imgThresh, ref errorCode); if (Properties.Settings.Default.debug) { CvInvoke.Imshow("Original image", imgOriginal); CvInvoke.Imshow("Threshold", imgThresh); } List <KeyValuePair <Mat, Mat> > licensePlates = PlateExtraction.DetectPlate(imgGrayScale, imgThresh, ref errorCode); foreach (var licensePlate in licensePlates) { if (licensePlate.Value != null) { licensePlateNumber.Add(TextRecognizer.RecognizeText(licensePlate.Value)); } } foreach (KeyValuePair <string, bool> pair in licensePlateNumber) { if (pair.Value == true) { Console.WriteLine("License plate # " + pair.Key); break; } else { Console.WriteLine("License plate # " + LicensePlateRegex.LicensePlateNumberProcess(pair.Key)); } } watch.Stop(); //stop the timer Console.WriteLine(watch.Elapsed); CvInvoke.WaitKey(); CvInvoke.DestroyAllWindows(); } Console.ReadLine(); }
public static KeyValuePair <string, bool> RecognizeText(Mat imgInput) { VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); List <ContoursWithData> listOfContoursWithData = new List <ContoursWithData>(); // declare a list of contours with data CvInvoke.FindContours(imgInput, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple); //imgInput.Save(@"D:\Visual Studio Projects\KNNtrain\Imagini\4\" + i + ".jpg"); //i++; // populate list of contours with data for (int i = 0; i <= contours.Size - 1; i++) // for each contour { if ((CvInvoke.ContourArea(contours[i]) > MIN_CONTOUR_AREA)) { ContoursWithData contourWithData = new ContoursWithData(); // declare new contour with data contourWithData.contour = contours[i]; // populate contour member variable contourWithData.boundingRectangle = CvInvoke.BoundingRectangle(contourWithData.contour); // calculate bounding rectangle contourWithData.dblArea = CvInvoke.ContourArea(contourWithData.contour); // calculate area if (contourWithData.checkIfContourIsValid()) { listOfContoursWithData.Add(contourWithData);// add to list of contours with data } else { if (contourWithData.boundingRectangle.Width > Properties.Settings.Default.boundingRectangleWidthMax) { Mat imgROItoBeCloned = new Mat(imgInput, contourWithData.boundingRectangle); Mat imgROI = imgROItoBeCloned.Clone(); Rectangle rectangleFirst = new Rectangle(0, 0, contourWithData.boundingRectangle.Width / 2, contourWithData.boundingRectangle.Height); Rectangle rectangleSecond = new Rectangle(contourWithData.boundingRectangle.Width / 2, 0, contourWithData.boundingRectangle.Width / 2, contourWithData.boundingRectangle.Height); Mat firstImage = new Mat(imgROI, rectangleFirst); Mat secondImage = new Mat(imgROI, rectangleSecond); VectorOfVectorOfPoint contoursSplitImage = new VectorOfVectorOfPoint(); CvInvoke.FindContours(firstImage, contoursSplitImage, null, RetrType.External, ChainApproxMethod.ChainApproxSimple); for (int j = 0; j <= contoursSplitImage.Size - 1; j++) // for each contour { if ((CvInvoke.ContourArea(contoursSplitImage[j]) > MIN_CONTOUR_AREA)) { ContoursWithData contourWithDataFirstImage = new ContoursWithData(); // declare new contour with data contourWithDataFirstImage.contour = contoursSplitImage[j]; // populate contour member variable contourWithDataFirstImage.boundingRectangle = CvInvoke.BoundingRectangle(contourWithDataFirstImage.contour); // calculate bounding rectangle contourWithDataFirstImage.boundingRectangle.X = contourWithData.boundingRectangle.X; contourWithDataFirstImage.boundingRectangle.Y = contourWithData.boundingRectangle.Y; contourWithDataFirstImage.dblArea = CvInvoke.ContourArea(contourWithDataFirstImage.contour); // calculate area if (contourWithDataFirstImage.checkIfContourIsValid()) { listOfContoursWithData.Add(contourWithDataFirstImage);// add to list of contours with data } } } contoursSplitImage = new VectorOfVectorOfPoint(); CvInvoke.FindContours(secondImage, contoursSplitImage, null, RetrType.External, ChainApproxMethod.ChainApproxSimple); for (int j = 0; j <= contoursSplitImage.Size - 1; j++) // for each contour { if ((CvInvoke.ContourArea(contoursSplitImage[j]) > MIN_CONTOUR_AREA)) { ContoursWithData contourWithDataSecondImage = new ContoursWithData(); // declare new contour with data contourWithDataSecondImage.contour = contoursSplitImage[j]; // populate contour member variable contourWithDataSecondImage.boundingRectangle = CvInvoke.BoundingRectangle(contourWithDataSecondImage.contour); // calculate bounding rectangle contourWithDataSecondImage.boundingRectangle.X = contourWithData.boundingRectangle.X + contourWithData.boundingRectangle.Width / 2; contourWithDataSecondImage.boundingRectangle.Y = contourWithData.boundingRectangle.Y; contourWithDataSecondImage.dblArea = CvInvoke.ContourArea(contourWithDataSecondImage.contour); // calculate area if (contourWithDataSecondImage.checkIfContourIsValid()) { listOfContoursWithData.Add(contourWithDataSecondImage);// add to list of contours with data } } } } } } } float averageLocationY = 0; float sumLocationY = 0; foreach (var item in listOfContoursWithData) { sumLocationY += item.boundingRectangle.Y + item.boundingRectangle.Height / 2; } averageLocationY = sumLocationY / listOfContoursWithData.Count; float minLocationY = averageLocationY - 0.15f * averageLocationY; float maxLocationY = averageLocationY + 0.15f * averageLocationY; listOfContoursWithData.RemoveAll(x => minLocationY > x.boundingRectangle.Y + x.boundingRectangle.Height / 2 || maxLocationY < x.boundingRectangle.Y + x.boundingRectangle.Height / 2); // sort contours with data from left to right listOfContoursWithData.Sort((oneContourWithData, otherContourWithData) => oneContourWithData.boundingRectangle.X.CompareTo(otherContourWithData.boundingRectangle.X)); string strFinalString = ""; // declare final string, this will have the final number sequence by the end of the program foreach (ContoursWithData contourWithData in listOfContoursWithData) // for each contour in list of valid contours { CvInvoke.Rectangle(imgInput, contourWithData.boundingRectangle, new MCvScalar(200, 0.0, 0.0), 2); // draw green rect around the current char Mat imgROItoBeCloned = new Mat(imgInput, contourWithData.boundingRectangle); // get ROI image of bounding rect Mat imgROI = imgROItoBeCloned.Clone(); // clone ROI image so we don't change original when we resize Mat imgROIResized = new Mat(); // resize image, this is necessary for char recognition CvInvoke.Resize(imgROI, imgROIResized, new System.Drawing.Size(RESIZED_IMAGE_WIDTH, RESIZED_IMAGE_HEIGHT)); // declare a Matrix of the same dimensions as the Image we are adding to the data structure of training images Matrix <float> mtxTemp = new Matrix <float>(imgROIResized.Size); // declare a flattened (only 1 row) matrix of the same total size Matrix <float> mtxTempReshaped = new Matrix <float>(1, RESIZED_IMAGE_WIDTH * RESIZED_IMAGE_HEIGHT); imgROIResized.ConvertTo(mtxTemp, DepthType.Cv32F); // convert Image to a Matrix of Singles with the same dimensions for (int intRow = 0; intRow <= RESIZED_IMAGE_HEIGHT - 1; intRow++) // flatten Matrix into one row by RESIZED_IMAGE_WIDTH * RESIZED_IMAGE_HEIGHT number of columns { for (int intCol = 0; intCol <= RESIZED_IMAGE_WIDTH - 1; intCol++) { mtxTempReshaped[0, (intRow * RESIZED_IMAGE_WIDTH) + intCol] = mtxTemp[intRow, intCol]; } } float sngCurrentChar; sngCurrentChar = kNearest.Predict(mtxTempReshaped); // finally we can call Predict !!! strFinalString = strFinalString + (char)(Convert.ToInt32(sngCurrentChar)); // append current char to full string of chars } bool licensePlateRegex = LicensePlateRegex.MatchRegex(strFinalString); return(new KeyValuePair <string, bool>(strFinalString, licensePlateRegex)); }