OpenCV 中用于不失真图像的重映射功能如何工作?

How does the remap function in OpenCV for undistorting images work?

出于调试目的,我尝试重新实现 OpenCV 的重映射功能。不考虑插值,它应该看起来像这样:

for( int j = 0; j < height; j++ )
{
    for( int i = 0; i < width; i++ )
    {
        undistortedImage.at<double>(mapy.at<float>(j,i),mapx.at<float>(j,i)) = distortedImage.at<double>(j,i);
    }
}

为了对此进行测试,我使用以下贴图围绕 y 轴镜像图像:

int width = distortedImage.cols;
int height = distortedImage.rows;
cv::Mat mapx = Mat(height, width, CV_32FC1);
cv::Mat mapy = Mat(height, width, CV_32FC1);
for( int j = 0; j < height; j++)
{
    for( int i = 0; i < width; i++)
    {
        mapx.at<float>(j,i) = width - i - 1;
        mapy.at<float>(j,i) = j;
    }
}

但插值的工作原理与

完全一样
cv::remap( distortedImage, undistortedImage, mapx, mapy, CV_INTER_LINEAR);

现在我尝试将此功能应用到 OCamCalib Toolbox 创建的地图上以消除图像失真。这与 OpenCV 去失真所做的基本相同。 我现在的实现显然没有考虑将源图像中的几个像素映射到目标图像中的相同像素。但情况更糟。实际上,看起来我的源图像在目标图像中以较小的版本出现了三次。否则重映射命令可以完美运行。

经过详尽的调试,我决定向你们寻求帮助。谁能解释我做错了什么或提供 link 来实现 OpenCV 中的重映射?

我自己想出来了。我最初的实现有两个根本性错误:

  1. 对地图使用方式的误解。
  2. 关于如何提取强度值的误解。

正确的做法:

for( int j = 0; j < height; j++ )
{
    for( int i = 0; i < width; i++ )
    {
        undistortedImage.at<uchar>(mapy.at<float>(j,i),mapx.at<float>(j,i)) = distortedImage.at<uchar>(j,i);
    }
}

我想强调的是,现在使用 .at 而不是 .at 提取图像的强度值。此外,地图的索引已切换。