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

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

问题描述

过去我问了



任何想法?我使用karlphillips代码:

  void find_squares(Mat& image,vector< vector< Point>& )
{
// blur会增强边缘检测
Mat blur(image);
medianBlur(image,blurred,9);

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

//在图像的每个颜色平面中找到正方形
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< threshold_level; l ++)
{
//使用Canny而不是零阈值!
// Canny有助于捕获带渐变阴影的正方形
if(l == 0)
{
Canny(gray0,gray,10,20,3) //

// Dilate有助于消除边缘段之间的潜在空洞
dilate(gray,gray,Mat(),Point(-1,-1));
}
else
{
gray = gray0> =(1 + 1)* 255 / threshold_level;
}

//查找轮廓并将它们存储在列表中
findContours(gray,contour,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);

//测试轮廓
矢量< Point>约;
for(size_t i = 0; i {
//精确比例的近似轮廓
//轮廓周长
approxPolyDP(Mat(contoururs [i]),approx,arcLength(Mat(contoururs [i]),true)* 0.02,true);

//注意:使用区域的绝对值,因为
//区域可以是正或负 - 根据
//轮廓方向
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(approximately [j%4],approximately [j-2 ],约[j-1]));
maxCosine = MAX(maxCosine,cosine);
}

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


解决方案

您可以尝试使用 HoughLines 检测广场。接下来,找到四个生成的线交叉点以检测拐角。 霍夫变换对噪声和遮挡非常强大,因此在此处可能很有用。此外,这里是一个交互式演示,演示了Hough转换的工作原理(我认为这是很酷的最少:)。 这里是我之前的一个



您可能会在每一边都有多条线,但定位交叉点应该有助于确定内点与离群值。找到候选角点后,您还可以按照区域或多边形的方形过滤这些候选。



编辑:所有这些答案与代码和图像使我认为我的答案有点缺乏:)所以,这里是一个如何做到这一点的实现:

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

边缘;
Canny(thresh,edges,66.0,133.0,3);

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

cout<< Detected<< lines.size()<< 线。 << endl;

//从检测到的行计算交集...
vector< Point2f>交叉点;
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< 交叉是< 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 {
theta1 + = CV_PI; //处理0和180个模糊度...
}

if(theta2 {
theta2 + = CV_PI; //处理0和180个模糊度...
}

return abs(theta1-theta2)> minTheta;
}

//长期讨厌的维基百科线路交叉方程... ... bb $ b 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 [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)* / p1 [1] .x)*(p2 [0] .y-p1 [0] p2 [1] .y) -
(p1 [0] .y - p1 [1] .y)*(p2 [0] .x * p2 [1] .y- p2 [1] .x))/ denom)

return intersect;
}

vector< Point2f> lineToPointPair(Vec2f line)
{
vector< Point2f>点数;

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

返回点;
}

注意:调整图片大小的主要原因



Canny



这使用了Canny边缘检测,以帮助大大减少阈值处理后检测到的行数。





Hough变换



然后使用Hough变换检测侧面的广场。



交叉



最后,我们计算所有线对的交集。



Hope这有助于!


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天全站免登陆