C++ 自动透视校正 OpenCV
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22519545/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Automatic perspective correction OpenCV
提问by Clip
I am trying to implement Automatic perspective correction in my iOS program and when I use the test image I found on the tutorial everything works as expected. But when I take a picture I get back a weird result.
我正在尝试在我的 iOS 程序中实现自动透视校正,当我使用在教程中找到的测试图像时,一切都按预期工作。但是当我拍照时,我得到了一个奇怪的结果。
I am using code found in this tutorial
我正在使用本教程中的代码
When I give it an image that looks like this:
当我给它一个看起来像这样的图像时:
I get this as the result:
我得到这个结果:
Here is what dst
gives me that might help.
这是dst
给我的可能有帮助的东西。
I am using this to call the method which contains the code.
我正在使用它来调用包含代码的方法。
quadSegmentation(Img, bw, dst, quad);
quadSegmentation(Img, bw, dst, quad);
Can anyone tell me when I am getting so many green lines compared to the tutorial? And how I might be able to fix this and properly crop the image to only contain the card?
谁能告诉我,与教程相比,我什么时候得到这么多绿线?我如何才能解决这个问题并正确裁剪图像以仅包含卡片?
回答by Haris
For perspective transform you need,
对于您需要的透视变换,
source points->Coordinates of quadrangle vertices in the source image.
源点->源图像中四边形顶点的坐标。
destination points-> Coordinates of the corresponding quadrangle vertices in the destination image.
目标点->目标图像中相应四边形顶点的坐标。
Here we will calculate these point by contour process.
在这里,我们将通过轮廓过程计算这些点。
Calculate Coordinates of quadrangle vertices in the source image
计算源图像中四边形顶点的坐标
- You will get the your card as contour by just by blurring, thresholding, then find contour, find largest contour etc..
- After finding largest contour just calculate approximates a polygonal curve, here you should get 4 Point which represent corners of your card. You can adjust the parameter
epsilon
to make 4 co-ordinates.
- 您只需通过模糊,阈值处理,然后找到轮廓,找到最大轮廓等,即可将您的卡片作为轮廓。
- 找到最大轮廓后,只需计算近似多边形曲线,在这里您应该得到 4 个代表卡角的点。您可以调整参数
epsilon
以制作 4 个坐标。
Calculate Coordinates of the corresponding quadrangle vertices in the destination image
计算目标图像中对应四边形顶点的坐标
- This can be easily find out by calculating bounding rectangle for largest contour.
- 这可以通过计算最大轮廓的边界矩形轻松找到。
In below image the red rectangle represent source points and green for destination points.
在下图中,红色矩形代表源点,绿色代表目标点。
Adjust the co-ordinates order and Apply Perspective transform
调整坐标顺序并应用透视变换
- Here I manually adjust the co-ordinates order and you can use some sorting algorithm.
- Then calculate transformation matrixand apply wrapPrespective
- 这里我手动调整坐标顺序,你可以使用一些排序算法。
- 然后计算变换矩阵并应用wrapPreferive
See the final result
查看最终结果
Code
代码
Mat src=imread("card.jpg");
Mat thr;
cvtColor(src,thr,CV_BGR2GRAY);
threshold( thr, thr, 70, 255,CV_THRESH_BINARY );
vector< vector <Point> > contours; // Vector for storing contour
vector< Vec4i > hierarchy;
int largest_contour_index=0;
int largest_area=0;
Mat dst(src.rows,src.cols,CV_8UC1,Scalar::all(0)); //create destination image
findContours( thr.clone(), contours, hierarchy,CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image
for( int i = 0; i< contours.size(); i++ ){
double a=contourArea( contours[i],false); // Find the area of contour
if(a>largest_area){
largest_area=a;
largest_contour_index=i; //Store the index of largest contour
}
}
drawContours( dst,contours, largest_contour_index, Scalar(255,255,255),CV_FILLED, 8, hierarchy );
vector<vector<Point> > contours_poly(1);
approxPolyDP( Mat(contours[largest_contour_index]), contours_poly[0],5, true );
Rect boundRect=boundingRect(contours[largest_contour_index]);
if(contours_poly[0].size()==4){
std::vector<Point2f> quad_pts;
std::vector<Point2f> squre_pts;
quad_pts.push_back(Point2f(contours_poly[0][0].x,contours_poly[0][0].y));
quad_pts.push_back(Point2f(contours_poly[0][1].x,contours_poly[0][1].y));
quad_pts.push_back(Point2f(contours_poly[0][3].x,contours_poly[0][3].y));
quad_pts.push_back(Point2f(contours_poly[0][2].x,contours_poly[0][2].y));
squre_pts.push_back(Point2f(boundRect.x,boundRect.y));
squre_pts.push_back(Point2f(boundRect.x,boundRect.y+boundRect.height));
squre_pts.push_back(Point2f(boundRect.x+boundRect.width,boundRect.y));
squre_pts.push_back(Point2f(boundRect.x+boundRect.width,boundRect.y+boundRect.height));
Mat transmtx = getPerspectiveTransform(quad_pts,squre_pts);
Mat transformed = Mat::zeros(src.rows, src.cols, CV_8UC3);
warpPerspective(src, transformed, transmtx, src.size());
Point P1=contours_poly[0][0];
Point P2=contours_poly[0][1];
Point P3=contours_poly[0][2];
Point P4=contours_poly[0][3];
line(src,P1,P2, Scalar(0,0,255),1,CV_AA,0);
line(src,P2,P3, Scalar(0,0,255),1,CV_AA,0);
line(src,P3,P4, Scalar(0,0,255),1,CV_AA,0);
line(src,P4,P1, Scalar(0,0,255),1,CV_AA,0);
rectangle(src,boundRect,Scalar(0,255,0),1,8,0);
rectangle(transformed,boundRect,Scalar(0,255,0),1,8,0);
imshow("quadrilateral", transformed);
imshow("thr",thr);
imshow("dst",dst);
imshow("src",src);
imwrite("result1.jpg",dst);
imwrite("result2.jpg",src);
imwrite("result3.jpg",transformed);
waitKey();
}
else
cout<<"Make sure that your are getting 4 corner using approxPolyDP..."<<endl;
回答by Vlad
teethe This typically happens when you rely on somebody else code to solve your particular problem instead of adopting the code. Look at the processing stages and also the difference between their and your image (it is a good idea by the way to start with their image and make sure the code works):
当您依靠其他人的代码而不是采用代码来解决您的特定问题时,通常会发生这种情况。查看处理阶段以及它们与您的图像之间的区别(顺便说一下,从它们的图像开始并确保代码有效,这是一个好主意):
- Get the edge map. - will probably work since your edges are fine
- Detect lines with Hough transform. - fail since you have lines not only on the contour but also inside of your card. So expect a lot of false alarm lines
- Get the corners by finding intersections between lines. - fail for the above mentioned reason
- Check if the approximate polygonal curve has 4 vertices. - fail
- Determine top-left, bottom-left, top-right, and bottom-right corner. - fail
- Apply the perspective transformation. - fail completely
- 获取边缘图。- 可能会起作用,因为你的边缘很好
- 使用霍夫变换检测线。-失败,因为您不仅在轮廓上而且在卡片内部都有线条。所以预计会有很多误报
- 通过查找线之间的交点来获得角点。-由于上述原因失败
- 检查近似多边形曲线是否有 4 个顶点。-失败
- 确定左上角、左下角、右上角和右下角。-失败
- 应用透视变换。-完全失败
To fix your problem you have to ensure that only lines on the periphery are extracted. If you always have a dark background you can use this fact to discard the lines with other contrasts/polarities. Alternatively you can extract all the lines and then select the ones that are closest to the image boundary (if your background doesn't have lines).
要解决您的问题,您必须确保仅提取外围的线条。如果你总是有一个黑暗的背景,你可以使用这个事实来丢弃具有其他对比度/极性的线条。或者,您可以提取所有线条,然后选择最接近图像边界的线条(如果您的背景没有线条)。