using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using System.Diagnostics;
namespace ShapeDetection
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
fileNameTextBox.Text = "pic3.png";
}
public void PerformShapeDetection()
{
if (fileNameTextBox.Text != String.Empty)
{
StringBuilder msgBuilder = new StringBuilder("Performance: ");
//Load the image from file and resize it for display
Image<bgr,> img =
new Image<bgr,>(fileNameTextBox.Text)
.Resize(400, 400, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR, true);
//Convert the image to grayscale and filter out the noise
Image<gray,> gray = img.Convert<gray,>().PyrDown().PyrUp();
#region circle detection
Stopwatch watch = Stopwatch.StartNew();
Gray cannyThreshold = new Gray(180);
Gray circleAccumulatorThreshold = new Gray(120);
CircleF[] circles = gray.HoughCircles(
cannyThreshold,
circleAccumulatorThreshold,
2.0, //Resolution of the accumulator used to detect centers of the circles
20.0, //min distance
5, //min radius
0 //max radius
)[0]; //Get the circles from the first channel
watch.Stop();
msgBuilder.Append(String.Format("Hough circles - {0} ms; ", watch.ElapsedMilliseconds));
#endregion
#region Canny and edge detection
watch.Reset(); watch.Start();
Gray cannyThresholdLinking = new Gray(120);
Image<gray,> 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
watch.Stop();
msgBuilder.Append(String.Format("Canny & Hough lines - {0} ms; ", watch.ElapsedMilliseconds));
#endregion
#region Find triangles and rectangles
watch.Reset(); watch.Start();
List<triangle2df> triangleList = new List<triangle2df>();
List<mcvbox2d> boxList = new List<mcvbox2d>(); //a box is a rotated rectangle
using (MemStorage storage = new MemStorage()) //allocate storage for contour approximation
for (
Contour<point> contours = cannyEdges.FindContours(
Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST,
storage);
contours != null;
contours = contours.HNext)
{
Contour<point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.05, storage);
if (currentContour.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 [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());
}
}
}
watch.Stop();
msgBuilder.Append(String.Format("Triangles & Rectangles - {0} ms; ", watch.ElapsedMilliseconds));
#endregion
originalImageBox.Image = img;
this.Text = msgBuilder.ToString();
#region draw triangles and rectangles
Image<bgr,> 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,> 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,> lineImage = img.CopyBlank();
foreach (LineSegment2D line in lines)
lineImage.Draw(line, new Bgr(Color.Green), 2);
lineImageBox.Image = lineImage;
#endregion
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
PerformShapeDetection();
}
private void loadImageButton_Click(object sender, EventArgs e)
{
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK || result == DialogResult.Yes)
{
fileNameTextBox.Text = openFileDialog1.FileName;
}
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
}
}
}