OpenCV C ++ / Obj-C:高级方形检测 [英] OpenCV C++/Obj-C: Advanced square detection
问题描述
过去我问了
任何想法?我使用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屋!