如何使用emgu cv在图像中找到任何旋转角度的黑色方块

我需要在测试表中找到三个黑色方块的坐标。 我从网站emgu.com上获取了示例代码并略微改变了它,但他找不到我需要的东西。 图像的大小为A4,测试forms的大小为A5。 我希望对你有所帮助:)我差点忘了,正方形的大小为30像素。

private void DetectRectangles(Image 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(); using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(cannyEdges, contours, null, RetrType.Tree, ChainApproxMethod.ChainApproxSimple); int count = contours.Size; for (int i = 0; i  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  94) { isRectangle = false; break; } } if (isRectangle) boxList.Add(CvInvoke.MinAreaRect(approxContour)); } } } } } var resultimg = new Image(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"); } 

输入图片:

由于您要查找非常特定的对象,因此可以使用以下算法:

  1. 反转图像,使前景变为白色,背景变为黑色。
  2. 查找连接组件的轮廓
  3. 对于每个轮廓

    一个。 计算最小面积矩形box

    湾 计算box的面积: barea

    C。 计算轮廓的面积: carea

    d。 应用一些约束以确保轮廓是您正在寻找的方形

步骤3d的约束是:

  1. barea / carea的比例应该很高(比如说高于0.9),这意味着轮廓属于几乎矩形的斑点。

  2. box的纵横比应该接近 1,这意味着box基本上是正方形

  3. 方形的大小应该接近30 ,以拒绝图像中的其他更小或更大的方块。

我运行的结果是:

在此处输入图像描述

这是代码。 对不起,它是C ++,但由于它是所有OpenCV函数调用,你应该能够轻松地将它移植到C#。 至少,您可以将其用作参考:

 #include  #include  using namespace cv; using namespace std; int main() { // Load image Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE); // Create the output image Mat3b out; cvtColor(img, out, COLOR_GRAY2BGR); // Create debug image Mat3b dbg = out.clone(); // Binarize (to remove jpeg arifacts) img = img > 200; // Invert image img = ~img; // Find connected components vector> contours; findContours(img.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); vector squares; // For each contour for (int i = 0; i < contours.size(); ++i) { // Find rotated bounding box RotatedRect box = minAreaRect(contours[i]); // Compute the area of the contour double carea = contourArea(contours[i]); // Compute the area of the box double barea = box.size.area(); // Constraint #1 if ((carea / barea) > 0.9) { drawContours(dbg, contours, i, Scalar(0, 0, 255), 7); // Constraint #2 if (min(box.size.height, box.size.width) / max(box.size.height, box.size.width) > 0.95) { drawContours(dbg, contours, i, Scalar(255, 0, 0), 5); // Constraint #3 if (box.size.width > 25 && box.size.width < 35) { drawContours(dbg, contours, i, Scalar(0, 255, 0), 3); // Found the square! squares.push_back(box); } } } // Draw output for (int i = 0; i < squares.size(); ++i) { Point2f pts[4]; squares[i].points(pts); for (int j = 0; j < 4; ++j) { line(out, pts[j], pts[(j + 1) % 4], Scalar(0,255,0), 5); } } } // Resize for better visualization resize(out, out, Size(), 0.25, 0.25); resize(dbg, dbg, Size(), 0.25, 0.25); // Show images imshow("Steps", dbg); imshow("Result", out); waitKey(); return 0; }