OpenCV 实现重新映射(53)

返回:OpenCV系列文章目录(持续更新中......)

上一篇:OpenCV 实现霍夫圆变换(52)
下一篇 :OpenCV实现仿射变换(54)

目标

在本教程中,您将学习如何:

一个。使用 OpenCV 函数 cv::remap 实现简单的重新映射例程。

理论

什么是重映射?

  • 它是从图像中的一个位置获取像素并将它们定位在新图像中的另一个位置的过程。

  • 为了完成映射过程,可能需要对非整数像素位置进行一些插值,因为源图像和目标图像之间并不总是存在一对一的像素对应关系。

  • 我们可以表示每个像素位置的重新映射(x,y)如:

    哪里g()是重新映射的图像,f()源图像和ℎ(x,y)是操作的映射函数(x,y).

  • 让我们举个简单的例子。想象一下,我们有一个图像我而且,比如说,我们想做一个重新映射,以便:

    会发生什么?很容易看出,图像会在x方向。例如,考虑输入图像:

观察红色圆圈相对于 x 如何改变位置(考虑到x水平方向):

  • 在 OpenCV 中,函数 cv::remap 提供了一个简单的重新映射实现。

C++代码

  • 这个程序是做什么的?

    • 加载图像
    • 每秒将 4 个不同的重新映射过程中的 1 个应用于图像,并在窗口中无限期地显示它们。
    • 等待用户退出程序
    • 教程代码如下所示。您也可以从这里下载
    cpp 复制代码
     
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include "opencv2/imgproc.hpp"
    #include <iostream>
     
    using namespace cv;
     
    void update_map( int &ind, Mat &map_x, Mat &map_y );
     
    int main(int argc, const char** argv)
    {
     CommandLineParser parser(argc, argv, "{@image |chicky_512.png|input image name}");
     std::string filename = parser.get<std::string>(0);
     Mat src = imread( samples::findFile( filename ), IMREAD_COLOR );
     if (src.empty())
     {
     std::cout << "Cannot read image: " << filename << std::endl;
     return -1;
     }
     
     Mat dst(src.size(), src.type());
     Mat map_x(src.size(), CV_32FC1);
     Mat map_y(src.size(), CV_32FC1);
     
     const char* remap_window = "Remap demo";
     namedWindow( remap_window, WINDOW_AUTOSIZE );
     
     int ind = 0;
     for(;;)
     {
     update_map(ind, map_x, map_y);
     remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0) );
     
     imshow( remap_window, dst );
     
     char c = (char)waitKey( 1000 );
     if( c == 27 )
     {
     break;
     }
     }
     return 0;
    }
     
    void update_map( int &ind, Mat &map_x, Mat &map_y )
    {
     for( int i = 0; i < map_x.rows; i++ )
     {
     for( int j = 0; j < map_x.cols; j++ )
     {
     switch( ind )
     {
     case 0:
     if( j > map_x.cols*0.25 && j < map_x.cols*0.75 && i > map_x.rows*0.25 && i < map_x.rows*0.75 )
     {
     map_x.at<float>(i, j) = 2*( j - map_x.cols*0.25f ) + 0.5f;
     map_y.at<float>(i, j) = 2*( i - map_x.rows*0.25f ) + 0.5f;
     }
     else
     {
     map_x.at<float>(i, j) = 0;
     map_y.at<float>(i, j) = 0;
     }
     break;
     case 1:
     map_x.at<float>(i, j) = (float)j;
     map_y.at<float>(i, j) = (float)(map_x.rows - i);
     break;
     case 2:
     map_x.at<float>(i, j) = (float)(map_x.cols - j);
     map_y.at<float>(i, j) = (float)i;
     break;
     case 3:
     map_x.at<float>(i, j) = (float)(map_x.cols - j);
     map_y.at<float>(i, j) = (float)(map_x.rows - i);
     break;
     default:
     break;
     } // end of switch
     }
     }
     ind = (ind+1) % 4;
    }

