【问题标题】:Automatic perspective correction OpenCV自动透视校正 OpenCV
【发布时间】:2014-04-26 12:08:07
【问题描述】:

我正在尝试在我的 iOS 程序中实现自动透视校正,当我使用在教程中找到的测试图像时,一切都按预期工作。但是当我拍照时,我得到了一个奇怪的结果。

我正在使用tutorial中的代码

当我给它一个看起来像这样的图像时:

结果如下:

这是dst 给我的可能有帮助的东西。

我正在使用它来调用包含代码的方法。

quadSegmentation(Img, bw, dst, quad);

谁能告诉我什么时候我得到这么多绿线与教程相比?以及我如何才能解决此问题并正确裁剪图像以仅包含卡片?

【问题讨论】:

  • 你的结果对我来说就像垃圾一样。您需要显示更多代码。具体来说,您发送Img 的格式是什么,您如何解释输出行?
  • 确实很有帮助!!但请注意,如果名片相对于水平轴保持一定角度,则可能无法正常工作。在这种情况下,边界矩形也将与水平轴成相同的角度,因此角点将不同

标签: c++ ios opencv


【解决方案1】:

teethe 当您依赖其他人的代码来解决您的特定问题而不是采用该代码时,通常会发生这种情况。查看处理阶段以及它们与您的图像之间的区别(最好从他们的图像开始并确保代码有效):

  1. 获取边缘图。 - 可能会工作,因为你的边缘很好
  2. 使用霍夫变换检测线条。 - 失败,因为您不仅在轮廓上有线条,而且在卡片内部也有线条。所以期待很多误报
  3. 通过寻找线之间的交点来获得拐角。 - 因上述原因失败
  4. 检查近似多边形曲线是否有 4 个顶点。 - 失败
  5. 确定左上角、左下角、右上角和右下角。 - 失败
  6. 应用透视变换。 - 完全失败

要解决您的问题,您必须确保只提取外围的线。如果您总是有深色背景,则可以使用此事实来丢弃具有其他对比度/极性的线条。或者,您可以提取所有线条,然后选择最接近图像边界的线条(如果您的背景没有线条)。

【讨论】:

    【解决方案2】:

    对于您需要的透视变换,

    源点->源图像中四边形顶点的坐标。

    destination points->目标图像中对应四边形顶点的坐标。

    这里我们将通过轮廓过程计算这些点。

    计算源图像中四边形顶点的坐标

    • 您只需通过模糊、阈值处理、查找轮廓、查找最大轮廓等即可将您的卡片作为轮廓。
    • 找到最大轮廓后计算approximates a polygonal curve,在这里你应该得到4个点,代表你卡片的角。您可以调整参数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;
    

    【讨论】:

    • 非常感谢!我会在早上研究这个。
    • 我几乎了解所有代码,但你能解释一下 if 语句后的 squre_pts 吗?
    • 这不过是在我们考虑源点时按顺序获得四个角点来包围矩形。
    • 当我设置阈值thr 时,我无法取回您在结果中取回的图像,其中包括卡片背景中的一些噪音和卡片本身的一些文字。这是直接来自 iOS 设备的源图像的示例。 i.imgur.com/T4wsOW8.jpg 知道如何解决这个问题吗?它导致 if-statment 返回 false。
    • 只有一个答案中的许多很酷和简单的想法,例如:“......这可以通过计算最大轮廓的边界矩形来轻松找出......”!非常有趣和有用的说明。非常非常感谢!
    猜你喜欢
    • 2014-12-20
    • 1970-01-01
    • 2014-05-04
    • 2018-01-11
    • 1970-01-01
    • 1970-01-01
    • 2018-05-27
    • 2012-06-09
    • 1970-01-01
    相关资源
    最近更新 更多