I need to find the coordinates of three black squares in the test form. I took the example code from the site emgu.com and slightly changed it, but he does not find what I need. The size of image is A4, and the size of the test form is A5. I am hope for your help :) I nearly forgot, the size of squares 30 pixels.
private void DetectRectangles(Image<Gray, byte> img)
{
var size = new Size(3, 3);
CvInvoke.GaussianBlur(img, img, size, 0);
CvInvoke.AdaptiveThreshold(img, img, 255, AdaptiveThresholdType.MeanC, ThresholdType.Binary, 75, 100);
UMat cannyEdges = new UMat();
CvInvoke.Canny(img, cannyEdges, 180, 120);
var boxList = new List<RotatedRect>();
using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
{
CvInvoke.FindContours(cannyEdges, contours, null, RetrType.Tree, ChainApproxMethod.ChainApproxSimple);
int count = contours.Size;
for (int i = 0; i < count; i++)
{
using (VectorOfPoint contour = contours[i])
using (VectorOfPoint approxContour = new VectorOfPoint())
{
CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true);
var area = CvInvoke.ContourArea(approxContour);
if (area > 800 && area < 1000)
{
if (approxContour.Size == 4)
{
bool isRectangle = true;
Point[] pts = approxContour.ToArray();
LineSegment2D[] edges = PointCollection.PolyLine(pts, true);
for (int j = 0; j < edges.Length; j++)
{
double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j]));
if (angle < 75 || angle > 94)
{
isRectangle = false;
break;
}
}
if (isRectangle)
boxList.Add(CvInvoke.MinAreaRect(approxContour));
}
}
}
}
}
var resultimg = new Image<Bgr,byte>(img.Width, img.Height);
CvInvoke.CvtColor(img, resultimg, ColorConversion.Gray2Bgr);
foreach (RotatedRect box in boxList)
{
CvInvoke.Polylines(resultimg, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.Red).MCvScalar, 2);
}
imageBox1.Image = resultimg;
resultimg.Save("result_img.jpg"); }
Input image:
Since you are looking for a very specific object, you can use the following algorithm:
For each contours
a. Compute the minimum area rectangle
box
b. Compute the area of
box
:barea
c. Compute the area of the contour:
carea
d. Apply some constraint to be sure your contour is the square you're looking for
The constraints of step 3d are:
The ratio
barea / carea
should be high (let's say higher then 0.9), meaning that the contour belongs to an almost rectangular blob.The aspect ratio of
box
should be almost 1, meaning that thebox
is basically a squareThe size of the square should be almost
30
, to reject other smaller or bigger squares in the image.The result I get running this is:
Here is the code. Sorry, it's C++, but since it's all OpenCV function calls you should be able to port it easily to C#. At least, you can use it as a reference: