好的,我必须承认我对OpenCV是个初学者,我的MATLAB/lin.代数知识可能会引入一些偏见。但我想要做的事情非常简单,但我仍然没有找到答案。
在尝试对透视变换下的图像(或部分图像)进行矫正时,你基本上要执行两个步骤(假设你有定义畸变物体的4个点):
- 找到某个完美矩形与畸变形状之间的变换(在OpenCV中,通过
findHomography()
或getPerspectiveTransform()
实现 - 为什么这两个函数对同一组点的操作不同是另一个故事,并且令人沮丧);这会给我们一个矩阵T。 - 将T的逆应用于最初的畸变形状,将其转换为矩形(在OpenCV中,这可以使用
warpPerspective()
完成)。
现在,这个最后的函数(warpPerspective()
)要求用户指定目标图像的大小。
我的问题是用户如何预先知道那个大小。低级别的方法是直接将变换矩阵T应用于发现物体的图像的角点,从而保证新转换的形状不会超出边界。
但是,即使你将T中的矩阵取出并手动将其应用于这些点,结果看起来也很奇怪。
在OpenCV中有一种方法可以做到这一点吗?谢谢!
P.S. 以下是一些代码:
float leftX, lowerY, rightX, higherY;
float minX = std::numeric_limits<float>::max(), maxX = std::numeric_limits<float>::min(), minY = std::numeric_limits<float>::max(), maxY = std::numeric_limits<float>::min();
Mat value, pt;
for(int i=0; i<4; i++)
{
switch(i)
{
case 0:
pt = (Mat_<float>(3, 1) << 1.00,1.00,1.00);
break;
case 1:
pt = (Mat_<float>(3, 1) << srcIm.cols,1.00,1.00);
break;
case 2:
pt = (Mat_<float>(3, 1) << 1.00,srcIm.rows,1.00);
break;
case 3:
pt = (Mat_<float>(3, 1) << srcIm.cols,srcIm.rows,1.00);
break;
default:
cerr << "Wrong switch." << endl;
break;
}
value = invH*pt;
value /= value.at<float>(2);
minX = min(minX,value.at<float>(0));
maxX = max(maxX,value.at<float>(0));
minY = min(minY,value.at<float>(1));
maxY = max(maxY,value.at<float>(1));
}
leftX = std::min<float>(1.00,-minX);
lowerY = std::min<float>(1.00,-minY);
rightX = max(srcIm.cols-minX,maxX-minX);
higherY = max(srcIm.rows-minY,maxY-minY);
warpPerspective(srcIm, dstIm, H, Size(rightX-leftX,higherY-lowerY), cv::INTER_CUBIC);
更新:也许我的结果看起来不好是因为我使用的矩阵是错误的。由于我无法观察到getPerspectiveTransform()
内部发生了什么,因此我无法知道如何计算这个矩阵,但它具有一些非常小和非常大的值,这使我认为它们是垃圾数据。
以下是我从T中获取数据的方法:
for(int row=0;row<3;row++)
for(int col=0;col<3;col++)
T.at<float>(row,col) = ((float*)(H.data + (size_t)H.step*row))[col];
尽管
getPerspectiveTransform()
的输出矩阵是3x3,但是尝试直接通过T.at<float>(row,col)
访问其值会导致分段错误。这样做是否正确?也许这就是出现原始问题的原因,因为我没有得到正确的矩阵...