Exemplo n.º 1
0
        ///''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        public PossiblePlate extractPlate(Mat imgOriginal, List <PossibleChar> listOfMatchingChars)
        {
            PossiblePlate possiblePlate = new PossiblePlate();

            //this will be the return value

            //sort chars from left to right based on x position
            listOfMatchingChars.Sort((firstChar, secondChar) => firstChar.intCenterX.CompareTo(secondChar.intCenterX));

            //calculate the center point of the plate
            double dblPlateCenterX = Convert.ToDouble(listOfMatchingChars[0].intCenterX + listOfMatchingChars[listOfMatchingChars.Count - 1].intCenterX) / 2.0;
            double dblPlateCenterY = Convert.ToDouble(listOfMatchingChars[0].intCenterY + listOfMatchingChars[listOfMatchingChars.Count - 1].intCenterY) / 2.0;
            PointF ptfPlateCenter  = new PointF(Convert.ToSingle(dblPlateCenterX), Convert.ToSingle(dblPlateCenterY));

            //calculate plate width and height
            int intPlateWidth = Convert.ToInt32(Convert.ToDouble(listOfMatchingChars[listOfMatchingChars.Count - 1].boundingRect.X + listOfMatchingChars[listOfMatchingChars.Count - 1].boundingRect.Width - listOfMatchingChars[0].boundingRect.X) * PLATE_WIDTH_PADDING_FACTOR);

            int intTotalOfCharHeights = 0;

            foreach (PossibleChar matchingChar in listOfMatchingChars)
            {
                intTotalOfCharHeights = intTotalOfCharHeights + matchingChar.boundingRect.Height;
            }

            double dblAverageCharHeight = Convert.ToDouble(intTotalOfCharHeights) / Convert.ToDouble(listOfMatchingChars.Count);

            object intPlateHeight = Convert.ToInt32(dblAverageCharHeight * PLATE_HEIGHT_PADDING_FACTOR);

            //calculate correction angle of plate region
            double dblOpposite             = listOfMatchingChars[listOfMatchingChars.Count - 1].intCenterY - listOfMatchingChars[0].intCenterY;
            double dblHypotenuse           = detectChars.distanceBetweenChars(listOfMatchingChars[0], listOfMatchingChars[listOfMatchingChars.Count - 1]);
            double dblCorrectionAngleInRad = Math.Asin(dblOpposite / dblHypotenuse);
            double dblCorrectionAngleInDeg = dblCorrectionAngleInRad * (180.0 / Math.PI);

            //assign rotated rect member variable of possible plate
            possiblePlate.rrLocationOfPlateInScene = new RotatedRect(ptfPlateCenter, new SizeF(Convert.ToSingle(intPlateWidth), Convert.ToSingle(intPlateHeight)), Convert.ToSingle(dblCorrectionAngleInDeg));

            Mat rotationMatrix = new Mat();
            //final steps are to perform the actual rotation
            Mat imgRotated = new Mat();
            Mat imgCropped = new Mat();

            CvInvoke.GetRotationMatrix2D(ptfPlateCenter, dblCorrectionAngleInDeg, 1.0, rotationMatrix);
            //get the rotation matrix for our calculated correction angle

            CvInvoke.WarpAffine(imgOriginal, imgRotated, rotationMatrix, imgOriginal.Size);
            //rotate the entire image

            //crop out the actual plate portion of the rotated image
            CvInvoke.GetRectSubPix(imgRotated, possiblePlate.rrLocationOfPlateInScene.MinAreaRect().Size, possiblePlate.rrLocationOfPlateInScene.Center, imgCropped);

            possiblePlate.imgPlate = imgCropped;
            //copy the cropped plate image into the applicable member variable of the possible plate

            return(possiblePlate);
        }
        ///''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        public void writeLicensePlateCharsOnImage(ref Mat imgOriginalScene, PossiblePlate licPlate)
        {
            Point ptCenterOfTextArea = new Point();
            //this will be the center of the area the text will be written to
            Point ptLowerLeftTextOrigin = new Point();
            //this will be the bottom left of the area that the text will be written to

            FontFace fontFace = FontFace.HersheySimplex;
            //choose a plain jane font
            double dblFontScale = licPlate.imgPlate.Height / 30;
            //base font scale on height of plate area
            int intFontThickness = Convert.ToInt32(dblFontScale * 1.5);
            //base font thickness on font scale
            Size textSize = new Size();

            //to get the text size, we should use the OpenCV function getTextSize, but for some reason Emgu CV does not include this
            //we can instead estimate the test size based on the font scale, this will not be especially accurate but is good enough for our purposes here
            textSize.Width  = Convert.ToInt32(dblFontScale * 18.5 * licPlate.strChars.Length);
            textSize.Height = Convert.ToInt32(dblFontScale * 25);

            ptCenterOfTextArea.X = Convert.ToInt32(licPlate.rrLocationOfPlateInScene.Center.X);
            //the horizontal location of the text area is the same as the plate

            //if the license plate is in the upper 3/4 of the image, we will write the chars in below the plate
            if ((licPlate.rrLocationOfPlateInScene.Center.Y < (imgOriginalScene.Height * 0.75)))
            {
                ptCenterOfTextArea.Y = Convert.ToInt32(licPlate.rrLocationOfPlateInScene.Center.Y + Convert.ToInt32(Convert.ToDouble(licPlate.rrLocationOfPlateInScene.MinAreaRect().Height) * 1.6));
                //else if the license plate is in the lower 1/4 of the image, we will write the chars in above the plate
            }
            else
            {
                ptCenterOfTextArea.Y = Convert.ToInt32(licPlate.rrLocationOfPlateInScene.Center.Y - Convert.ToInt32(Convert.ToDouble(licPlate.rrLocationOfPlateInScene.MinAreaRect().Height) * 1.6));
            }

            ptLowerLeftTextOrigin.X = Convert.ToInt32(ptCenterOfTextArea.X - (textSize.Width / 2));
            //calculate the lower left origin of the text area
            ptLowerLeftTextOrigin.Y = Convert.ToInt32(ptCenterOfTextArea.Y + (textSize.Height / 2));
            //based on the text area center, width, and height

            CvInvoke.PutText(imgOriginalScene, licPlate.strChars, ptLowerLeftTextOrigin, fontFace, dblFontScale, SCALAR_YELLOW, intFontThickness);
            //write the text on the image
        }
        ///''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        public void drawRedRectangleAroundPlate(Mat imgOriginalScene, PossiblePlate licPlate)
        {
            PointF[] ptfRectPoints = new PointF[5];
            //declare array of 4 points, floating point type

            ptfRectPoints = licPlate.rrLocationOfPlateInScene.GetVertices();
            //get 4 vertices of rotated rect

            Point pt0 = new Point(Convert.ToInt32(ptfRectPoints[0].X), Convert.ToInt32(ptfRectPoints[0].Y));
            //declare 4 points, integer type
            Point pt1 = new Point(Convert.ToInt32(ptfRectPoints[1].X), Convert.ToInt32(ptfRectPoints[1].Y));
            Point pt2 = new Point(Convert.ToInt32(ptfRectPoints[2].X), Convert.ToInt32(ptfRectPoints[2].Y));
            Point pt3 = new Point(Convert.ToInt32(ptfRectPoints[3].X), Convert.ToInt32(ptfRectPoints[3].Y));

            CvInvoke.Line(imgOriginalScene, pt0, pt1, SCALAR_RED, 2);
            //draw 4 red lines
            CvInvoke.Line(imgOriginalScene, pt1, pt2, SCALAR_RED, 2);
            CvInvoke.Line(imgOriginalScene, pt2, pt3, SCALAR_RED, 2);
            CvInvoke.Line(imgOriginalScene, pt3, pt0, SCALAR_RED, 2);
        }
        private void btnOpenFile_Click(object sender, EventArgs e)
        {
            Mat imgOriginalScene = new Mat();
            //this is the original image scene

            bool blnImageOpenedSuccessfully = openImageWithErrorHandling(ref imgOriginalScene);

            //attempt to open image

            //if image was not opened successfully
            if ((!blnImageOpenedSuccessfully))
            {
                ibOriginal.Image = null;
                //set the image box on the form to blank
                return;
                //and bail
            }

            lblChosenFile.Text = ofdOpenFile.FileName;
            //update label with file name

            CvInvoke.DestroyAllWindows();
            //close any windows that are open from previous button press

            ibOriginal.Image = imgOriginalScene;
            //show original image on main form

            List <PossiblePlate> listOfPossiblePlates = detectPlates.detectPlatesInScene(imgOriginalScene);

            //detect plates

            listOfPossiblePlates = detectChars.detectCharsInPlates(listOfPossiblePlates);
            //detect chars in plates

            //check if list of plates is null or zero
            if ((listOfPossiblePlates == null))
            {
                txtInfo.AppendText("\r\n" + "no license plates were detected" + "\r\n");
            }
            else if ((listOfPossiblePlates.Count == 0))
            {
                txtInfo.AppendText("\r\n" + "no license plates were detected" + "\r\n");
            }
            else
            {
                //if we get in here list of possible plates has at leat one plate

                //sort the list of possible plates in DESCENDING order (most number of chars to least number of chars)
                listOfPossiblePlates.Sort((onePlate, otherPlate) => otherPlate.strChars.Length.CompareTo(onePlate.strChars.Length));

                //suppose the plate with the most recognized chars
                PossiblePlate licPlate = listOfPossiblePlates[0];
                //(the first plate in sorted by string length descending order)
                //is the actual plate

                CvInvoke.Imshow("final imgPlate", licPlate.imgPlate);
                //show the final color plate image
                CvInvoke.Imshow("final imgThresh", licPlate.imgThresh);
                //show the final thresh plate image

                //if no chars are present in the lic plate,
                if ((licPlate.strChars.Length == 0))
                {
                    txtInfo.AppendText("\r\n" + "no characters were detected" + licPlate.strChars + "\r\n");
                    //update info text box
                    return;
                    //and return
                }

                drawRedRectangleAroundPlate(imgOriginalScene, licPlate);
                //draw red rectangle around plate

                txtInfo.AppendText("\r\n" + "license plate read from image = " + licPlate.strChars + "\r\n");
                //write license plate text to text box
                txtInfo.AppendText("\r\n" + "----------------------------------------" + "\r\n");

                writeLicensePlateCharsOnImage(ref imgOriginalScene, licPlate);
                //write license plate text on the image

                ibOriginal.Image = imgOriginalScene;
                //update image on main form

                CvInvoke.Imwrite("imgOriginalScene.png", imgOriginalScene);
                //write image out to file
            }
        }
