在OpenCV中扭曲一组矩形以形成正方形网格

时间:2015-04-01 07:32:20

标签: c++ opencv image-processing computer-vision

我正在尝试映射包含这些点的图像,使用左上角和右下角绘制为矩形,但我确实将点作为四边形

enter image description here

我正在尝试将上面的方块映射到下面的方块:

enter image description here

我相信我应该从每个四边形中获得透视变换。以下是我编写的一些代码,用于尝试和促进这一点:

cv::Mat output = cv::Mat::zeros(outputSize,CV_32F);


    // Uses the size of the quadOutput to
    std::vector<std::vector<cv::Point2f>> quadOutputImage = quadralateralsFromImageOutput(imageToWarp.size().height);

    cv::Mat perspectiveMatrix = cv::Mat(3,3,CV_32F);

    cv::Mat warp = cv::Mat::zeros(outputSize,CV_32F);

    for (int i = 0; i < quadOutputImage.size(); i ++) {

            // get the mapping from the quadtriangles
            perspectiveMatrix = cv::getPerspectiveTransform(quadCentroids[i],quadOutputImage[i]);

            // perform the warp with the current quadtriangles
            cv::warpPerspective(imageToWarp,warp,perspectiveMatrix,output.size());

            // copy roi to output

    }

    return warp;

我通过四边形这样做,图像看起来根本不正确。它看起来有点歪斜。

修改

我也试过找到单应矩阵,但最终得到了一个奇怪的结果。这是我写的代码

    cv::Mat warpedImageGeneration(const cv::Mat& imageToWarp,cv::Size outputSize, std::vector<std::vector<cv::Point2f>> quadCentroids) {        

    // Uses the size of the quadOutput 50 by 50 squares
    std::vector<std::vector<cv::Point2f>> quadOutputImage = quadralateralsFromImageOutput(450);

    // flatten the matrices
    std::vector<cv::Point2f> flattenedQuads = flattenMatrix(quadOutputImage);
    std::vector<cv::Point2f> flattenedCentroids = flattenMatrix(quadCentroids);

    cv::Mat perspectiveMatrix = cv::Mat(3,3,CV_32F);

    cv::Mat warp = cv::Mat::zeros(450,450,CV_32F);

    perspectiveMatrix = cv::findHomography(flattenedCentroids, flattenedQuads);

    cv::warpPerspective(imageToWarp, warp, perspectiveMatrix, warp.size());

    return warp;
 }

在示例图片上,这是我获得的未扭曲结果:

enter image description here

我认为问题可能是源的顶点超出了四边形顺序,即左上角,右上角,左下角和右下角。

1 个答案:

答案 0 :(得分:1)

单独对每个矩形进行变形不会通过getPerspectiveTransform为您提供最佳效果。相反,如果您知道原始图像中每个四边形映射到变形的精确坐标,请尝试定义一个透视变换矩阵,将所有这些对应关系包含在一起。具体来说,查看源图像中每个四边形的所有角点,确定它们应在扭曲图像中的位置,并定义一个描述所有这些点的透视变换矩阵。这样,当您从源图像中提供点时,它们应该精确映射到扭曲中的扭曲点,其他所有内容都应该干净地插入。

在实施方面,有两个vector容器,其中一个容器包含所有图像点,另一个vector容器包含所有扭曲的容器图像点。订单很重要,因此请确保源vector容器中的每个位置都对应于扭曲的vector容器中的相同位置。

但是,您必须改变方向并使用findHomography代替。 findHomographygetPerspectiveTransform的更一般情况,因为您确定的转换矩阵最好将一组点转换为另一组具有最少错误的点。 getPerspectiveTransform只允许您指定4个点。 findHomography允许您根据需要指定任意数量的点。

如果要将其修改为当前框架,则已经有代码包含输入和扭曲图像的每个相应四边形的点矢量矢量。您正在访问每个向量并将其指定到getPerspectiveTransform以获得每个四元组的透视变换矩阵。只需为输入指定一个向量,为包含所有四个点的扭曲图像指定一个向量,然后单次调用findHomography。显然,顺序非常重要,因此请确保输入图像中四边形的每个位置与扭曲图像的输出位置匹配。

另外,请确保您的坐标系正确无误。 OpenCV的Point结构假设x水平坐标,而y垂直坐标。由于您已将我在原始帖子中建议的编辑内容放在首位,因此我会将它们放在此处以保证完整性,并使答案自成一体:

 cv::Mat warpedImageGeneration(const cv::Mat& imageToWarp,cv::Size outputSize, std::vector<std::vector<cv::Point2f>> quadCentroids) {

    // Uses the size of the quadOutput 50 by 50 squares
    std::vector<std::vector<cv::Point2f>> quadOutputImage = quadralateralsFromImageOutput(450);

    // flatten the matrices
    std::vector<cv::Point2f> flattenedQuads = flattenMatrix(quadOutputImage);
    std::vector<cv::Point2f> flattenedCentroids = flattenMatrix(quadCentroids);

    cv::Mat perspectiveMatrix = cv::Mat(3,3,CV_32F);

    cv::Mat warp = cv::Mat::zeros(450,450,CV_32F);

    perspectiveMatrix = cv::findHomography(flattenedCentroids, flattenedQuads);

    cv::warpPerspective(imageToWarp, warp, perspectiveMatrix, warp.size());

    return warp;
 }