Detect Basic Shape in Image with WPF EmguCV

Second tutorial that I have tried was how to detect circles, rectangles and triangles in an image. Like the previous program, I will use WPF and C# for the following program. When you start new project, do not ever forget to do basic setting for the project.

Basic Setting:

  • Copy paste the library (opencv_ffmpeg310_64.dll, opencv_core220.dll, opencv_imgproc220.dll) into Debug folder inside your project folder.
  • Add existing item into the solution explorer in the Visual Studio. Add 3 libraries mentioned above.
  • Copy paste cvextern.dll also into our project folder.
  • Change the Advanced Properties into “Copy Always”

  • Add new references into References. Add Emgu.CV.UI, Emgu.CV.World and Add Emgu. Util. If needed, I also add System.Drawing into the references.
  • Add existing class provided by EmguCV: BitmapSourceConverter.cs
  • Change the Build Properties into x64 setting. Please refer to previous tutorial.
  • Declare the using statement before begin writing your code.
using Emgu.CV.Structure;
using Emgu.CV;
using Emgu.Util;
using Emgu.CV.CvEnum;
using Microsoft.Win32;
using Emgu.CV.Util;

Start Program:

Now We can start writing the algorithm. First of all, take care of the GUI first. I will put the output image into Image Control in WPF. the XAML code as follow:

<Grid>
  <Grid.ColumnDefinitions>
   <ColumnDefinition />
   <ColumnDefinition />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
   <RowDefinition Height="*"/>
   <RowDefinition Height="*"/>
   <RowDefinition Height="auto"/>
  </Grid.RowDefinitions>
 <Image x:Name="myImage" Margin="5" />
 <Image Grid.Column="1" x:Name="myGreyImage" Margin="5"/>
 <Image Grid.Row="1" x:Name="detectCircle" Margin="5"/>
 <Image Grid.Row="1" Grid.Column="1" x:Name="detectRectangle" Margin="5"/>
 <Button Grid.Column="1" Grid.Row="2" x:Name="testButton" Content="Load Image" Click="testButton_Click" HorizontalAlignment="Right" VerticalAlignment="Bottom" Height="44" Width="92"/>
</Grid>

I create two methods,first for detecting circles and second for detecting rectangles and triangles. Below are the code:

Detect and Draw detected circles:

private static Image<Bgr, byte> detectCircle(Image<Bgr, byte> image)
{
Image<Gray, byte> imageGrey = image.Convert<Gray, byte>();
 
double cannyThreshold = 180.0;
double circleAccumulatorThreshold = 120;
CircleF[] circles = CvInvoke.HoughCircles(imageGrey, HoughType.Gradient,
2.0, 20.0, cannyThreshold,
circleAccumulatorThreshold, 5);
 
//canny and edge detection
double cannyThresholdLinking = 120.0;
UMat cannyEdges = new UMat();
CvInvoke.Canny(imageGrey, cannyEdges, cannyThreshold, cannyThresholdLinking);
 
LineSegment2D[] lines = CvInvoke.HoughLinesP(cannyEdges, 1, Math.PI / 45.0,
20, 30, 10);
Image<Bgr, byte> circleImage = image.CopyBlank();
foreach (CircleF circle in circles)
circleImage.Draw(circle, new Bgr(255, 0, 0), 5);
 
return circleImage;
}

Detect and Draw detected rectangles and triangles:

 

 private static Image<Bgr, byte> detectRectTri(Image<Bgr, byte> image)
 {
 Image<Gray, byte> imageGrey = image.Convert<Gray, byte>();
 
 List<Triangle2DF> triangleList = new List<Triangle2DF>();
 List<RotatedRect> boxList = new List<RotatedRect>();
 
 UMat cannyEdges = new UMat();
 double cannyThreshold = 180.0;
 double cannyThresholdLinking = 120.0;
 CvInvoke.Canny(imageGrey, cannyEdges, cannyThreshold, cannyThresholdLinking);
 
 
 using (VectorOfVectorOfPoint countours = new VectorOfVectorOfPoint())
 {
 
 CvInvoke.FindContours(cannyEdges, countours, null, RetrType.List,
 ChainApproxMethod.ChainApproxSimple);
 int count = countours.Size;
 for (int i = 0; i < count; i++)
 {
 using (VectorOfPoint kontur = countours[i])
 using (VectorOfPoint approxContour = new VectorOfPoint())
 {
 CvInvoke.ApproxPolyDP(kontur, approxContour, CvInvoke.ArcLength(kontur, true) * 0.05, true);
 if (CvInvoke.ContourArea(approxContour, false) > 250) //only consider contours with area greater than 250
 {
 if (approxContour.Size == 3) //the countour has 3 vertices. it is triangle
 {
 System.Drawing.Point[] pts = approxContour.ToArray();
 triangleList.Add(new Triangle2DF(pts[0], pts[1], pts[2]));
 }
 else if (approxContour.Size == 4) //rectangle
 {
 //determine if allthe angles in the contour are within [80,100] degree
 bool isRectangle = true;
 System.Drawing.Point[] pts = approxContour.ToArray();
 LineSegment2D[] edges = Emgu.CV.PointCollection.PolyLine(pts, true);
 
 for (int j = 0; j < edges.Length; j++)
 {
 double angle = Math.Abs(
 edges[(j+i)% edges.Length].GetExteriorAngleDegree(edges[j]));
 if (angle < 80 || angle > 100)
 {
 isRectangle = false;
 break;
 }
 
 }
 if (isRectangle) boxList.Add(CvInvoke.MinAreaRect(approxContour));
 }
 }
 }
 }
 }
 
 Image<Bgr, byte> triRectImage = image.CopyBlank();
 foreach (Triangle2DF triangle in triangleList)
 triRectImage.Draw(triangle, new Bgr(0, 255, 0), 5);
 foreach (RotatedRect box in boxList)
 triRectImage.Draw(box, new Bgr(0, 0, 255), 5);
 
 return triRectImage;
 }

Button Event Handler:

 private void Button_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openPic = new OpenFileDialog();
            if (openPic.ShowDialog() == true)
            {
                Image<Bgr, byte> gambar = new Image<Bgr,byte>(openPic.FileName);
                originalImage.Source = Emgu.CV.WPF.BitmapSourceConvert.ToBitmapSource(gambar);
 
                Image<Bgr,byte> bunder = detectCircle(gambar);
              lingkaranImage.Source = Emgu.CV.WPF.BitmapSourceConvert.ToBitmapSource(bunder);
 
                Image<Bgr, byte> kotak = detectRectTri(gambar);
                kotakSegitigaImage.Source = Emgu.CV.WPF.BitmapSourceConvert.ToBitmapSource(kotak);
            }
 
        }

Then below was the result:

References: 1

One thought on “Detect Basic Shape in Image with WPF EmguCV

  1. FirstAndra

    I have noticed you don’t monetize your website, don’t waste your traffic, you can earn additional bucks every month because you’ve got hi quality content.

    If you want to know how to make extra money, search for: Boorfe’s tips best adsense
    alternative

Leave a Reply

Your email address will not be published. Required fields are marked *