/// <summary> /// Detect the square in the image using contours /// </summary> /// <param name="img">Image</param> /// <param name="modifiedImg">Modified image to be return</param> /// <param name="storage">Memory storage</param> /// <returns></returns> public static CvPoint[] DetectSquares(IplImage img) { // Debug //System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); //stopWatch.Start(); using (CvMemStorage storage = new CvMemStorage()) { // create empty sequence that will contain points - // 4 points per square (the square's vertices) CvSeq<CvPoint> squares = new CvSeq<CvPoint>(SeqType.Zero, CvSeq.SizeOf, storage); using (IplImage timg = img.Clone()) using (IplImage gray = new IplImage(timg.Size, BitDepth.U8, 1)) using (IplImage dstCanny = new IplImage(timg.Size, BitDepth.U8, 1)) { // Get gray scale timg.CvtColor(gray, ColorConversion.BgrToGray); // Canny Cv.Canny(gray, dstCanny, 70, 300); // dilate canny output to remove potential // holes between edge segments Cv.Dilate(dstCanny, dstCanny, null, 2); // find contours and store them all as a list CvSeq<CvPoint> contours; dstCanny.FindContours(storage, out contours); // Debug //Cv.ShowImage("Edge", dstCanny); //if (contours != null) Console.WriteLine(contours.Count()); // Test each contour while (contours != null) { // Debug //if (stopWatch.ElapsedMilliseconds > 100) //{ // Console.WriteLine("ROI detection is taking too long and is skipped."); //} // approximate contour with accuracy proportional // to the contour perimeter CvSeq<CvPoint> result = Cv.ApproxPoly(contours, CvContour.SizeOf, storage, ApproxPolyMethod.DP, contours.ContourPerimeter() * 0.02, false); // square contours should have 4 vertices after approximation // relatively large area (to filter out noisy contours) // and be convex. // Note: absolute value of an area is used because // area may be positive or negative - in accordance with the // contour orientation if (result.Total == 4 && Math.Abs(result.ContourArea(CvSlice.WholeSeq)) > 250 && result.CheckContourConvexity()) { double s = 0; for (int i = 0; i < 5; i++) { // find minimum Angle between joint // edges (maximum of cosine) if (i >= 2) { double t = Math.Abs(Angle(result[i].Value, result[i - 2].Value, result[i - 1].Value)); s = s > t ? s : t; } } // if cosines of all angles are small // (all angles are ~90 degree) then write quandrange // vertices to resultant sequence if (s < 0.3) { //Console.WriteLine("ROI found!"); // Debug for (int i = 0; i < 4; i++) { //Console.WriteLine(result[i]); squares.Push(result[i].Value); } } } // Take the next contour contours = contours.HNext; } } //stopWatch.Stop(); //Console.WriteLine("ROI Detection : {0} ms", stopWatch.ElapsedMilliseconds); // Debug return squares.ToArray(); } }