OpenCV C++/Obj-C:高级方块检测 [英] OpenCV C++/Obj-C: Advanced square detection

查看:28
本文介绍了OpenCV C++/Obj-C:高级方块检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

不久前我问了

有什么想法吗?我正在使用 karlphillips 代码:

void find_squares(Mat& image, vector >& squares){//模糊将增强边缘检测垫子模糊(图像);中值模糊(图像,模糊,9);Mat gray0(blurred.size(), CV_8U),灰色;矢量<矢量<点>>轮廓;//在图像的每个颜色平面中找到正方形for (int c = 0; c <3; c++){int ch[] = {c, 0};mixChannels(&blurred, 1, &gray0, 1, ch, 1);//尝试几个阈值级别const int threshold_level = 2;for (int l = 0; l = (l+1) * 255/threshold_level;}//查找轮廓并将它们存储在列表中findContours(灰色,轮廓,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);//测试轮廓矢量<点>约;for (size_t i = 0; i 1000 & &isContourConvex(Mat(approx))){双最大余弦 = 0;for (int j = 2; j <5; j++){双余弦 = fabs(angle(approx[j%4],approx[j-2],approx[j-1]));maxCosine = MAX(maxCosine, cosine);}如果 (maxCosine <0.3)squares.push_back(大约);}}}}}

解决方案

您可以尝试使用 HoughLines 检测正方形的四个边.接下来,定位四个生成的线交叉点以检测角点.霍夫变换对噪声和遮挡相当稳健,因此它在这里很有用.另外,这里是一个交互式演示,展示了霍夫变换的工作原理(我认为它至少很酷:).这里是我之前的一个检测激光交叉中心的答案显示大部分相同的数学(除了它只找到一个角).

每边可能有多条线,但定位交叉点应该有助于确定内部点与异常点.找到候选角后,您还可以按面积或多边形的方形"程度来过滤这些候选角.

所有这些带有代码和图像的答案让我觉得我的答案有点缺乏:)所以,这是一个如何做到这一点的实现:

#include #include #include #include #include <向量>使用命名空间 cv;使用命名空间标准;Point2f computeIntersect(Vec2f line1, Vec2f line2);矢量<Point2f>lineToPointPair(Vec2f 线);bool acceptLinePair(Vec2f line1, Vec2f line2, float minTheta);int main(int argc, char* argv[]){Mat occludedSquare = imread("Square.jpg");调整大小(occludedSquare, occludedSquare, Size(0, 0), 0.25, 0.25);Mat occludedSquare8u;cvtColor(occludedSquare, occludedSquare8u, CV_BGR2GRAY);垫脱粒;阈值(occludedSquare8u, thresh, 200.0, 255.0, THRESH_BINARY);GaussianBlur(thresh, thresh, Size(7, 7), 2.0, 2.0);垫子边缘;Canny(thresh, edge, 66.0, 133.0, 3);向量<Vec2f>线条;HoughLines(edges, lines, 1, CV_PI/180, 50, 0, 0);cout<<检测到"<<线条大小()<<线条."<<结束;//计算检测到的线的交点...矢量<Point2f>交叉路口;for( size_t i = 0; i  0){矢量<Point2f>::迭代器i;for(i =intersections.begin(); i !=intersections.end();++i){cout<<交点是"<<i->x<<", " <<i->y<<结束;圆(遮挡方,*i,1,标量(0、255、0)、3);}}imshow("相交", occludedSquare);等待键();返回0;}bool acceptLinePair(Vec2f line1, Vec2f line2, float minTheta){浮动 theta1 = line1[1], theta2 = line2[1];if(theta1 minTheta;}//冗长的维基百科线交方程...bleh...Point2f computeIntersect(Vec2f line1, Vec2f line2){矢量<Point2f>p1 = lineToPointPair(line1);矢量<Point2f>p2 = lineToPointPair(line2);浮点数 = (p1[0].x - p1[1].x)*(p2[0].y - p2[1].y) - (p1[0].y - p1[1].y)*(p2[0].x - p2[1].x);Point2f 相交(((p1[0].x*p1[1].y - p1[0].y*p1[1].x)*(p2[0].x - p2[1].x) -(p1[0].x - p1[1].x)*(p2[0].x*p2[1].y - p2[0].y*p2[1].x))/denom,((p1[0].x*p1[1].y - p1[0].y*p1[1].x)*(p2[0].y - p2[1].y) -(p1[0].y - p1[1].y)*(p2[0].x*p2[1].y - p2[0].y*p2[1].x))/denom);返回相交;}矢量<Point2f>lineToPointPair(Vec2f 线){矢量<Point2f>积分;浮动 r = 行 [0],t = 行 [1];双 cos_t = cos(t), sin_t = sin(t);双 x0 = r*cos_t, y0 = r*sin_t;双阿尔法 = 1000;points.push_back(Point2f(x0 + alpha*(-sin_t), y0 + alpha*cos_t));points.push_back(Point2f(x0 - alpha*(-sin_t), y0 - alpha*cos_t));返回点;}

