c++ - 如何将两个 remap() 操作合并为一个?

标签 c++ opencv

我有一个紧密的循环,我在其中获取相机图像,对其进行去畸变,然后根据某种变换(例如透视变换)对其进行变换。我已经想出为每个操作使用 cv::remap(...),这已经比使用普通矩阵操作更有效。

以我的理解,应该可以将查找映射合并为一个,并在每次循环迭代中仅调用一次重新映射。有没有规范的方法来做到这一点?我不想自己实现所有插值。

注意:该过程应该适用于不同大小的 map 。在我的特殊情况下,不失真保留了图像尺寸,而其他变换将图像缩放到不同的尺寸。

说明代码:

// input arguments
const cv::Mat_<math::flt> intrinsic  = getIntrinsic();
const cv::Mat_<math::flt> distortion = getDistortion();
const cv::Mat mNewCameraMatrix = cv::getOptimalNewCameraMatrix(intrinsic, distortion, myImageSize, 0);

// output arguments
cv::Mat undistortMapX;
cv::Mat undistortMapY;

// computes undistortion maps
cv::initUndistortRectifyMap(intrinsic, distortion, cv::Mat(),
                            newCameraMatrix, myImageSize, CV_16SC2,
                            undistortMapX, undistortMapY);

// computes undistortion maps
// ...computation of mapX and mapY omitted
cv::convertMaps(mapX, mapY, skewMapX, skewMapY, CV_16SC2);

for(;;) {
    cv::Mat originalImage = getNewImage();

    cv::Mat undistortedImage;
    cv::remap(originalImage, undistortedImage, undistortMapX, undistortMapY, cv::INTER_LINEAR);

    cv::Mat skewedImage;
    cv::remap(undistortedImage, skewedImage, skewMapX, skewMapY, cv::INTER_LINEAR);

    outputImage(skewedImage);
}

最佳答案

您可以在 undistortMapX 和 undistortMapY 上应用重映射。

cv::remap(undistortMapX, undistrtSkewX, skewMapX, skewMapY, cv::INTER_LINEAR);
cv::remap(undistortMapY, undistrtSkewY, skewMapX, skewMapY, cv::INTER_LINEAR);

你可以使用:

cv::remap(originalImage , skewedImage, undistrtSkewX, undistrtSkewY, cv::INTER_LINEAR);

之所以可行,是因为 skewMaps 和 undistortMaps 是图像中的坐标数组,所以它应该类似于获取位置的位置......

编辑(回复评论):

我想我需要做一些澄清。 remap() 函数根据旧图像的像素计算新图像中的像素。在线性插值的情况下,新图像中的每个像素都是旧图像中 4 个像素的加权平均值。根据提供的 map 中的值,权重因像素而异。如果该值或多或少是整数,则大部分权重取自单个像素。因此,新图像将与原始图像一样清晰。另一方面,如果该值远非整数(即整数 + 0.5),则权重相似。这将产生平滑效果。要了解我在说什么,请查看未失真的图像。您会看到图像的某些部分比其他部分更清晰/更平滑。

现在回到有关将两个重新映射操作合二为一时发生的情况的解释。组合图中的坐标是正确的,即 skewedImage 中的像素是从具有正确权重的 originalImage 的正确 4 个像素计算得出的。但它与两次重映射操作的结果并不相同。 undistortedImage 中的每个像素都是 originalImage 的 4 个像素的加权平均值。这意味着 skewedImage 的每个像素都是 originalImage 的 9-16 个像素的加权平均值。结论:使用单个 remap() 可能不会 得到与两次使用 remap() 相同的结果。

关于两种可能的图像(单重映射()与双重映射())中哪一种更好的讨论是相当复杂的。通常最好进行尽可能少的插值,因为每次插值都会引入不同的伪像。特别是如果图像中的伪影不均匀(某些区域变得比其他区域更平滑)。在某些情况下,这些伪像可能会对图像产生良好的视觉效果——比如减少一些抖动。但如果这是你想要的,你可以通过更便宜和更一致的方式实现这一点。例如,在重新映射之前对原始图像进行平滑处理。

关于c++ - 如何将两个 remap() 操作合并为一个?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29944709/

相关文章:

C++ OpenCV : Convert vector<vector<Point>> to vector<vector<Point2f>>

C++ 将 unique_ptr 移动到 vector 并继续使用它

c++ - 其他类体内的模板类别名会产生编译错误

c++ - 在 OpenGL 中渲染纹理 1 到 1

c++ - mkdir C++ 函数

c++ - 委托(delegate)构造函数 C++

java - XmlSerializer 可以在声明中使用双引号而不是单引号吗?

c++ - Dlib使用istream反序列化人脸形状模型

eclipse - 在 openCv 中使用 calcCovarMatrix 时出错

c++ - 确定 OpenCV 中矩阵的类型