Exemplo n.º 5
0
        ///''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        public List <PossiblePlate> detectPlatesInScene(Mat imgOriginalScene)
        {
            List <PossiblePlate> listOfPossiblePlates = new List <PossiblePlate>();
            //this will be the return value

            Mat imgGrayscaleScene = new Mat();
            Mat imgThreshScene    = new Mat();
            Mat imgContours       = new Mat(imgOriginalScene.Size, DepthType.Cv8U, 3);

            Random random = new Random();

            CvInvoke.DestroyAllWindows();

            // show steps '''''''''''''''''''''''''''''''''
            if ((frm.cbShowSteps.Checked == true))
            {
                CvInvoke.Imshow("0", imgOriginalScene);
            }
            // show steps '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

            Preprocess.preprocess(imgOriginalScene, ref imgGrayscaleScene, ref imgThreshScene);
            //preprocess to get grayscale and threshold images

            // show steps '''''''''''''''''''''''''''''''''
            if ((frm.cbShowSteps.Checked == true))
            {
                CvInvoke.Imshow("1a", imgGrayscaleScene);
                CvInvoke.Imshow("1b", imgThreshScene);
            }
            // show steps '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

            //find all possible chars in the scene,
            //this function first finds all contours, then only includes contours that could be chars (without comparison to other chars yet)
            List <PossibleChar> listOfPossibleCharsInScene = findPossibleCharsInScene(imgThreshScene);

            // show steps '''''''''''''''''''''''''''''''''
            if ((frm.cbShowSteps.Checked == true))
            {
                frm.txtInfo.AppendText("step 2 - listOfPossibleCharsInScene.Count = " + listOfPossibleCharsInScene.Count.ToString() + "\r\n");
                //131 with MCLRNF1 image

                VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();

                foreach (PossibleChar possibleChar in listOfPossibleCharsInScene)
                {
                    contours.Push(possibleChar.contour);
                }

                CvInvoke.DrawContours(imgContours, contours, -1, SCALAR_WHITE);
                CvInvoke.Imshow("2b", imgContours);
            }
            // show steps '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

            //given a list of all possible chars, find groups of matching chars
            //in the next steps each group of matching chars will attempt to be recognized as a plate
            List <List <PossibleChar> > listOfListsOfMatchingCharsInScene = detectChars.findListOfListsOfMatchingChars(listOfPossibleCharsInScene);

            // show steps '''''''''''''''''''''''''''''''''
            if ((frm.cbShowSteps.Checked == true))
            {
                frm.txtInfo.AppendText("step 3 - listOfListsOfMatchingCharsInScene.Count = " + listOfListsOfMatchingCharsInScene.Count.ToString() + "\r\n");
                //13 with MCLRNF1 image

                imgContours = new Mat(imgOriginalScene.Size, DepthType.Cv8U, 3);

                foreach (List <PossibleChar> listOfMatchingChars in listOfListsOfMatchingCharsInScene)
                {
                    object intRandomBlue  = random.Next(0, 256);
                    object intRandomGreen = random.Next(0, 256);
                    object intRandomRed   = random.Next(0, 256);

                    VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();

                    foreach (PossibleChar matchingChar in listOfMatchingChars)
                    {
                        contours.Push(matchingChar.contour);
                    }

                    CvInvoke.DrawContours(imgContours, contours, -1, new MCvScalar(Convert.ToDouble(intRandomBlue), Convert.ToDouble(intRandomGreen), Convert.ToDouble(intRandomRed)));
                }
                CvInvoke.Imshow("3", imgContours);
            }
            // show steps '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

            //for each group of matching chars
            foreach (List <PossibleChar> listOfMatchingChars in listOfListsOfMatchingCharsInScene)
            {
                PossiblePlate possiblePlate = extractPlate(imgOriginalScene, listOfMatchingChars);
                //attempt to extract plate

                //if plate was found
                if (((possiblePlate.imgPlate != null)))
                {
                    listOfPossiblePlates.Add(possiblePlate);
                    //add to list of possible plates
                }
            }

            frm.txtInfo.AppendText("\r\n" + listOfPossiblePlates.Count.ToString() + " possible plates found" + "\r\n");
            //update text box with # of plates found

            // show steps '''''''''''''''''''''''''''''''''
            if ((frm.cbShowSteps.Checked == true))
            {
                frm.txtInfo.AppendText("\r\n");
                CvInvoke.Imshow("4a", imgContours);

                for (int i = 0; i <= listOfPossiblePlates.Count - 1; i++)
                {
                    PointF[] ptfRectPoints = new PointF[5];

                    ptfRectPoints = listOfPossiblePlates[i].rrLocationOfPlateInScene.GetVertices();

                    Point pt0 = new Point(Convert.ToInt32(ptfRectPoints[0].X), Convert.ToInt32(ptfRectPoints[0].Y));
                    Point pt1 = new Point(Convert.ToInt32(ptfRectPoints[1].X), Convert.ToInt32(ptfRectPoints[1].Y));
                    Point pt2 = new Point(Convert.ToInt32(ptfRectPoints[2].X), Convert.ToInt32(ptfRectPoints[2].Y));
                    Point pt3 = new Point(Convert.ToInt32(ptfRectPoints[3].X), Convert.ToInt32(ptfRectPoints[3].Y));

                    CvInvoke.Line(imgContours, pt0, pt1, SCALAR_RED, 2);
                    CvInvoke.Line(imgContours, pt1, pt2, SCALAR_RED, 2);
                    CvInvoke.Line(imgContours, pt2, pt3, SCALAR_RED, 2);
                    CvInvoke.Line(imgContours, pt3, pt0, SCALAR_RED, 2);

                    CvInvoke.Imshow("4a", imgContours);
                    frm.txtInfo.AppendText("possible plate " + i.ToString() + ", click on any image and press a key to continue . . ." + "\r\n");
                    CvInvoke.Imshow("4b", listOfPossiblePlates[i].imgPlate);
                    CvInvoke.WaitKey(0);
                }
                frm.txtInfo.AppendText("\r\n" + "plate detection complete, click on any image and press a key to begin char recognition . . ." + "\r\n" + "\r\n");
                CvInvoke.WaitKey(0);
            }
            // show steps '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

            return(listOfPossiblePlates);
        }
