最初我的图像带有完美的圆形网格,表示为 A 我添加了一些镜头失真和透视变换,它变成 B 在相机校准中, A 将是我的目标图像, B 将是我的源图像。 假设我在两个图像中都有所有圆心坐标,存储在 stdPts 和 disPts 中。
//25 center pts in A
vector<Point2f> stdPts;
for (int i = 0; i <= 4; ++i) {
for (int j = 0; j <= 4; ++j) {
stdPts[i * 5 + j].x = 250 + i * 500;
stdPts[i * 5 + j].y = 200 + j * 400;
}
}
//25 center pts in B
vector<Point2f> disPts = FindCircleCenter();
我想从输入中生成与 A 一样接近的图像 C : B , stdPts 和 disPts 。 我试图使用cv :: calibrateCamera生成的内在和外在。这是我的代码:
//prepare object_points and image_points
vector<vector<Point3f>> object_points;
vector<vector<Point2f>> image_points;
object_points.push_back(stdPts);
image_points.push_back(disPts);
//prepare distCoeffs rvecs tvecs
Mat distCoeffs = Mat::zeros(5, 1, CV_64F);
vector<Mat> rvecs;
vector<Mat> tvecs;
//prepare camera matrix
Mat intrinsic = Mat::eye(3, 3, CV_64F);
//solve calibration
calibrateCamera(object_points, image_points, Size(2500,2000), intrinsic, distCoeffs, rvecs, tvecs);
//apply undistortion
string inputName = "../B.jpg";
Mat imgB = imread(imgName);
cvtColor(imgB, imgB, CV_BGR2GRAY)
Mat tempImgC;
undistort(imgB, tempImgC, intrinsic, distCoeffs);
//apply perspective transform
double transData[] = { 0, 0, tvecs[0].at<double>(0), 0, 0,,tvecs[0].at<double>(1), 0, 0, tvecs[0].at<double>(2) };
Mat translate3x3(3, 3, CV_64F, transData);
Mat rotation3x3;
Rodrigues(rvecs[0], rotation3x3);
Mat transRot3x3(3, 3, CV_64F);
rotation3x3.col(0).copyTo(transRot3x3.col(0));
rotation3x3.col(1).copyTo(transRot3x3.col(1));
translate3x3.col(2).copyTo(transRot3x3.col(2));
Mat imgC;
Mat matPerspective = intrinsic*transRot3x3;
warpPerspective(tempImgC, imgC, matPerspective, Size(2500, 2000));
//write
string outputName = "../C.jpg";
imwrite(outputName, imgC); // A JPG FILE IS BEING SAVED
有人可以教我如何恢复 A 吗?感谢。
答案 0 :(得分:0)
<强>加强>
好的,伙计们,简单的错误。我之前使用 warpPerspective 来扭曲图像而不是恢复。由于它以这种方式工作,我没有彻底阅读the doc。事实证明,如果要进行恢复,则应设置标志 WARP_INVERSE_MAP 。将函数调用更改为this,就是这样。warpPerspective(tempImgC, imgC, matPerspective, Size(2500, 2000), WARP_INVERSE_MAP);
我现在唯一关心的是中间件 tempImgC ,它是 undistort 之后和 warpPerspective 之前的图片。在一些使用不同人工 B 的测试中,此图片可能会成为 B 的放大版本>删除失真。这意味着在外地区域丢失了大量信息。 warpPerspective 没有多少用处。我想也许可以缩小 undistort 中的图像并在 warpPerspective 中进行缩放。但我不确定如何计算正确的比例以保留 B 中的所有信息。
已添加2
最后一块拼图已经到位。在 undistort 之前调用 getOptimalNewCameraMatrix 以生成保留 B 中所有信息的新相机矩阵。并将此新相机矩阵传递给 undistort 和 warpPerspective。
Mat newIntrinsic=getOptimalNewCameraMatrix(intrinsic, distCoeffs, Size(2500, 2000), 1);
undistort(imgB, tempImgC, intrinsic, distCoeffs, newIntrinsic);
Mat matPerspective = newIntrinsic*transRot3x3;
warpPerspective(tempImgC, imgC, matPerspective, Size(2500, 2000), WARP_INVERSE_MAP);
在这种情况下,结果图像 C 是相同的。但其他案例则有很大差异。例如,使用另一个扭曲的图像 B1 。 没有新相机矩阵的结果图像 C1 如下所示。 使用新相机矩阵的结果图像 C1 可以在 B1 中保留信息
已添加3
我意识到,由于相机捕获的每个帧需要处理和效率很重要,我不能为每个帧使用undistort
和warpPerspective
。拥有一张地图并为每一帧使用remap
是合理的。
实际上,有一种直接的方式,即projectPoints
。由于它直接生成从目标图像到源图像的地图,不需要中间图像,因此可以避免信息丢失。
// ....
//solve calibration
//generate a 3-channel mat with each entry containing it's own coordinates
Mat xyz(2000, 2500, CV_32FC3);
float *pxyz = (float*)xyz.data;
for (int y = 0; y < 2000; y++)
for (int x = 0; x < 2500; x++)
{
*pxyz++ = x;
*pxyz++ = y;
*pxyz++ = 0;
}
// project coordinates of destination image,
// which generates the map from destination image to source image directly
xyz=xyz.reshape(0, 5000000);
Mat mapToSrc(5000000, 1, CV_32FC2);
projectPoints(xyz, rvecs[0], tvecs[0], intrinsic, distCoeffs, mapToSrc);
Mat maps[2];
mapToSrc = mapToSrc.reshape(0, 2000);
split(mapToSrc, maps);
//apply map
remap(imgB, imgC, maps[0], maps[1], INTER_LINEAR);