我正在尝试在我的iOS程序中实现自动透视校正,当我使用我在教程中找到的测试图像时,一切都按预期工作。但是当我拍照时,我得到了一个奇怪的结果。
我正在使用此tutorial
中的代码当我给它一个看起来像这样的图像时:
我得到了这个结果:
以下dst
给了我的帮助。
我用它来调用包含代码的方法。
quadSegmentation(Img, bw, dst, quad);
与教程相比,当我获得如此多的绿线时,有人能告诉我吗?我怎么能够解决这个问题并正确裁剪图像只包含卡片?
答案 0 :(得分:34)
对于你需要的透视变换,
源点 - >源图像中四边形顶点的坐标。
目的地点 - >目标图像中相应四边形顶点的坐标。
这里我们将按轮廓过程计算这些点。
计算源图像中四边形顶点的坐标
epsilon
以进行4次坐标。
计算目标图像中相应四边形顶点的坐标
在下图中,红色矩形表示源点,绿色表示目标点。
调整坐标顺序和应用透视变换
查看最终结果
<强>代码强>
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;
答案 1 :(得分:6)
teethe当您依赖其他人的代码来解决您的特定问题而不是采用代码时,通常会发生这种情况。看一下处理阶段以及它们和你的图像之间的区别(从开始使用它们的图像并确保代码有效的方式是一个好主意):
要解决您的问题,您必须确保只提取外围的线条。如果你总是有一个黑暗的背景,你可以使用这个事实来丢弃具有其他对比度/极性的线条。或者,您可以提取所有线条,然后选择最接近图像边界的线条(如果您的背景没有线条)。