1

或者,也许,不够扭曲......

所以我正在尝试拍摄一张图像并指定四个角 - 然后将这四个角移动到图像中间的一个(接近)完美的正方形中。

更新 1(底部):格林威治标准时间 2013 年 9 月 10 日下午 8 点 20 分此次更新添加了数学和矩阵标签。(如果您在 8:20 之前阅读此更新,我必须道歉,我给了您非常糟糕的信息!)

我不需要它超级准确,但是我目前的结果显然不起作用,但是在查看了多个其他示例之后,我看不出我做错了什么。

这是我的模型: 因为我不能使用照片,所以使用了模型。 坐标相同。

通过一些神奇的过程,我获得了坐标。对于这个 640x480 模型,要点如下:

Corners:
  Upper-Left: 186, 87
  Upper-Right: 471, 81
  Lower-Left: 153, 350
  Lower-Right: 500, 352

我想将角移动到的点如下:

Upper-Left: 176, 96
Upper-Right: 464, 96
Lower-Left: 176, 384
Lower-Right: 464, 384

现在,这里的最终目标是获取黑点事物相对于角的坐标。我没有让盒子填满整个图像,因为中心的那个点可能在盒子外面给定一张不同的图片,所以我想保留足够的“盒子外面”的空间来概括这个过程。我知道在它移动后我能明白这一点,我只是在正确移动它时遇到了麻烦。我当前的 warpPerspective 尝试提供以下结果:

3D! 伊什。

好的,所以看起来它正在尝试正确地适应事物,但角落实际上并没有最终到达我们认为的位置。左上角离右边太远了。左下角太高了,右边的两个都太右太靠近了。好吧,好吧……让我们尝试扩展目标坐标,让它填满屏幕。

没想到...

只是看起来放大了?我的坐标是不是有问题?我需要给它新的坐标吗?来源、目的地,还是两者兼而有之?

这是我的代码:(这显然被编辑为关键信息,但如果我遗漏了什么,请让我重新包含它。)

Mat frame = inputPicture;

Point2f sourceCoords[4], destinationCoords[4];

// These values were pre-determined, and given above for this image.
sourceCoords[0].x = UpperLeft.X;
sourceCoords[0].y = UpperLeft.Y;
sourceCoords[1].x = UpperRight.X;
sourceCoords[1].y = UpperRight.Y;
sourceCoords[2].x = LowerLeft.X;
sourceCoords[2].y = LowerLeft.Y;
sourceCoords[3].x = LowerRight.X;
sourceCoords[3].y = LowerRight.Y;

// We need to make a square in the image. The 'if' is just in case the
// picture used is not longer left-to-right than it is top-to-bottom.

int top = 0;
int bottom = 0;
int left = 0;
int right = 0;

if (frame.cols >= frame.rows)
{
    int longSideMidpoint = frame.cols/2.0;
    int shortSideFifthpoint = frame.rows/5.0;
    int shortSideTenthpoint = frame.rows/10.0;

    top = shortSideFifthpoint;
    bottom = shortSideFifthpoint*4;
    left = longSideMidpoint - (3*shortSideTenthpoint);
    right = longSideMidpoint + (3*shortSideTenthpoint);
}
else
{
    int longSideMidpoint = frame.rows/2.0;
    int shortSideFifthpoint = fFrame.cols/5.0;
    int shortSideTenthpoint = frame.cols/10.0;

    top = longSideMidpoint - (3*shortSideTenthpoint);
    bottom = longSideMidpoint + (3*shortSideTenthpoint);
    left = shortSideFifthpoint;
    right = shortSideFifthpoint*4;
}

// This code was used instead when putting the destination coords on the edges.
//top = 0;
//bottom = frame.rows-1;
//left = 0;
//right = frame.cols-1;

destinationCoords[0].y = left;      // UpperLeft
destinationCoords[0].x = top;       // UL
destinationCoords[1].y = right;     // UpperRight
destinationCoords[1].x = top;       // UR
destinationCoords[2].y = left;      // LowerLeft
destinationCoords[2].x = bottom;    // LL
destinationCoords[3].y = right;     // LowerRight
destinationCoords[3].x = bottom;    // LR

