如何在摄像机拍摄坐标中取消失真并获得相应的未失真图像坐标?

时间:2011-12-14 05:43:40

标签: opencv computer-vision

我使用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 );

我收到良好的无失真图像,这意味着与单独的点相比,像素坐标的修改不会那么大。

如何获得与图像相同的特定点的不失真度? 感谢。

3 个答案:

答案 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声道输入,但实际上它接受

  • 1列,2通道,多排垫或(此情况未记录)
  • 2列,多行,1通道垫或
  • 多列,1行,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()