【问题标题】:How to undistort points in camera shot coordinates and obtain corresponding undistorted image coordinates?如何对相机拍摄坐标中的点进行不失真处理,得到对应的不失真图像坐标?
【发布时间】:2011-12-14 05:43:40
【问题描述】:

在相机校准后,我使用 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 );

我收到了良好的未失真图像,这意味着与单独的点相比,像素坐标没有被大幅修改。

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

【问题讨论】:

  • 你确定camera1和camera是一样的吗?
  • 是的,同样 - 我有固定的问题。谢谢你指出。此外,最初我在 EmguCV 中收到这种行为,然后试图找出这种行为是在哪里引入的:在 OpenCV 或 EmguCV 本身中。它出现在 OpenCV 中。

标签: opencv computer-vision


【解决方案1】:

这些点应该使用相机矩阵“非标准化”。

更具体地说,在调用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);

【讨论】:

    【解决方案2】:

    可能是你的矩阵大小:)

    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 通道。

    【讨论】:

    • 你说 1 个频道是什么意思?我在 cvCreateMat 中使用常量 CV_32FC2,这意味着 2 个通道。谢谢。
    • 我查看了 undistortPoints() 函数的源代码,文档有误。请查看上面的编辑以获取详细信息
    【解决方案3】:

    我也遇到了这个问题,我花了一些时间研究一下终于明白了。

    Formula 你看上面的公式,在开放系统中,扭曲操作在相机矩阵之前,所以处理顺序是:
    image_distorted ->camera_matrix -> un-distort function->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()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-11
      • 2023-01-18
      • 2018-11-16
      • 1970-01-01
      • 2014-04-18
      • 1970-01-01
      • 1970-01-01
      • 2021-08-30
      相关资源
      最近更新 更多