如何使用emgu CV找到与图像中的任意角度的旋转一个黑色的方形 [英] How to find a black square with any angle of rotation in the image using emgu cv

查看:5459
本文介绍了如何使用emgu CV找到与图像中的任意角度的旋转一个黑色的方形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要找到三个黑色方块的坐标在测试形式。我把示例代码从网站emgu.com并略有变化,但他没有找到我需要什么。图像的尺寸为A4,并且测试形式的尺寸A5。我希望对你有所帮助:)
我差点忘了,广场30像素的大小。

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:


  1. 反转的形象,使前景变为白色,并背景黑色。

  2. 找到连接组件

  3. 对于每个轮廓

  1. Invert the image, so that the foreground becomes white, and the background black.
  2. Find contours of connected components
  3. For each contours

一。计算的最小面积的矩形

a. Compute the minimum area rectangle box

乙。计算面积:巴里亚

℃。计算轮廓的区域: CAREA

c. Compute the area of the contour: carea

Ð。涂一些约束,以确保您的轮廓就是你要找的方

d. Apply some constraint to be sure your contour is the square you're looking for

步骤3d的约束条件是:

The constraints of step 3d are:


  1. 巴里亚/ CAREA 应该是很高的(假设较高那么0.9),这意味着轮廓属于一个的几乎的矩形一滴。

  1. The ratio barea / carea should be high (let's say higher then 0.9), meaning that the contour belongs to an almost rectangular blob.

的宽高比箱应的几乎的1,这意味着基本上是一个方形

The aspect ratio of box should be almost 1, meaning that the box is basically a square

广场的大小应该是几乎 30 ,拒绝图像中的其它更小或更大的正方形。

The 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:

下面是代码。对不起,这是C ++,但因为它是所有OpenCV的函数调用,你应该能够将它移植容易C#。至少,你可以用它作为参考:

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:

#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;
}

这篇关于如何使用emgu CV找到与图像中的任意角度的旋转一个黑色的方形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