Exemplo n.º 6
0
        private void RunLive(object sender, EventArgs e)
        {
            Mat imgOriginalScene = new Mat();

            imgOriginalScene = capWebcam.QueryFrame();
            if (imgOriginalScene == null)
            {
                MessageBox.Show("unable to read frame from webcam" + Environment.NewLine + Environment.NewLine +
                                "exiting program");
                Application.Idle -= RunLive;
                //Apli.Exit(0);
                return;
            }

            ibOriginal.Image = imgOriginalScene;
            //show original image on main form

            List <PossiblePlate> listOfPossiblePlates = detectPlates.detectPlatesInScene(imgOriginalScene);

            //detect plates

            listOfPossiblePlates = detectChars.detectCharsInPlates(listOfPossiblePlates);
            //detect chars in plates

            //check if list of plates is null or zero
            if ((listOfPossiblePlates == null))
            {
                //txtInfo.AppendText("\r\n" + "no license plates were detected" + "\r\n");
            }
            else if ((listOfPossiblePlates.Count == 0))
            {
                // txtInfo.AppendText("\r\n" + "no license plates were detected" + "\r\n");
            }
            else
            {
                //if we get in here list of possible plates has at leat one plate

                //sort the list of possible plates in DESCENDING order (most number of chars to least number of chars)
                listOfPossiblePlates.Sort((onePlate, otherPlate) => otherPlate.strChars.Length.CompareTo(onePlate.strChars.Length));

                //suppose the plate with the most recognized chars
                PossiblePlate licPlate = listOfPossiblePlates[0];
                //(the first plate in sorted by string length descending order)
                //is the actual plate

                //CvInvoke.Imshow("final imgPlate", licPlate.imgPlate);
                //show the final color plate image
                //CvInvoke.Imshow("final imgThresh", licPlate.imgThresh);
                //show the final thresh plate image

                //if no chars are present in the lic plate,
                if ((licPlate.strChars.Length == 0))
                {
                    // txtInfo.AppendText("\r\n" + "no characters were detected" + licPlate.strChars + "\r\n");
                    //update info text box
                    return;
                    //and return
                }

                drawRedRectangleAroundPlate(imgOriginalScene, licPlate);
                //draw red rectangle around plate

                txtInfo.AppendText("\r\n" + "license plate read from image = " + licPlate.strChars + "\r\n");
                //write license plate text to text box
                txtInfo.AppendText("\r\n" + "----------------------------------------" + "\r\n");

                writeLicensePlateCharsOnImage(ref imgOriginalScene, licPlate);
                //write license plate text on the image

                ibOriginal.Image = imgOriginalScene;
                //update image on main form
                foreach (var plates in MyPlates)
                {
                    if (licPlate.strChars == plates)
                    {
                        if (PlatesRead.Exists(x => x.PlateNumber == licPlate.strChars && DateTime.Now - x.Time < new TimeSpan(0, 0, 45)))
                        {
                            PlatesRead.Add(new LicensePlates(licPlate.strChars, DateTime.Now));
                        }
                        else if (PlatesRead.Count == 0)
                        {
                            PlatesRead.Add(new LicensePlates(licPlate.strChars, DateTime.Now));
                        }
                        else if (DateTime.Now - PlatesRead.Last().Time > new TimeSpan(0, 1, 0))
                        {
                            PlatesRead.Clear();
                        }
                        //else if

                        if (PlatesRead.Count >= 3)
                        {
                            SendCommandToESP8266(licPlate.strChars + "\n");
                            Application.Idle -= RunLive;
                        }
                    }
                }
            }
        }