好的,我不得不承认我是 OpenCV 和我的 MATLAB/lin 的新手。代数知识可能会引入偏见。但是我想做的很简单,虽然我仍然没有找到答案。
当试图在透视变换下校正图像(或图像的一部分)时,您基本上执行两个步骤(假设您有定义扭曲对象的 4 个点):
- 找到一些完美矩形和扭曲形状之间的转换(在 OpenCV 中,通过
findHomography()
或getPerspectiveTransform()
- 为什么这两者在相同点上的操作不同是另一回事,也令人沮丧);这给了我们一个矩阵T。 -
将 T 的倒数应用于最初扭曲的形状以将其转换为矩形(在 OpenCV 中,这是用 完成的
warpPerspective()
)。
现在,最后一个函数 ( warpPerspective()
) 要求用户指定目标图像的大小。
我的问题是用户应该如何事先知道该尺寸是多少。执行此操作的低级方法是简单地将变换 T 应用于找到对象的图像的角点,从而保证您不会超出新变换形状的范围。但是,即使您从 T 中取出矩阵并将其手动应用于这些点,结果看起来也很奇怪。
有没有办法在 OpenCV 中做到这一点?谢谢!
PS下面是一些代码:
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)
会导致分段错误。)
这是正确的方法吗?也许这就是出现原始问题的原因,因为我没有得到正确的矩阵......