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(); }
/// <summary> /// /// </summary> /// <param name="potentialPlates">List of potentials plates</param> /// <param name="pass">What pass is executing</param> /// <param name="errorCode">Error code</param> /// <returns>Key value pair of license plate image and its treshold</returns> private static KeyValuePair <Mat, Mat> FindPlateInPotentialPlates(List <Mat> potentialPlates, string pass, ref int errorCode) { // Initiate license plate variable KeyValuePair <Mat, Mat> licensePlate = new KeyValuePair <Mat, Mat>(); // Initiate variable for if license plate was found bool licensePlateFound = false; try { // Check what pass if (pass == "firstPass") { // Loop through all potential plates foreach (var potentialPlate in potentialPlates) { // Initate images used Mat imgBilateralFilter = new Mat(); Mat imgThresh = new Mat(); Mat imgOpen = new Mat(); // Initiate structuring elements used in morphological procedures Mat structuringElement = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(150, 150), new Point(-1, -1)); Mat openElement = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(7, 7), new Point(-1, -1)); Mat closeElement = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(8, 15), new Point(-1, -1)); Mat erodeElement = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1)); // Initiate other variables VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); List <Rectangle> boundingRectangles = new List <Rectangle>(); // Maximize contrast of a potential plate Mat imgMaxContrast = ImageProcess.MaximizeContrast(potentialPlate, ref errorCode); // Apply bilateral filter to image with contrast maximized CvInvoke.BilateralFilter(imgMaxContrast, imgBilateralFilter, 5, 20, 20); // 40 20 20 // Do morphological operation of tophat CvInvoke.MorphologyEx(imgBilateralFilter, imgOpen, MorphOp.Tophat, structuringElement, new Point(-1, -1), 2, BorderType.Default, new MCvScalar()); // Do adaptive treshold to tophat image CvInvoke.AdaptiveThreshold(imgOpen, imgThresh, 255, AdaptiveThresholdType.GaussianC, ThresholdType.BinaryInv, 295, 19); // first pass // Do morphological operation of open to thresholded image CvInvoke.MorphologyEx(imgThresh, imgThresh, MorphOp.Open, openElement, new Point(-1, -1), 1, BorderType.Default, new MCvScalar()); // Do morphological operation of erode to open image CvInvoke.MorphologyEx(imgThresh, imgThresh, MorphOp.Erode, erodeElement, new Point(-1, -1), 1, BorderType.Constant, new MCvScalar()); // Do morphological operation of close to thresholded image CvInvoke.MorphologyEx(imgThresh, imgThresh, MorphOp.Close, closeElement, new Point(-1, -1), 1, BorderType.Constant, new MCvScalar()); // Find contours in erode image CvInvoke.FindContours(imgThresh, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple); Image <Bgr, byte> imgContours = imgThresh.ToImage <Bgr, byte>(); // Loop through found contours for (int i = 0; i < contours.Size; i++) { // Create a bounding rectangle of the contour var boundingRectangle = CvInvoke.BoundingRectangle(contours[i]); // Check if contour has required dimensions if (boundingRectangle.Height >= Properties.Settings.Default.boundingRectangleHeightMin && boundingRectangle.Height <= Properties.Settings.Default.boundingRectangleHeightMax && boundingRectangle.Width <= Properties.Settings.Default.boundingRectangleWidthMax) { CvInvoke.Rectangle(imgContours, boundingRectangle, new MCvScalar(0, 0, 255)); // Add bounding rectangle to the list of bounding rectangles boundingRectangles.Add(boundingRectangle); } } // Check if the list of bounding rectangles has the required number of items if (boundingRectangles.Count >= 5 && boundingRectangles.Count <= 9) { // Make a key value pair with the cropped image and its threshold licensePlate = new KeyValuePair <Mat, Mat>(potentialPlate, imgThresh); licensePlateFound = true; // Check if debug enabled if (Properties.Settings.Default.debug) { // Show image of plate segmented CvInvoke.Imshow("Plate segmented first pass", imgContours.Mat); //CvInvoke.Imshow("Plate segmented first pass", potentialPlate); } // Stop from searching further break; } } } else if (pass == "secondPass") { foreach (var potentialPlate in potentialPlates) { // Initate images used Mat imgBilateralFilter = new Mat(); Mat imgThresh = new Mat(); Mat imgOpen = new Mat(); // Initiate structuring elements used in morphological procedures Mat structuringElement = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(150, 150), new Point(-1, -1)); Mat openElement = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(7, 7), new Point(-1, -1)); Mat closeElement = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(5, 5), new Point(-1, -1)); Mat erodeElement = CvInvoke.GetStructuringElement(ElementShape.Ellipse, new Size(3, 3), new Point(-1, -1)); // Initiate other variables VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); List <Rectangle> boundingRectangles = new List <Rectangle>(); // Maximize contrast of a potential plate Mat imgMaxContrast = ImageProcess.MaximizeContrast(potentialPlate, ref errorCode); // Apply bilateral filter to image with contrast maximized CvInvoke.BilateralFilter(imgMaxContrast, imgBilateralFilter, 5, 10, 10); // 20 10 10 // Do morphological operation of tophat CvInvoke.MorphologyEx(imgBilateralFilter, imgOpen, MorphOp.Tophat, structuringElement, new Point(-1, -1), 1, BorderType.Default, new MCvScalar()); // Do adaptive treshold to tophat image CvInvoke.AdaptiveThreshold(imgOpen, imgThresh, 255, AdaptiveThresholdType.GaussianC, ThresholdType.BinaryInv, 105, 5); // second pass // Do morphological operation of open to thresholded image CvInvoke.MorphologyEx(imgThresh, imgThresh, MorphOp.Open, openElement, new Point(-1, -1), 1, BorderType.Constant, new MCvScalar()); // Do morphological operation of erode to open image CvInvoke.MorphologyEx(imgThresh, imgThresh, MorphOp.Erode, erodeElement, new Point(-1, -1), 1, BorderType.Constant, new MCvScalar()); // Do morphological operation of close to thresholded image CvInvoke.MorphologyEx(imgThresh, imgThresh, MorphOp.Close, closeElement, new Point(-1, -1), 1, BorderType.Constant, new MCvScalar()); // Find contours in erode image CvInvoke.FindContours(imgThresh, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple); Image <Bgr, byte> imgContours = imgThresh.ToImage <Bgr, byte>(); // Loop through found contours for (int i = 0; i < contours.Size; i++) { // Create a bounding rectangle of the contour var boundingRectangle = CvInvoke.BoundingRectangle(contours[i]); // Check if contour has required dimensions if (boundingRectangle.Height >= Properties.Settings.Default.boundingRectangleHeightMin && boundingRectangle.Height <= Properties.Settings.Default.boundingRectangleHeightMax) { CvInvoke.Rectangle(imgContours, boundingRectangle, new MCvScalar(0, 0, 255)); // Add bounding rectangle to the list of bounding rectangles boundingRectangles.Add(boundingRectangle); } } // Check if the list of bounding rectangles has the required number of items if (boundingRectangles.Count >= 5 && boundingRectangles.Count <= 9) { // Make a key value pair with the cropped image and its threshold licensePlate = new KeyValuePair <Mat, Mat>(potentialPlate, imgThresh); licensePlateFound = true; // Check if debug enabled if (Properties.Settings.Default.debug) { // Show image of plate segmented CvInvoke.Imshow("Plate segmented second pass", imgContours.Mat); //CvInvoke.Imshow("Plate segmented second pass", potentialPlate); } // Stop from searching further break; } } } // Check if license plate has been found if (!licensePlateFound) { // Return null return(new KeyValuePair <Mat, Mat>()); } else { // Return the key value pair return(licensePlate); } } catch (Exception ex) { Console.WriteLine(ex); errorCode = 8; return(new KeyValuePair <Mat, Mat>()); } }