c++ - OpenCV/C++:warpPerspective产生过度扭曲的结果

标签 c++ math opencv image-processing matrix

或者,也许是翘曲不够……

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

更新1(在底部):13/9/13 @ 8:20 GMT 此更新添加了数学和矩阵标记。 (如果您在8:20之前阅读了此更新,我必须道歉,我给了您非常糟糕的信息!)

我不需要 super 准确,但是我目前的结果显然是行不通的,但是在查看了多个其他示例之后,我看不到我做错了什么。

这是我的模型:

通过一些神奇的过程,我得到了坐标。对于此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尝试提供以下结果:

好的,看起来好像正在尝试正确地放置东西,但实际上这些拐角并没有到达我们认为合适的地方。左上方距离右侧太远。底部左脚太高,右侧的两个脚都太右,也太靠近。好吧,好吧...因此,让我们尝试扩展目标坐标,使其填满整个屏幕。

似乎只是放大了?我的坐标以某种方式偏离吗?我是否需要为其提供新的坐标?源,目的地或两者兼而有之?

这是我的代码:(显然,这已被编辑为关键信息,但是如果我错过了某些内容,请让我重新添加它。)
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 Error: Assertion failed (scn + 1 == m.cols && (depth == CV_32F || depth == CV_64F)) in unknown function, file C:\slace\builds\WinInstallerMegaPack\src\opencv\modules\core\src\matmul.cpp, line 1926



这导致我尝试使用getHomography导致此错误,而不是:

OpenCV Error: Assertion failed (npoints >= 0 && points2.checkVector(2) == npoints && points1.type()) in unknown function, file C:\slave\builds\WinInstallerMegaPack\src\opencv\modules\calib3d\src\fundam.cpp, line 1074



(我检查了-npoints大于零,因为它等于points1.checkVector(2)-失败是因为points1.checkVector(2)和points2.checkVector(2)不匹配-但我不明白checkVector( 2)可以,point1和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|

对于每个坐标。然后将cX'和cY'都除以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正在工作...

最佳答案

嗯亚历克斯

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;

Jus想知道的想法。

关于c++ - OpenCV/C++:warpPerspective产生过度扭曲的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18644023/

相关文章:

python - AttributeError: 'NoneType'对象没有属性 'shape'/从多个轮廓框转换为单数

c++ - 采用 Bamboo 或 TeamCity 作为原生 Windows C++ 构建自动化/CI 服务器?

c++ - 为什么我可以在类之外声明构造函数

c++ - 重载、字符串和默认参数

c++ - Djikstra的实现似乎与理论复杂性不符

algorithm - 如何快速估算透视图中立方体的投影面积?

c++ - 限制 Concurrency::parallel_for 中使用的线程数

c# - 如何计算三个数之间的最大公约数

python - OpenCV 3.2.0 windows,OpenCL 在 C++ 中显示设备,但在 python 中不显示

c++ - 我有一个使用 openCV 检测人脸的视频流,我怎么能捕捉到离相机最近的人脸并将其保存到图像文件中呢?