注意:我调整图像大小的主要原因是我可以在屏幕上看到它,并加快处理速度.

精明

这使用 Canny 边缘检测来帮助大大减少阈值后检测到的行数.

霍夫变换

然后使用霍夫变换来检测正方形的边.

交叉路口

最后,我们计算所有线对的交点.

希望有帮助!

A while ago I asked a question about square detection and karlphillip came up with a decent result.

Now I want to take this a step further and find squares which edge aren't fully visible. Take a look at this example:

Any ideas? I'm working with karlphillips code:

void find_squares(Mat& image, vector<vector<Point> >& squares)
{
    // blur will enhance edge detection
    Mat blurred(image);
    medianBlur(image, blurred, 9);

    Mat gray0(blurred.size(), CV_8U), gray;
    vector<vector<Point> > contours;

    // find squares in every color plane of the image
    for (int c = 0; c < 3; c++)
    {
        int ch[] = {c, 0};
        mixChannels(&blurred, 1, &gray0, 1, ch, 1);

        // try several threshold levels
        const int threshold_level = 2;
        for (int l = 0; l < threshold_level; l++)
        {
            // Use Canny instead of zero threshold level!
            // Canny helps to catch squares with gradient shading
            if (l == 0)
            {
                Canny(gray0, gray, 10, 20, 3); // 

                // Dilate helps to remove potential holes between edge segments
                dilate(gray, gray, Mat(), Point(-1,-1));
            }
            else
            {
                    gray = gray0 >= (l+1) * 255 / threshold_level;
            }

            // Find contours and store them in a list
            findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

            // Test contours
            vector<Point> approx;
            for (size_t i = 0; i < contours.size(); i++)
            {
                    // approximate contour with accuracy proportional
                    // to the contour perimeter
                    approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

                    // Note: absolute value of an area is used because
                    // area may be positive or negative - in accordance with the
                    // contour orientation
                    if (approx.size() == 4 &&
                            fabs(contourArea(Mat(approx))) > 1000 &&
                            isContourConvex(Mat(approx)))
                    {
                            double maxCosine = 0;

                            for (int j = 2; j < 5; j++)
                            {
                                    double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                                    maxCosine = MAX(maxCosine, cosine);
                            }

                            if (maxCosine < 0.3)
                                    squares.push_back(approx);
                    }
            }
        }
    }
}

解决方案

You might try using HoughLines to detect the four sides of the square. Next, locate the four resulting line intersections to detect the corners. The Hough transform is fairly robust to noise and occlusions, so it could be useful here. Also, here is an interactive demo showing how the Hough transform works (I thought it was cool at least :). Here is one of my previous answers that detects a laser cross center showing most of the same math (except it just finds a single corner).

You will probably have multiple lines on each side, but locating the intersections should help to determine the inliers vs. outliers. Once you've located candidate corners, you can also filter these candidates by area or how "square-like" the polygon is.

EDIT : All these answers with code and images were making me think my answer was a bit lacking :) So, here is an implementation of how you could do this:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

Point2f computeIntersect(Vec2f line1, Vec2f line2);
vector<Point2f> lineToPointPair(Vec2f line);
bool acceptLinePair(Vec2f line1, Vec2f line2, float minTheta);

