2011-12-14 19 views
6

我使用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号码比较。

在如果我经由呼叫undistort图像相同的时间:

cvUndistort2(srcImage, dstImage, &camera1, &dist_coeffs1); 

我收到良好的失真的图像,这意味着像素坐标不与单独的点比较修改,以便大幅度。

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

+0

你确定camera1和相机是一样的吗? – Sam 2011-12-14 06:47:04

+0

是的,相同 - 我有固定的问题。感谢您指出。此外,最初我在EmguCV中收到了这样的行为,然后试图找出引入此类行为的位置:OpenCV或EmguCV本身。它出现在OpenCV中。 – sergtk 2011-12-14 12:40:47

回答

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'

UPDATE:

以下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

这可能是你矩阵大小:)

OpenCV的预期点的矢量 - 一列或双通道行矩阵。但是因为你的输入矩阵只有2点,而且通道数也是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); 

EDIT

虽然OpenCV的指定undistortPoints只接受2声道输入,实际上,它接受

  • 1列,2通道,多排垫或(和这种情况下,未记录)
  • 2列,多行,1通道垫或
  • 多列,1行,2通道垫

(如图undistort.cpp,线390)

但(或者缺乏可用的信息),当列数为2时,会错误地将第二个和第三个混合起来。因此,您的数据被视为2列2行1通道。