Mat warp_matrix = cvCreateMat(3, 3, CV_32FC1);
warp_matrix = getPerspectiveTransform(sourceCoords, destinationCoords); // This seems to set the warp_matrix to 3x3 even if it isn't.
warpPerspective(frame, frame, warp_matrix, frame.size(), CV_INTER_LINEAR, 0);

IplImage *savePic = new IplImage(frame);
sprintf(fileName, "test/%s/photo%i-7_warp.bmp", startupTime, Count);
cvSaveImage(fileName, savePic);
delete savePic;

我也尝试过使用 perspectiveTransform,但这会导致错误:

OpenCV 错误:断言失败 (scn + 1 == m.cols && (depth == CV_32F || depth == CV_64F)) 未知函数,文件 C:\slace\builds\WinInstallerMegaPack\src\opencv\modules\core\ src\matmul.cpp,第 1926 行

这导致我尝试 getHomography 导致这个错误:

OpenCV 错误:未知函数中的断言失败 (npoints >= 0 && points2.checkVector(2) == npoints && points1.type()),文件 C:\slave\builds\WinInstallerMegaPack\src\opencv\modules\calib3d\src \fundam.cpp,第 1074 行

(我检查了 - npoints 大于零,因为它等于 points1.checkVector(2) - 它失败了,因为 points1.checkVector(2) 和 points2.checkVector(2) 不匹配 - 但我不明白什么 checkVector( 2) 确实,points1 和 points2 取自我尝试输入 getHomography 的坐标——它们与上面的坐标相同。

知道如何获得我正在寻找的输出吗?我已经困惑了一段时间了。:/

^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^- ^-^-^-^-^-^-^-^-^-^-^-^

更新1: 好的,所以我已经弄清楚它应该如何计算事物。getPerspectiveTransform 应该找到一个 3x3 矩阵,这样:

|M00  M10  M20|   |X|   |c*X'|
|M01  M11  M21| * |Y| = |c*Y'|
|M02  M12  M22|   |1|   |  c |

其中 MXX 是常数矩阵,X & Y 是输入坐标,X' & Y' 是输出坐标。这必须适用于所有四个输入/输出坐标组合。(这个想法很简单,即使到达那里的数学可能不是 - 我仍然不确定他们应该如何得到那个矩阵......在这里输入将不胜感激 - 因为我只需要一个实际坐标我不介意完全绕过 getPerspectiveTransform 和 WarpPerspective 并且只使用数学解决方案。)

获得透视变换矩阵后,WarpPerspective 基本上只是通过乘以移动每个像素的坐标:

|M00  M10  M20|   |X|
|M01  M11  M21| * |Y|
|M02  M12  M22|   |1|

对于每个坐标。然后将 c X' 和 c Y' 都除以 c(显然)。然后需要进行一些平均,因为结果不太可能是完美的整数。

好的,基本的想法很简单,但问题来了;getPerspectiveTransform 似乎不起作用!在上面的示例中,我修改了程序以打印出从 getPerspectiveTransform 获得的矩阵。它给了我这个:

|1.559647 0.043635 -37.808761|
|0.305521 1.174385 -50.688854|
|0.000915 0.000132   1.000000|

在上面的示例中,我将左上角坐标 186、87 移动到 176、96。不幸的是,当我将上面的 warp_matrix 与输入坐标 (186、87) 相乘时,我得到的不是 176、96,而是 217, 92!这与 WarpPerspective 得到的结果相同。所以至少我们知道 WarpPerspective 正在工作......

4

1 回答 1

1

嗯,亚历克斯...

您的 X 和 Y 坐标在源坐标和目标坐标上都是相反的。

换句话说:

sourceCoords[0].x = UpperLeft.X;
sourceCoords[0].y = UpperLeft.Y;

应该

sourceCoords[0].x = UpperLeft.Y;
sourceCoords[0].y = UpperLeft.X;

destinationCoords[0].y = top;
destinationCoords[0].x = left;

应该

destinationCoords[0].y = left;
destinationCoords[0].x = top;

贾斯认为你想知道。

于 2013-09-11T18:13:20.283 回答