我使用OpenCV在摄像机校准后取消设定点集。 代码如下。
const int npoints = 2; // number of point specified
// Points initialization.
// Only 2 ponts in this example, in real code they are read from file.
float input_points[npoints][2] = {{0,0}, {2560, 1920}};
CvMat * src = cvCreateMat(1, npoints, CV_32FC2);
CvMat * dst = cvCreateMat(1, npoints, CV_32FC2);
// fill src matrix
float * src_ptr = (float*)src->data.ptr;
for (int pi = 0; pi < npoints; ++pi) {
for (int ci = 0; ci < 2; ++ci) {
*(src_ptr + pi * 2 + ci) = input_points[pi][ci];
}
}
cvUndistortPoints(src, dst, &camera1, &distCoeffs1);
以上代码dst
包含以下数字后:
-8.82689655e-001 -7.05507338e-001 4.16228324e-001 3.04863811e-001
与src
中的数字相比太小。
同时,如果我通过电话取消图像:
cvUndistort2( srcImage, dstImage, &camera1, &dist_coeffs1 );
我收到良好的无失真图像,这意味着与单独的点相比,像素坐标的修改不会那么大。
如何获得与图像相同的特定点的不失真度? 感谢。
答案 0 :(得分:10)
使用相机矩阵,这些点应该是“非标准化的”。
更具体地说,在调用cvUndistortPoints
之后,还应添加以下转换:
double fx = CV_MAT_ELEM(camera1, double, 0, 0);
double fy = CV_MAT_ELEM(camera1, double, 1, 1);
double cx = CV_MAT_ELEM(camera1, double, 0, 2);
double cy = CV_MAT_ELEM(camera1, double, 1, 2);
float * dst_ptr = (float*)dst->data.ptr;
for (int pi = 0; pi < npoints; ++pi) {
float& px = *(dst_ptr + pi * 2);
float& py = *(dst_ptr + pi * 2 + 1);
// perform transformation.
// In fact this is equivalent to multiplication to camera matrix
px = px * fx + cx;
py = py * fy + cy;
}
有关OpenCV 'Camera Calibration and 3D Reconstruction'
的相机矩阵的更多信息<强>更新强>
以下C ++函数调用也应该有效:
std::vector<cv::Point2f> inputDistortedPoints = ...
std::vector<cv::Point2f> outputUndistortedPoints;
cv::Mat cameraMatrix = ...
cv::Mat distCoeffs = ...
cv::undistortPoints(inputDistortedPoints, outputUndistortedPoints, cameraMatrix, distCoeffs, cv::noArray(), cameraMatrix);
答案 1 :(得分:1)
可能是您的矩阵大小:)
OpenCV期望一个点向量 - 具有两个通道的列或行矩阵。但由于您的输入矩阵仅为2 pts,并且通道数也为1,因此无法确定输入,行或列的内容。
所以,填充一个带有伪值的较长输入垫,并只保留第一个:
const int npoints = 4; // number of point specified
// Points initialization.
// Only 2 ponts in this example, in real code they are read from file.
float input_points[npoints][4] = {{0,0}, {2560, 1920}}; // the rest will be set to 0
CvMat * src = cvCreateMat(1, npoints, CV_32FC2);
CvMat * dst = cvCreateMat(1, npoints, CV_32FC2);
// fill src matrix
float * src_ptr = (float*)src->data.ptr;
for (int pi = 0; pi < npoints; ++pi) {
for (int ci = 0; ci < 2; ++ci) {
*(src_ptr + pi * 2 + ci) = input_points[pi][ci];
}
}
cvUndistortPoints(src, dst, &camera1, &distCoeffs1);
修改强>
虽然OpenCV指定undistortPoints只接受2声道输入,但实际上它接受
(见于undistort.cpp,第390行)
但是内部的一个错误(或缺少可用信息)会使第二个与第三个错误混合,当列数为2.因此,您的数据被认为是2列,2行, 1通道。
答案 2 :(得分:0)
我也遇到了这个问题,我花了一些时间来研究最终的理解。
<img src="https://i.stack.imgur.com/nmR5P.jpg"></img>
Formula
您会看到上面的公式,在开放系统中,扭曲操作在相机矩阵之前,因此处理顺序为:
image_distorted-> camera_matrix->取消扭曲功能-> camera_matrix->回到image_undistorted。
因此,您需要再次修复和camera1。
Mat eye3 = Mat :: eye(3,3,CV_64F);
cvUndistortPoints(src,dst,&camera1,&distCoeffs1,&eye3,&camera1 );
否则,如果最后两个参数为空,则将其投影到归一化图像坐标。
查看代码:opencv-3.4.0-src \ modules \ imgproc \ src \ undistort.cpp:297 cvUndistortPointsInternal()