实现OpenCV中的warpPerspective()方法

4
我正试图从头开始实现openCV中的warpPerspective()方法,我编写了下面的代码,它可以处理y和x的移位,但是当我将findHomography()函数生成的单应性矩阵传递给我编写的函数时,与warpPerspective()输出相比,它总是产生空白图像。
我按照以下定义来找到像素的新位置: s*x' h1 h2 h3 x s*y' = h4 h5 h6 * y s h7 h8 1 1
我的映射可以处理像{1,0.5,-51,0,1,50,0,0,1}这样的简单移位。 enter image description here 但是当矩阵如下所示时: [1.0340946, 0.032195676, -6.419126; 0.00302419, 1.0487343, -96.520393; 3.7013847e-06, 0.00010837225, 1]
输出结果如下所示: enter image description here 我的实现方式如下: -给定H和图像A, -在A中找到像素的新位置并将它们保存在TransArry中,其中数组的索引是A的线性化索引。 -将A的像素重新映射到tranImg中。
    Mat transform(Mat A, Mat H)
{
// allocate array of all locations
int Numrows = A.rows;
int Numcols = A.cols;
int channels   = A.channels();
cout << "rows " << Numrows << "col " << Numcols << "channels " << channels <<endl;
int size = Numrows*Numcols;
int MaxX,MaxY = -1000;
int MinX,MinY =  1000;
int *TransArry = (int *)malloc(sizeof(int)*size);
int Idx;

 int homeX=Idx % Numcols;
 int homeY=Idx / Numcols;
 cout << H << endl;

 waitKey();         
for (Idx=0; Idx < size; ++Idx ){

        homeX=Idx % Numcols;
        homeY=Idx / Numcols;

        float x  = (H.at<float>(0,0) * (homeX)) +( H.at<float>(0,1) * (homeY)) + ( H.at<float>(0,2) * 1) ;
        float y  = (H.at<float>(1,0) * (homeX)) +( H.at<float>(1,1) * (homeY)) + ( H.at<float>(1,2) * 1) ;
        float s  = (H.at<float>(2,0) * (homeX)) +( H.at<float>(2,1) * (homeY)) + ( H.at<float>(2,2) * 1) ;

        cout << " x = " << x << " y= " << y << " s= " << s;
        x = (x/s);

        y = y/s;

        // for the first col in TransMatrix
        if (homeX ==0){
            if (x > MaxX) MaxX = x;
            if (x < MinX) MinX = x; 
        }

        //for thee first row in TransMatrix
        if (homeY ==0){
            if (y > MaxY) MaxY = y;
            if (y < MinY) MinY = y;
        }
        if((y)>=A.rows || (y)<0 || (x)>=A.cols || (x)<0){
            TransArry[Idx]  = -1;
            cout << "x= " << x << "y= "<< y << endl;
        }else{
            TransArry[Idx] = (y * Numcols + x); 
        }           

        //cout << Numcols << endl;
        cout <<     "New index of " << Idx << "is " << TransArry[Idx] << endl;
        }

         Mat   tranImg ;

         A.copyTo(tranImg);
         tranImg = tranImg - tranImg;
        cout <<     "Rows" << tranImg.rows << "cols" << tranImg.cols << "cha" <<  A.channels() << endl;


        waitKey();
        // Remap Image
        for (Idx=0; Idx < size; Idx ++ ){

            homeX=Idx % Numcols;
            homeY=Idx / Numcols;                
            //tranImg.at<uchar>(homeY, homeX) =0;
            if(TransArry[Idx] != -1){   
                //cout << "Index " << Idx << "Passed " << endl;
                int newhomeX=TransArry[Idx] % Numcols; // Col ID
                int newhomeY=TransArry[Idx] / Numcols;  // Row ID


                 cout << "Index is " << Idx << endl;
                 cout << "HomeX is " << homeX << " and HomeY is " << homeY << endl;
                 cout << "New Index is " << TransArry[Idx] << endl;
                 cout << "New HomeX is " << newhomeX << " and New HomeY is " << newhomeY << endl;   
                 cout << "*****************************************"<< endl; 
                // if (!(Idx%100)) sleep(20);  

                tranImg.at<uchar>(newhomeY, (newhomeX*channels)) = A.at<uchar>(homeY, homeX*channels);
                if(channels>1)
                    tranImg.at<uchar>(newhomeY, newhomeX*channels+1) = A.at<uchar>(homeY, homeX*channels+1);
                if(channels>2)
                    tranImg.at<uchar>(newhomeY, newhomeX*channels+2) = A.at<uchar>(homeY, homeX*channels+2);
                // if (!(Idx%100)){
                    // imshow("inside", tranImg);
                    // waitKey(1);
                    // }
                }
        }
        //cout << tranImg << endl;  

return tranImg;

}

已计算并验证 H 矩阵。

那么,我访问 H 和 A 矩阵的方式有问题吗?

2个回答

3
请参考我在这里的回答,它可以回答你的两个问题。这个回答仍然使用了warpPerspective(),但它完整地解释了如何计算单应性变换使图像超出图像边界的距离,因此你可以适当地在图像的每一侧进行填充。
至于手动执行warpPerspective(),您只需要将所有图像坐标放入线性化的齐次数组中,并乘以单应矩阵,然后除以最后一个坐标以返回笛卡尔坐标。然后,您可以使用remap()进行插值。对于remap()的语法可能会让人困惑,你可以参考我的回答这里来了解如何使用它。这个回答显示了一个手动的变换和插值,它应该可以给你(至少基本上)与warpPerspective()相同的结果。

谢谢你详细的回答。我尝试了一个解决方案,但是我没有得到旋转后的图像。我应该发布我的代码到另一个问题吗?由于我在处理矩阵元素时遇到了问题,并尝试将它们转换为C数组。 - Karam Abo Ghalieh
1
@KaramAboGhalieh 我认为它仍然很好地适合这个问题的范围,你应该编辑你的原始帖子并包括代码和当前问题(但我建议不要删除任何你当前的帖子)。编辑您的帖子也会在问题队列中提高其优先级,因此您可能会得到更多的回复。此外,请查看我的GitHub存储库padded warps in C++,这可能会有所帮助。 - alkasm
我的实现对于x或y的移位工作正常,但无法处理完整的H矩阵。 - Karam Abo Ghalieh
@KaramAboGhalieh 上面的缩进非常混乱,代码很难读。如果你能更好地组织它,就会更容易发现任何问题。你能给出示例输入和当前输出吗?你说的“无法处理完整的H矩阵”是什么意思? - alkasm
抱歉,现在怎么样?我所说的完整矩阵是这样的{0.97744,-0.014668,1.75,-0.00308,0.96445,91.30,-4.80865,-7.4539,1};例如,我能够处理这个矩阵{1,0.5,-51,0,1,50,0,0,1},但不能处理前面那个。 - Karam Abo Ghalieh

0

我找到了问题所在。您使用的坐标是浮点数而不是整数。将x和y强制转换为整数并向下取整,即x = floor(x/s)和y = floor(y/s)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接