你如何重新扭曲一个点?
How do you redistort a point?
我有一张扭曲的图像,我使用 Cv2.Undistort()
将其拉直。在此之后,我在图像中找到了一些点。我需要得到这些点在扭曲图像中的位置。
我已经尝试 Cv2.ProjectPoints()
但未能获得合适的坐标。他们在图像的边界之外。
我就是这样做的:
List<float> arr = new List<float>();
foreach (var i in points)
{
arr.Add(i.X);
arr.Add(i.Y);
arr.Add(0);
}
Mat pointArr = new Mat(3, points.Count, MatType.CV_32FC1, arr.ToArray());
float[] rotArr = { 1, 0, 0,
0, 1, 0,
0, 0, 1};
float[] transArr = { 0, 0, 0 };
Mat rot = new Mat(3, 1, MatType.CV_32F, rotArr);
Mat trans = new Mat(3, 1, MatType.CV_32F, transArr);
Cv2.ProjectPoints(pointArr, rot, trans, camMatrix, dist, outputPoints);
List<Point2f> point2Fs = new List<Point2f>();
var lngt = outputPoints.Rows * outputPoints.Cols * outputPoints.Channels();
var matarr = new List<float>();
for (int i = 0; i < outputPoints.Rows; i++)
{
point2Fs.Add(new Point2f(outputPoints.ExtractChannel(0).At<float>(0, i), outputPoints.ExtractChannel(1).At<float>(0, i)));
}
points - 我想在原始图像中找到的未失真图像中的点
有什么建议吗?
谢谢!
不幸的是,OpenCV 没有提供直接执行您想要的操作的功能,即将失真系数应用于未失真的 2D 点。您可以:
选项 1
您使用 projectPoints() 的方法正确。理解这是如何工作的诀窍是未失真图像中的一个点“存在于”图像平面中,它看起来像这样(图片来自https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html):
其中图像平面位于距原点 f(焦距)和 x 和 y坐标是相对于cx和cy.
您要做的是从未失真的 2D 点 (xu, yu) 像这样:
x = (x_u - c_x) / f_x
y = (y_u - c_y) / f_y
z = 1
而不是像在第一个 foreach[=64 中那样使用 (xu, yu, 0) =]循环。
然后调用 projectPoints()。
您正确地使用了身份旋转和 0 翻译。 fx、fy、cx 和 cy, 在 cameraMatrix:
|f_x 0 c_x|
| 0 f_y c_y|
| 0 0 1 |
选项 2:
您可以直接应用失真方程 (https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html):
在第一步中,您将 x' 和 y' 替换为:
x' = (x_u - c_x) / f_x
y' = (y_u - c_y) / f_y
然后应用其余的方程式。这就是 projectPoints() 所做的,没有 rotation/translation 部分。
我最终使用了 Milo 提出的第二个选项。我已经重写了没有旋转和平移部分的项目点方法,并从 x' 和 y' 开始方程路径,其中:
x' = (x_u - c_x) / f_x
y' = (y_u - c_y) / f_y
然后我应用了其余提供的方程式。
这里是源代码:
Point2f DistortPoint(Point2f point)
{
var tempPt = new Point2f((point.X-intr.cx)/intr.fx, (point.Y-intr.cy)/intr.fy);
var r2 = Math.Pow(tempPt.X, 2) + Math.Pow(tempPt.Y, 2);
var xtmp = tempPt.X * ((1 + intr.k1 * r2 + intr.k2 * Math.Pow(r2, 2) + intr.k3 * Math.Pow(r2, 3)) /
(1 + intr.k4 * r2 + intr.k5 * Math.Pow(r2, 2) + intr.k6 * Math.Pow(r2, 3))) + 2 * intr.p1 * tempPt.X * tempPt.Y + intr.p2 * (r2 + 2 * Math.Pow(tempPt.X, 2));
var ytmp = tempPt.Y * ((1 + intr.k1 * r2 + intr.k2 * Math.Pow(r2, 2) + intr.k3 * Math.Pow(r2, 3)) /
(1 + intr.k4 * r2 + intr.k5 * Math.Pow(r2, 2) + intr.k6 * Math.Pow(r2, 3))) + 2 * intr.p2 * tempPt.X * tempPt.Y + intr.p1 * (r2 + 2 * Math.Pow(tempPt.Y, 2));
return new Point2f((float)(intr.fx * xtmp + intr.cx), (float)(intr.fy * ytmp + intr.cy));
}
我通过使用从 cv2.initUndistortRectifyMap()
返回的索引 mapx
和 mapy
来做到这一点。
x_distored = mapx[y_rectified, x_rectified]
y_distored = mapy[y_rectified, x_rectified]
此方法的局限性在于索引必须在范围内。
即使在 x_rectified
和 y_rectified
归一化后,我也无法使用 Cv2.ProjectPoints()
将校正位置投影到扭曲。我的问题是无法将 R
和 T
(我从 cv2.stereoRectify()
得到它们。它们不全是零。)转换为 rvec
和 tvec
所需的 Cv2.ProjectPoints()
作为输入。如果哪位有成功的经验请分享一下,谢谢!
我有一张扭曲的图像,我使用 Cv2.Undistort()
将其拉直。在此之后,我在图像中找到了一些点。我需要得到这些点在扭曲图像中的位置。
我已经尝试 Cv2.ProjectPoints()
但未能获得合适的坐标。他们在图像的边界之外。
我就是这样做的:
List<float> arr = new List<float>();
foreach (var i in points)
{
arr.Add(i.X);
arr.Add(i.Y);
arr.Add(0);
}
Mat pointArr = new Mat(3, points.Count, MatType.CV_32FC1, arr.ToArray());
float[] rotArr = { 1, 0, 0,
0, 1, 0,
0, 0, 1};
float[] transArr = { 0, 0, 0 };
Mat rot = new Mat(3, 1, MatType.CV_32F, rotArr);
Mat trans = new Mat(3, 1, MatType.CV_32F, transArr);
Cv2.ProjectPoints(pointArr, rot, trans, camMatrix, dist, outputPoints);
List<Point2f> point2Fs = new List<Point2f>();
var lngt = outputPoints.Rows * outputPoints.Cols * outputPoints.Channels();
var matarr = new List<float>();
for (int i = 0; i < outputPoints.Rows; i++)
{
point2Fs.Add(new Point2f(outputPoints.ExtractChannel(0).At<float>(0, i), outputPoints.ExtractChannel(1).At<float>(0, i)));
}
points - 我想在原始图像中找到的未失真图像中的点
有什么建议吗?
谢谢!
不幸的是,OpenCV 没有提供直接执行您想要的操作的功能,即将失真系数应用于未失真的 2D 点。您可以:
选项 1
您使用 projectPoints() 的方法正确。理解这是如何工作的诀窍是未失真图像中的一个点“存在于”图像平面中,它看起来像这样(图片来自https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html):
其中图像平面位于距原点 f(焦距)和 x 和 y坐标是相对于cx和cy.
您要做的是从未失真的 2D 点 (xu, yu) 像这样:
x = (x_u - c_x) / f_x
y = (y_u - c_y) / f_y
z = 1
而不是像在第一个 foreach[=64 中那样使用 (xu, yu, 0) =]循环。
然后调用 projectPoints()。
您正确地使用了身份旋转和 0 翻译。 fx、fy、cx 和 cy, 在 cameraMatrix:
|f_x 0 c_x|
| 0 f_y c_y|
| 0 0 1 |
选项 2:
您可以直接应用失真方程 (https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html):
在第一步中,您将 x' 和 y' 替换为:
x' = (x_u - c_x) / f_x
y' = (y_u - c_y) / f_y
然后应用其余的方程式。这就是 projectPoints() 所做的,没有 rotation/translation 部分。
我最终使用了 Milo 提出的第二个选项。我已经重写了没有旋转和平移部分的项目点方法,并从 x' 和 y' 开始方程路径,其中:
x' = (x_u - c_x) / f_x
y' = (y_u - c_y) / f_y
然后我应用了其余提供的方程式。
这里是源代码:
Point2f DistortPoint(Point2f point)
{
var tempPt = new Point2f((point.X-intr.cx)/intr.fx, (point.Y-intr.cy)/intr.fy);
var r2 = Math.Pow(tempPt.X, 2) + Math.Pow(tempPt.Y, 2);
var xtmp = tempPt.X * ((1 + intr.k1 * r2 + intr.k2 * Math.Pow(r2, 2) + intr.k3 * Math.Pow(r2, 3)) /
(1 + intr.k4 * r2 + intr.k5 * Math.Pow(r2, 2) + intr.k6 * Math.Pow(r2, 3))) + 2 * intr.p1 * tempPt.X * tempPt.Y + intr.p2 * (r2 + 2 * Math.Pow(tempPt.X, 2));
var ytmp = tempPt.Y * ((1 + intr.k1 * r2 + intr.k2 * Math.Pow(r2, 2) + intr.k3 * Math.Pow(r2, 3)) /
(1 + intr.k4 * r2 + intr.k5 * Math.Pow(r2, 2) + intr.k6 * Math.Pow(r2, 3))) + 2 * intr.p2 * tempPt.X * tempPt.Y + intr.p1 * (r2 + 2 * Math.Pow(tempPt.Y, 2));
return new Point2f((float)(intr.fx * xtmp + intr.cx), (float)(intr.fy * ytmp + intr.cy));
}
我通过使用从 cv2.initUndistortRectifyMap()
返回的索引 mapx
和 mapy
来做到这一点。
x_distored = mapx[y_rectified, x_rectified]
y_distored = mapy[y_rectified, x_rectified]
此方法的局限性在于索引必须在范围内。
即使在 x_rectified
和 y_rectified
归一化后,我也无法使用 Cv2.ProjectPoints()
将校正位置投影到扭曲。我的问题是无法将 R
和 T
(我从 cv2.stereoRectify()
得到它们。它们不全是零。)转换为 rvec
和 tvec
所需的 Cv2.ProjectPoints()
作为输入。如果哪位有成功的经验请分享一下,谢谢!