鸟瞰变换OpenCV C++的透视变换

鸟瞰变换OpenCV C++的透视变换,c++,opencv,perspective,C++,Opencv,Perspective,我对视角转换到鸟瞰图感兴趣。到目前为止,我已经尝试过getPerspectiveTransform和findHomography,然后将其传递到透视图。结果非常接近,但TL和BR存在偏差。此外,变换后轮廓区域的平移也不相等 轮廓是一个正方形,内部有多个形状 关于如何进行的任何建议 到目前为止我所做的代码块 std::vector<Point2f> quad_pts; std::vector<Point2f> squre_pts; cv::

我对视角转换到鸟瞰图感兴趣。到目前为止,我已经尝试过getPerspectiveTransform和findHomography,然后将其传递到透视图。结果非常接近,但TL和BR存在偏差。此外,变换后轮廓区域的平移也不相等

轮廓是一个正方形,内部有多个形状

关于如何进行的任何建议

到目前为止我所做的代码块

    std::vector<Point2f> quad_pts;
    std::vector<Point2f> squre_pts;    

    cv::approxPolyDP( Mat(validContours[largest_contour_index]), contours_poly[0], epsilon, true );

    if (approx_poly.size() > 4) return false;

    for (int i=0; i< 4; i++)
            quad_pts.push_back(contours_poly[0][i]);

    if (! orderRectPoints(quad_pts))
            return false;

    float widthTop = (float)distanceBetweenPoints(quad_pts[1], quad_pts[0]); // sqrt( pow(quad_pts[1].x - quad_pts[0].x, 2) + pow(quad_pts[1].y - quad_pts[0].y, 2));
    float widthBottom = (float)distanceBetweenPoints(quad_pts[2], quad_pts[3]); // sqrt( pow(quad_pts[2].x - quad_pts[3].x, 2) + pow(quad_pts[2].y - quad_pts[3].y, 2));

    float maxWidth = max(widthTop, widthBottom);

    float heightLeft = (float)distanceBetweenPoints(quad_pts[1], quad_pts[2]); // sqrt( pow(quad_pts[1].x - quad_pts[2].x, 2) + pow(quad_pts[1].y - quad_pts[2].y, 2));
    float heightRight = (float)distanceBetweenPoints(quad_pts[0], quad_pts[3]); // sqrt( pow(quad_pts[0].x - quad_pts[3].x, 2) + pow(quad_pts[0].y - quad_pts[3].y, 2));

    float maxHeight = max(heightLeft, heightRight);
    int mDist = (int)max(maxWidth, maxHeight);

    // transform TO points
    const int offset = 50;
    squre_pts.push_back(Point2f(offset, offset));
    squre_pts.push_back(Point2f(mDist-1, offset));
    squre_pts.push_back(Point2f(mDist-1, mDist-1));
    squre_pts.push_back(Point2f(offset, mDist-1));

    maxWidth += offset; maxHeight += offset;
    Size matSize ((int)maxWidth, (int)maxHeight);

    Mat transmtx = getPerspectiveTransform(quad_pts, squre_pts);
   //  Mat homo = findHomography(quad_pts, squre_pts);
    warpPerspective(mRgba, mRgba, transmtx, matSize);
    return true;

原始变换前的图像不太好,方块大小不同,看起来呈波浪状。考虑到您输入的质量,您得到的结果相当好

你可以试着校准你的相机来补偿镜头的失真,你的结果可能会有所改善


编辑:仅总结以下评论,如果正方形有圆角或模糊,approxPolyDp可能无法正确定位角。您可能需要通过其他方式来改进角点位置,如更清晰的原始图像、不同的预处理中值滤波器或阈值,正如您在评论中所建议的那样,或其他用于更精细角点定位的算法,如使用cornersubpix函数或使用Hough变换检测边,然后计算它们的交点

如图所示,红色直线不会穿过极端轮廓的中间。此外,我的轮廓区域与我期望的轮廓区域不均匀。我希望避免使用相机校准或固有参数。正如我前面提到的,TL和BR不是直的。有没有可能根据一些参数来拉直它们?我会在原始的预变换图像上画四个点,看看发现了什么轮廓。由于图像中矩形的边不是直的,它们是圆形或波浪形的,因此它找到的四边形可能有1或2个像素的小错误,这足以导致您在输出中注意到的错误,在原始帖子中添加了corner_0.png。你是对的,线条是波浪形的,MatSize在最终转换中能起到作用吗?基本上是像素比?ApproxPolyDP没有准确定位角点,因为它们在你的图像中看起来是圆形的,可能只是模糊了。如果一个角点是圆形的,该函数将拾取其中一个像素,而不会拾取中心像素。你应该打印一个带有锐角的正方形,而不是圆角。另一种选择是使用更复杂的算法定位角点,例如,使用Hough变换查找边,然后计算线的交点这将更精确,因为角点将具有十进制精度感谢@user2518618,这可能是原因。我会试试你的建议。我们尝试了一些更复杂的东西,比如计算中间中心TL-BR和TR-BL,然后计算转换点,但仍然注意到一个偏差。