【问题标题】:How to find a black square with any angle of rotation in the image using emgu cv如何使用 emgu cv 在图像中找到具有任意旋转角度的黑色正方形
【发布时间】:2016-05-17 00:21:17
【问题描述】:

我需要在测试表格中找到三个黑色方块的坐标。我从站点 emgu.com 获取示例代码并稍作更改,但他没有找到我需要的内容。图片尺寸为A4,试卷尺寸为A5。我希望你的帮助:) 我差点忘了,正方形的大小是 30 像素。

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");       }

输入图片:

【问题讨论】:

    标签: c# .net opencv emgucv


    【解决方案1】:

    由于您正在寻找一个非常具体的对象,您可以使用以下算法:

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

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

      b.计算box的面积:barea

      c。计算轮廓的面积:carea

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

    步骤 3d 的约束是:

    1. barea / carea 的比率应该很高(假设高于 0.9),这意味着轮廓属于一个几乎矩形斑点。

    2. box的纵横比应该几乎为1,也就是说box基本上是一个正方形

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

    我运行的结果是:

    这里是代码。抱歉,它是 C++,但由于它都是 OpenCV 函数调用,您应该能够轻松地将其移植到 C#。至少,您可以将其用作参考:

    #include <opencv2/opencv.hpp>
    #include <iostream>
    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<vector<Point>> contours;
        findContours(img.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    
        vector<RotatedRect> 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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-18
      • 2017-08-31
      • 2012-11-03
      • 2011-08-07
      • 2021-04-22
      • 2020-03-20
      • 2015-09-05
      • 1970-01-01
      相关资源
      最近更新 更多