/// <summary> /// Filter the license plate to remove noise /// </summary> /// <param name="plate">The license plate image</param> /// <returns>License plate image without the noise</returns> private static UMat FilterPlate(UMat plate, int threshold_parameter) { UMat thresh = new UMat(); //Modify line height(modifica captura de linea por color de pixel) CvInvoke.Threshold(plate, thresh, threshold_parameter, 255, ThresholdType.BinaryInv); //Image<Gray, Byte> thresh = plate.ThresholdBinaryInv(new Gray(120), new Gray(255)); SaveImageClass.SaveImage(plate, "plate.jpg"); Size plateSize = plate.Size; using (Mat plateMask = new Mat(plateSize.Height, plateSize.Width, DepthType.Cv8U, 1)) using (Mat plateCanny = new Mat()) using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { plateMask.SetTo(new MCvScalar(255.0)); CvInvoke.Canny(plate, plateCanny, 100, 50); CvInvoke.FindContours(plateCanny, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple); int count = contours.Size; for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) { Rectangle rect = CvInvoke.BoundingRectangle(contour); if (rect.Height > (plateSize.Height >> 1)) { rect.X -= 1; rect.Y -= 1; rect.Width += 2; rect.Height += 2; Rectangle roi = new Rectangle(Point.Empty, plate.Size); rect.Intersect(roi); CvInvoke.Rectangle(plateMask, rect, new MCvScalar(), -1); //plateMask.Draw(rect, new Gray(0.0), -1); } } } thresh.SetTo(new MCvScalar(), plateMask); } SaveImageClass.SaveImage(thresh, "thresh1.jpg"); CvInvoke.Erode(thresh, thresh, null, new Point(-1, -1), 1, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue); SaveImageClass.SaveImage(thresh, "threshErode.jpg"); CvInvoke.Dilate(thresh, thresh, null, new Point(-1, -1), 1, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue); SaveImageClass.SaveImage(thresh, "threshDilate.jpg"); return(thresh); }
private void FindLicensePlate( VectorOfVectorOfPoint contours, int[,] hierachy, int idx, IInputArray gray, IInputArray canny, List <IInputOutputArray> licensePlateImagesList, List <IInputOutputArray> filteredLicensePlateImagesList, List <RotatedRect> detectedLicensePlateRegionList, List <String> licenses, int ocr_mode, int threshold_parameter) { for (; idx >= 0; idx = hierachy[idx, 0]) { int numberOfChildren = GetNumberOfChildren(hierachy, idx); //if it does not contains any children (charactor), it is not a license plate region if (numberOfChildren == 0) { continue; } using (VectorOfPoint contour = contours[idx]) { if (CvInvoke.ContourArea(contour) > 400) { if (numberOfChildren < 6) { //If the contour has less than 6 children, it is not a license plate (assuming license plate has at least 3 charactor) //However we should search the children of this contour to see if any of them is a license plate FindLicensePlate(contours, hierachy, hierachy[idx, 2], gray, canny, licensePlateImagesList, filteredLicensePlateImagesList, detectedLicensePlateRegionList, licenses, ocr_mode, threshold_parameter); continue; } RotatedRect box = CvInvoke.MinAreaRect(contour); if (box.Angle < -45.0) { float tmp = box.Size.Width; box.Size.Width = box.Size.Height; box.Size.Height = tmp; box.Angle += 90.0f; } else if (box.Angle > 45.0) { float tmp = box.Size.Width; box.Size.Width = box.Size.Height; box.Size.Height = tmp; box.Angle -= 90.0f; } double whRatio = (double)box.Size.Width / box.Size.Height; if (!(3.0 < whRatio && whRatio < 10.0)) //if (!(1.0 < whRatio && whRatio < 2.0)) { //if the width height ratio is not in the specific range,it is not a license plate //However we should search the children of this contour to see if any of them is a license plate //Contour<Point> child = contours.VNext; if (hierachy[idx, 2] > 0) { FindLicensePlate(contours, hierachy, hierachy[idx, 2], gray, canny, licensePlateImagesList, filteredLicensePlateImagesList, detectedLicensePlateRegionList, licenses, ocr_mode, threshold_parameter); } continue; } using (UMat tmp1 = new UMat()) using (UMat tmp2 = new UMat()) { PointF[] srcCorners = box.GetVertices(); PointF[] destCorners = new PointF[] { new PointF(0, box.Size.Height - 1), new PointF(0, 0), new PointF(box.Size.Width - 1, 0), new PointF(box.Size.Width - 1, box.Size.Height - 1) }; using (Mat rot = CvInvoke.GetAffineTransform(srcCorners, destCorners)) { //box.Center.X -= 20; //box.Size.Height += 20; //box.Size.Width += 20; //box.Center.Y -= 20; CvInvoke.WarpAffine(gray, tmp1, rot, Size.Round(box.Size)); } SaveImageClass.SaveImage(gray, "gray2.jpg"); SaveImageClass.SaveImage(tmp1, "tmp1.jpg"); //resize the license plate such that the front is ~ 10-12. This size of front results in better accuracy from tesseract Size approxSize = new Size(240, 180); double scale = Math.Min(approxSize.Width / box.Size.Width, approxSize.Height / box.Size.Height); Size newSize = new Size((int)Math.Round(box.Size.Width * scale), (int)Math.Round(box.Size.Height * scale)); CvInvoke.Resize(tmp1, tmp2, newSize, 0, 0, Inter.Cubic); SaveImageClass.SaveImage(tmp1, "tmp1after.jpg"); SaveImageClass.SaveImage(tmp2, "tmp2.jpg"); //removes some pixels from the edge int edgePixelSize = 3; Rectangle newRoi = new Rectangle(new Point(edgePixelSize, edgePixelSize), tmp2.Size - new Size(2 * edgePixelSize, 2 * edgePixelSize)); UMat plate = new UMat(tmp2, newRoi); SaveImageClass.SaveImage(plate, "plate.jpg"); UMat filteredPlate = new UMat(); filteredPlate = FilterPlate(plate, threshold_parameter); SaveImageClass.SaveImage(filteredPlate, "filtered.jpg"); StringBuilder strBuilder = new StringBuilder(); switch (ocr_mode) { case 1: { strBuilder = TesseractOCR.GetText(filteredPlate, _ocr); break; } case 2: { strBuilder = GoogleApiOCR.GetText(filteredPlate); break; } case 3: { strBuilder = ComputerVisionOCR.GetText(filteredPlate); break; } default: break; } if (strBuilder != null) { licenses.Add(strBuilder.ToString()); licensePlateImagesList.Add(plate); filteredLicensePlateImagesList.Add(filteredPlate); detectedLicensePlateRegionList.Add(box); } } } } } }
/* * /// <summary> * /// Compute the white pixel mask for the given image. * /// A white pixel is a pixel where: saturation < 40 AND value > 200 * /// </summary> * /// <param name="image">The color image to find white mask from</param> * /// <returns>The white pixel mask</returns> * private static Image<Gray, Byte> GetWhitePixelMask(Image<Bgr, byte> image) * { * using (Image<Hsv, Byte> hsv = image.Convert<Hsv, Byte>()) * { * Image<Gray, Byte>[] channels = hsv.Split(); * * try * { * //channels[1] is the mask for satuation less than 40, this is the mask for either white or black pixels * channels[1]._ThresholdBinaryInv(new Gray(40), new Gray(255)); * * //channels[2] is the mask for bright pixels * channels[2]._ThresholdBinary(new Gray(200), new Gray(255)); * * CvInvoke.BitwiseAnd(channels[1], channels[2], channels[0], null); * } * finally * { * channels[1].Dispose(); * channels[2].Dispose(); * } * return channels[0]; * } * }*/ /// <summary> /// Detect license plate from the given image /// </summary> /// <param name="img">The image to search license plate from</param> /// <param name="licensePlateImagesList">A list of images where the detected license plate regions are stored</param> /// <param name="filteredLicensePlateImagesList">A list of images where the detected license plate regions (with noise removed) are stored</param> /// <param name="detectedLicensePlateRegionList">A list where the regions of license plate (defined by an MCvBox2D) are stored</param> /// <param name="ocr_mode">Bool to check the ocr mode </param> /// <param name="canny_thres">Canny threshold will take 3 values 20, 30, 40, 50</param> /// <returns>The list of words for each license plate</returns> /// <returns></returns> public List <String> DetectLicensePlate( IInputArray img, List <IInputOutputArray> licensePlateImagesList, List <IInputOutputArray> filteredLicensePlateImagesList, List <RotatedRect> detectedLicensePlateRegionList, int ocr_mode) { List <String> licenses = new List <String>(); using (Mat gray = new Mat()) using (Mat canny = new Mat()) using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.CvtColor(img, gray, ColorConversion.Bgr2Gray); CvInvoke.Canny(gray, canny, 100, 50, 3, false); int[,] hierachy = CvInvoke.FindContourTree(canny, contours, ChainApproxMethod.ChainApproxSimple); SaveImageClass.SaveImage(gray, "gray.jpg"); SaveImageClass.SaveImage(canny, "canny.jpg"); for (int i = 0; i <= 5; i++) { switch (i) { case 0: { FindLicensePlate(contours, hierachy, 0, gray, canny, licensePlateImagesList, filteredLicensePlateImagesList, detectedLicensePlateRegionList, licenses, ocr_mode, 80); break; } case 1: { FindLicensePlate(contours, hierachy, 0, gray, canny, licensePlateImagesList, filteredLicensePlateImagesList, detectedLicensePlateRegionList, licenses, ocr_mode, 100); break; } case 2: { FindLicensePlate(contours, hierachy, 0, gray, canny, licensePlateImagesList, filteredLicensePlateImagesList, detectedLicensePlateRegionList, licenses, ocr_mode, 120); break; } case 3: { FindLicensePlate(contours, hierachy, 0, gray, canny, licensePlateImagesList, filteredLicensePlateImagesList, detectedLicensePlateRegionList, licenses, ocr_mode, 130); break; } case 4: { FindLicensePlate(contours, hierachy, 0, gray, canny, licensePlateImagesList, filteredLicensePlateImagesList, detectedLicensePlateRegionList, licenses, ocr_mode, 150); break; } case 5: { FindLicensePlate(contours, hierachy, 0, gray, canny, licensePlateImagesList, filteredLicensePlateImagesList, detectedLicensePlateRegionList, licenses, ocr_mode, 170); break; } default: break; } } } return(licenses); }