当前位置:网站首页>【OpenCV】-重映射
【OpenCV】-重映射
2022-08-04 00:55:00 【我菜就爱学】
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())
- 第一个参数:输出图像
- 第二个参数:函数调用后的运算结果存在这里,即这个参数用于存放函数调用后的输出结果,需和源图片有一样的尺寸和类型
- 第三个参数: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<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
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);
}

4、实现多重映射
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
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方向反转" ;
}
第一种映射方式,缩小2倍

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

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

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

边栏推荐
猜你喜欢

互斥锁、读写锁、自旋锁,以及原子操作指令xaddl、cmpxchg的使用场景剖析

typescript54 - generic constraints

typescript57 - Array generic interface

如何通过单步调试的方式找到引起 Fiori Launchpad 路由错误的原因试读版

MATLAB三维绘图命令plot3入门

Salesforce's China business may see new changes, rumors may be closing

字符串变形

Nanoprobes 棕榈酰纳米金相关说明书

The problem of disorganized data output by mnn model

LeetCode第三题(Longest Substring Without Repeating Characters)三部曲之三:两次优化
随机推荐
第1章:初识数据库与MySQL----MySQL安装
求解同余方程 数论 扩展欧几里得
Talking about the future development direction of my country's industrial parks
Vant3—— 点击对应的name名称跳转到下一页对应的tab栏的name的位置
跨域问题解决方式 代理服务器
谁说程序员不懂浪漫,表白代码来啦~
Shell编程之循环语句(for、while)
fsdbDump用法
typescript52-简化泛型函数调用
BGP实验(含MPLS)
【正则表达式】笔记
数据库扩容也可以如此丝滑,MySQL千亿级数据生产环境扩容实战
GeoAO:一种快速的环境光遮蔽方案
Justin Sun: Web3.0 and the Metaverse will assist mankind to enter the online world more comprehensively
《Greenplum构建实时数据仓库实践》简介
typescript51 - basic use of generics
Linux安装mysql最简单教程(一次成功)
typescript53-泛型约束
corn表达式 具体详解与案例
Analysis: What makes the Nomad Bridge hack unique