• 【OpenCV】-重映射


    1、重映射的概念

    重映射是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成重映射过程,需要获得一些插值为非整数像素的坐标,因为源图像与目标图像像素坐标不是一一对应的。如下:
    g ( x , y ) = f ( h ( x , y ) ) g(x,y)=f(h(x,y)) g(x,y)=f(h(x,y))
    g()是目标图像,f()是源图像,而h(x,y)是作用于(x,y)的映射方法函数。

    2、实现重映射:remap()函数

    remap()函数会根据指定的映射形式,将源图像进行重映射几何变换:
    d s t ( x , y ) = s r c ( m a p x ( x , y ) , m a p y ( x , y ) ) dst(x,y)=src(mapx(x,y),mapy(x,y)) dst(x,y)=src(mapx(x,y),mapy(x,y))

    void remap(InputArray src,OutputArray dst,InputArray map1,InputArray map2,int interpolation,intborderMode=BORDER_CONSTANT,const Scalar& borderValue=Scalar())
    
    • 1
    • 第一个参数:输出图像
    • 第二个参数:函数调用后的运算结果存在这里,即这个参数用于存放函数调用后的输出结果,需和源图片有一样的尺寸和类型
    • 第三个参数:InputArray类型的 map1,有两种可能的表示对象
      • 表示点(x,y)的第一映射
      • 表示CV_16SC2,CV_32FC1,CV_32FC2类型的X值
    • 第四个参数:InputArray类型的 map2,有两种可能的表示对象
      • 若map1表示点(x,y)时,这个参数不代表任何值
      • 表示CV_16UC1,CV_32FC1类型的Y值
    • 第五个参数:int 类型的interpolation,插值方式,所选的插值方式如下:
      • INTER_NEAREST——最近邻插值
      • INTER_LINEAR——双线性插值(默认值)
      • INTER_CUBIC——双三次样条插值
      • INTER_LANCZOS4——Lanczos插值
    • 第六个参数:边界模式
    • 第七个参数:const Scalar&类型的borderValue,当有常数边界使用的值,其默认值Scalar(),即默认值为0

    3、基本重映射

    说明:下面是精简后的以remap函数为核心的示例程序

    #include
    #include
    #include
    #include
    using namespace std;
    using namespace cv;
    int main()
    {
    	Mat srcImage, dstImage;
    	Mat map_x, map_y;
    	//载入原始图像
    	srcImage = imread("E:\\Pec\\car.jpg", 1);
    	imshow("【原始图】", srcImage);
    	//创建和原始图一样的效果图,x重映射图,y重映射图
    	dstImage.create(srcImage.size(), srcImage.type());
    	map_x.create(srcImage.size(), CV_32FC1);
    	map_y.create(srcImage.size(), CV_32FC1);
    	//双层循环,遍历每一个像素点,改变map_x和Map_y
    	for (int j = 0; j < srcImage.rows; j++)
    	{
    		for (int i = 0; i < srcImage.cols; i++)
    		{
                //通过at获取像素值
    			map_x.at<float>(j, i) = static_cast<float>(i);
    			map_y.at<float>(j, i) = static_cast<float>(srcImage.rows-j);
    		}
    	}
    	//进行重映射
    	remap(srcImage, dstImage, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    	imshow("【效果图】", dstImage);
    
    	waitKey(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    4、实现多重映射

    #include
    #include
    #include
    #include
    using namespace std;
    using namespace cv;
    #define WINDOW_NAME "【程序窗口】"
    Mat g_srcImage, g_dstImage;
    Mat g_map_x, g_map_y;
    int update_map(int key);
    static void ShowHelpText();
    int main()
    {
    	system("color 2F");
    	ShowHelpText();
    	//载入原始图像
    	g_srcImage = imread("E:\\Pec\\car.jpg", 1);
    	imshow("【原始图】", g_srcImage);
    	//创建和原始图一样的效果图,x重映射图,y重映射图
    	g_dstImage.create(g_srcImage.size(), g_srcImage.type());
    	g_map_x.create(g_srcImage.size(), CV_32FC1);
    	g_map_y.create(g_srcImage.size(), CV_32FC1);
    	namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
    	imshow(WINDOW_NAME, g_srcImage);
    	while (1)
    	{
    		int key = waitKey(0);
    		if ((key & 255) == 27)
    		{
    			cout << "程序退出......" << endl;
    			break;
    		}
    		update_map(key);
    		//根据按下键盘按键来更新map_x & map_y的值,然后调用remap()进行重映射
    		remap(g_srcImage, g_dstImage, g_map_x, g_map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    		imshow(WINDOW_NAME, g_dstImage);
    	}
    	return 0;
    }
    int update_map(int key)
    {
    	//双层循环,遍历每一个像素点,改变map_x和Map_y
    	for (int j = 0; j < g_srcImage.rows; j++)
    	{
    		for (int i = 0; i < g_srcImage.cols; i++)
    		{
    			switch (key)
    			{
    				case '1'://按键1按下,进行第一重映射操作
    					if (i > g_srcImage.cols*0.25&&i<g_srcImage.cols*0.75&&j>g_srcImage.rows*0.25&&j < g_srcImage.rows*0.75)
    					{
    						g_map_x.at<float>(j, i) = 2 * (i - g_srcImage.cols*0.25) + 0.5;
    						g_map_y.at<float>(j, i) = 2 * (j - g_srcImage.rows*0.25) + 0.5;
    					}
    					else
    					{
    						g_map_x.at<float>(j, i) = 0;
    						g_map_y.at<float>(j, i) = 0;
    					}
    					break;
    				case '2': //按键2按下,进行第二重映射操作
    					g_map_x.at<float>(j, i) = static_cast<float>(i);
    					g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows - j);
    					break;
    				case '3':
    					g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols-i);
    					g_map_y.at<float>(j, i) = static_cast<float>(j);
    					break;
    				case '4':
    					g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols - i);
    					g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows - j);
    					break;
    			}
    		}
    	}
    	return 1;
    }
    static void ShowHelpText()
    {
    	cout << "\n\n\n\t欢迎来到重映射示例程序\n";
    	cout << "\n\n\n\t按键操作如下:" ;
    	cout << "\n\n\n\t键盘按下【ESC】-退出程序" ;
    	cout << "\n\n\n\t键盘按下【1】-第一种映射方式,缩小2倍" ;
    	cout << "\n\n\n\t键盘按下【2】-第二种映射方式,y方向翻转" ;
    	cout << "\n\n\n\t键盘按下【3】-第三种映射方式,x方向反转" ;
    	cout << "\n\n\n\t键盘按下【4】-第四种映射方式,x,y方向反转" ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    第一种映射方式,缩小2倍

    在这里插入图片描述

    第二种映射方式,y方向翻转

    在这里插入图片描述

    第三种映射方式,x方向反转

    在这里插入图片描述

    第四种映射方式,x,y方向反转

    在这里插入图片描述

  • 相关阅读:
    【git 协同】开源项目实战
    vue-router路由守卫
    ECharts 实例2
    Linux远程管理工具
    .NET Evolve 数据库版本管理工具
    基于窗函数法的FIR数字滤波器实现matlab仿真
    【问题思考总结】共享设备和独占设备的区别,为什么共享设备不会死锁?
    文盘Rust -- 生命周期问题引发的 static hashmap 锁 | 京东云技术团队
    ceph 006 rbd高级特性 rbd快照 镜像克隆 rbd缓存 rbd增量备份 rbd镜像单向同步
    网络安全(黑客技术)—自学手册
  • 原文地址:https://blog.csdn.net/qq_44859533/article/details/126142255