解释

  • 加载图像

    cpp 复制代码
     
     Mat src = imread( samples::findFile( filename ), IMREAD_COLOR );
     if (src.empty())
     {
     std::cout << "Cannot read image: " << filename << std::endl;
     return -1;
     }
  • 创建目标映像和两个映射矩阵(对于 x 和 y )

    cpp 复制代码
    Mat dst(src.size(), src.type());
     Mat map_x(src.size(), CV_32FC1);
     Mat map_y(src.size(), CV_32FC1);
  • 创建一个窗口以显示结果

    cpp 复制代码
     const char* remap_window = "Remap demo";
     namedWindow( remap_window, WINDOW_AUTOSIZE );
  • 建立循环。每隔 1000 毫秒,我们就会更新映射矩阵(mat_xmat_y),并将它们应用于我们的源图像:

    cpp 复制代码
     int ind = 0;
     for(;;)
     {
     update_map(ind, map_x, map_y);
     remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0) );
     
     imshow( remap_window, dst );
     
     char c = (char)waitKey( 1000 );
     if( c == 27 )
     {
     break;
     }
     }
cpp 复制代码
void update_map( int &ind, Mat &map_x, Mat &map_y )
{
 for( int i = 0; i < map_x.rows; i++ )
 {
 for( int j = 0; j < map_x.cols; j++ )
 {
 switch( ind )
 {
 case 0:
 if( j > map_x.cols*0.25 && j < map_x.cols*0.75 && i > map_x.rows*0.25 && i < map_x.rows*0.75 )
 {
 map_x.at<float>(i, j) = 2*( j - map_x.cols*0.25f ) + 0.5f;
 map_y.at<float>(i, j) = 2*( i - map_x.rows*0.25f ) + 0.5f;
 }
 else
 {
 map_x.at<float>(i, j) = 0;
 map_y.at<float>(i, j) = 0;
 }
 break;
 case 1:
 map_x.at<float>(i, j) = (float)j;
 map_y.at<float>(i, j) = (float)(map_x.rows - i);
 break;
 case 2:
 map_x.at<float>(i, j) = (float)(map_x.cols - j);
 map_y.at<float>(i, j) = (float)i;
 break;
 case 3:
 map_x.at<float>(i, j) = (float)(map_x.cols - j);
 map_y.at<float>(i, j) = (float)(map_x.rows - i);
 break;
 default:
 break;
 } // end of switch
 }
 }
 ind = (ind+1) % 4;
}

结果

  1. 编译上面的代码后,您可以执行它,并给出一个图像路径作为参数。例如,使用下图:
  1. 这是将其减小到一半大小并居中的结果:
  1. 把它颠倒过来:
  1. 在 x 方向上反映它
  1. 在两个方向上反映它:

参考文献:

1、《Remapping》------Ana Huamán

相关推荐
小菜AI科技4 分钟前
Windsurf 评测:这款 人工智能 IDE 是你需要的颠覆性工具吗?
人工智能
RaymondZhao347 分钟前
【全面推导】策略梯度算法:公式、偏差方差与进化
人工智能·深度学习·算法·机器学习·chatgpt
yzx99101331 分钟前
小程序开发APP
开发语言·人工智能·python·yolo
AKAMAI1 小时前
通过自动化本地计算磁盘与块存储卷加密保护数据安全
人工智能·云计算
飞翔的佩奇1 小时前
【完整源码+数据集+部署教程】二维码与查找模式检测系统源码和数据集:改进yolo11-CSwinTransformer
python·yolo·计算机视觉·数据集·yolo11·二维码与查找模式检测
啊阿狸不会拉杆1 小时前
《算法导论》第 32 章 - 字符串匹配
开发语言·c++·算法
无规则ai1 小时前
动手学深度学习(pytorch版):第四章节—多层感知机(5)权重衰减
人工智能·pytorch·python·深度学习
小学生的信奥之路1 小时前
洛谷P3817题解:贪心算法解决糖果分配问题
c++·算法·贪心算法
zskj_zhyl2 小时前
家庭健康能量站:微高压氧舱结合艾灸机器人,智享双重养生SPA
人工智能·科技·安全·机器人
朗迪锋2 小时前
数字孪生 :提高制造生产力的智能方法
大数据·人工智能·制造