Shape (Triangle, Rectangle, Circle, Line) Detection in CSharp

From Emgu CV: OpenCV in .NET (C#, VB, C++ and more)
Jump to: navigation, search

This project is part of the Emgu.CV.Example solution

System Requirement

Component Requirement Detail
Emgu CV Version 1.5
Operation System Cross Platform

Shape Detection

In this tutorial, we demonstrate how to perform Hough Line and Circle detection using Emgu CV, as well as using the Contour class to detect Triangles and Rectangles in the image. The "pic3.png" file from the OpenCV sample folder is used here.
pic3.png from opencv

Source Code

//Load the image from file
Image<Bgr, Byte> img = new Image<Bgr, byte>(fileNameTextBox.Text).Resize(400, 400, true);
 
//Convert the image to grayscale and filter out the noise
Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp();
 
Gray cannyThreshold = new Gray(180);
Gray cannyThresholdLinking = new Gray(120);
Gray circleAccumulatorThreshold = new Gray(120);
 
CircleF[] circles = gray.HoughCircles(
    cannyThreshold,
    circleAccumulatorThreshold,
    5.0, //Resolution of the accumulator used to detect centers of the circles
    10.0, //min distance 
    5, //min radius
    0 //max radius
    )[0]; //Get the circles from the first channel
 
Image<Gray, Byte> cannyEdges = gray.Canny(cannyThreshold, cannyThresholdLinking);
LineSegment2D[] lines = cannyEdges.HoughLinesBinary(
    1, //Distance resolution in pixel-related units
    Math.PI / 45.0, //Angle resolution measured in radians.
    20, //threshold
    30, //min Line width
    10 //gap between lines
    )[0]; //Get the lines from the first channel
 
#region Find triangles and rectangles
List<Triangle2DF> triangleList = new List<Triangle2DF>();
List<MCvBox2D> boxList = new List<MCvBox2D>();
 
using (MemStorage storage = new MemStorage()) //allocate storage for contour approximation
   for (Contour<Point> contours = cannyEdges.FindContours(); contours != null; contours = contours.HNext)
   {
      Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.05, storage);
 
      if (contours.Area > 250) //only consider contours with area greater than 250
      {
         if (currentContour.Total == 3) //The contour has 3 vertices, it is a triangle
         {
            Point[] pts = currentContour.ToArray();
            triangleList.Add(new Triangle2DF(
               pts[0],
               pts[1],
               pts[2]
               ));
         }
         else if (currentContour.Total == 4) //The contour has 4 vertices.
         {
            #region determine if all the angles in the contour are within the range of [80, 100] degree
            bool isRectangle = true;
            Point[] pts = currentContour.ToArray();
            LineSegment2D[] edges = PointCollection.PolyLine(pts, true);
 
            for (int i = 0; i < edges.Length; i++)
            {
               double angle = Math.Abs(
                  edges[(i + 1) % edges.Length].GetExteriorAngleDegree(edges[i]));
               if (angle < 80 || angle > 100)
               {
                  isRectangle = false;
                  break;
               }
            }
            #endregion
 
            if (isRectangle) boxList.Add(currentContour.GetMinAreaRect());
         }
      }
   }
#endregion
 
originalImageBox.Image = img;
 
#region draw triangles and rectangles
Image<Bgr, Byte> triangleRectangleImage = img.CopyBlank();
foreach (Triangle2DF triangle in triangleList)
   triangleRectangleImage.Draw(triangle, new Bgr(Color.DarkBlue), 2);
foreach (MCvBox2D box in boxList)
   triangleRectangleImage.Draw(box, new Bgr(Color.DarkOrange), 2);
triangleRectangleImageBox.Image = triangleRectangleImage;
#endregion
 
#region draw circles
Image<Bgr, Byte> circleImage = img.CopyBlank();
foreach (CircleF circle in circles)
   circleImage.Draw(circle, new Bgr(Color.Brown), 2);
circleImageBox.Image = circleImage;
#endregion
 
#region draw lines
Image<Bgr, Byte> lineImage = img.CopyBlank();
foreach (LineSegment2D line in lines)
   lineImage.Draw(line, new Bgr(Color.Green), 2);
lineImageBox.Image = lineImage;
#endregion

Result

Result of shape detection