int main(int argc, char* argv[])
{
    Mat occludedSquare = imread("Square.jpg");

    resize(occludedSquare, occludedSquare, Size(0, 0), 0.25, 0.25);

    Mat occludedSquare8u;
    cvtColor(occludedSquare, occludedSquare8u, CV_BGR2GRAY);

    Mat thresh;
    threshold(occludedSquare8u, thresh, 200.0, 255.0, THRESH_BINARY);

    GaussianBlur(thresh, thresh, Size(7, 7), 2.0, 2.0);

    Mat edges;
    Canny(thresh, edges, 66.0, 133.0, 3);

    vector<Vec2f> lines;
    HoughLines( edges, lines, 1, CV_PI/180, 50, 0, 0 );

    cout << "Detected " << lines.size() << " lines." << endl;

    // compute the intersection from the lines detected...
    vector<Point2f> intersections;
    for( size_t i = 0; i < lines.size(); i++ )
    {
        for(size_t j = 0; j < lines.size(); j++)
        {
            Vec2f line1 = lines[i];
            Vec2f line2 = lines[j];
            if(acceptLinePair(line1, line2, CV_PI / 32))
            {
                Point2f intersection = computeIntersect(line1, line2);
                intersections.push_back(intersection);
            }
        }

    }

    if(intersections.size() > 0)
    {
        vector<Point2f>::iterator i;
        for(i = intersections.begin(); i != intersections.end(); ++i)
        {
            cout << "Intersection is " << i->x << ", " << i->y << endl;
            circle(occludedSquare, *i, 1, Scalar(0, 255, 0), 3);
        }
    }

    imshow("intersect", occludedSquare);
    waitKey();

    return 0;
}

bool acceptLinePair(Vec2f line1, Vec2f line2, float minTheta)
{
    float theta1 = line1[1], theta2 = line2[1];

    if(theta1 < minTheta)
    {
        theta1 += CV_PI; // dealing with 0 and 180 ambiguities...
    }

    if(theta2 < minTheta)
    {
        theta2 += CV_PI; // dealing with 0 and 180 ambiguities...
    }

    return abs(theta1 - theta2) > minTheta;
}

// the long nasty wikipedia line-intersection equation...bleh...
Point2f computeIntersect(Vec2f line1, Vec2f line2)
{
    vector<Point2f> p1 = lineToPointPair(line1);
    vector<Point2f> p2 = lineToPointPair(line2);

    float denom = (p1[0].x - p1[1].x)*(p2[0].y - p2[1].y) - (p1[0].y - p1[1].y)*(p2[0].x - p2[1].x);
    Point2f intersect(((p1[0].x*p1[1].y - p1[0].y*p1[1].x)*(p2[0].x - p2[1].x) -
                       (p1[0].x - p1[1].x)*(p2[0].x*p2[1].y - p2[0].y*p2[1].x)) / denom,
                      ((p1[0].x*p1[1].y - p1[0].y*p1[1].x)*(p2[0].y - p2[1].y) -
                       (p1[0].y - p1[1].y)*(p2[0].x*p2[1].y - p2[0].y*p2[1].x)) / denom);

    return intersect;
}

vector<Point2f> lineToPointPair(Vec2f line)
{
    vector<Point2f> points;

    float r = line[0], t = line[1];
    double cos_t = cos(t), sin_t = sin(t);
    double x0 = r*cos_t, y0 = r*sin_t;
    double alpha = 1000;

    points.push_back(Point2f(x0 + alpha*(-sin_t), y0 + alpha*cos_t));
    points.push_back(Point2f(x0 - alpha*(-sin_t), y0 - alpha*cos_t));

    return points;
}

NOTE : The main reason I resized the image was so I could see it on my screen, and speed-up processing.

Canny

This uses Canny edge detection to help greatly reduce the number of lines detected after thresholding.

Hough transform

Then the Hough transform is used to detect the sides of the square.

Intersections

Finally, we compute the intersections of all the line pairs.

Hope that helps!

这篇关于OpenCV C++/Obj-C:高级方块检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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