OpenCV中的像素重映射原理及实战分析

引言

映射是个数学术语,指两个元素的集之间元素相互“对应”的关系,为名词。映射,或者射影,在数学及相关的领域经常等同于函数。 基于此,部分映射就相当于部分函数,而完全映射相当于完全函数。

说的简单点,每个人都有一个名字,都有身份证号,人对应人名字,对应自己的身份证号,这种对应关系就叫映射。

 

一、什么是像素重映射

把一个图像中一个位置的像素放置到另一个图片指定位置的过程就是像素重映射。

为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的.

简单的说就是改变图片的位置(左,右,上,下,颠倒)

for example (举个栗子):g(x, y)=f(h(x,y))。 这里g()是目标图像,f()是原图像,h(x,y)是作用于(x,y)的映射方法函数。假设有一幅图像I,满足后面条件作重映射: h(x,y)=(I.cols - x,y)这个公式是有点绕哈,有些对数学不感冒的童鞋可以看一下这个图

7ebf7ae6da174ab1b2603896f7a83982.jpeg

没错,就是轴对称,左右翻转。 这就是数学的魅力。我们一起来体验一下。

 

二、像素重映射API — remap()

下面是函数原型:

cv::remap  (   
          InputArray  src,
          OutputArray  dst,
          InputArray  map1,
          InputArray  map2,
          int    interpolation,
          int    borderMode = BORDER_CONSTANT,
          const Scalar    borderValue = Scalar()
)

函数各个参数的解释:

第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像。

第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放函数调用后的输出结果,需和源图片有一样的尺寸和类型

第三个参数,InputArray类型的map1,它有两种可能的表示对象。表示点(x,y)的第一个映射。表示CV_16SC2 , CV_32FC1 或CV_32FC2类型的X值。

第四个参数,InputArray类型的map2,同样,它也有两种可能的表示对象,而且他是根据map1来确定表示那种对象。若map1表示点(x,y)时。这个参数不代表任何值。表示CV_16UC1 , CV_32FC1类型的Y值(第二个值)。

第五个参数,int类型的interpolation,插值方式,之前的resize( )函数中有讲到,需要注意,resize( )函数中提到的INTER_AREA插值方式在这里是不支持的,所以可选的插值方式如下:INTER_NEAREST - 最近邻插值INTER_LINEAR – 双线性插值(默认值)INTER_CUBIC – 双三次样条插值(逾4×4像素邻域内的双三次插值)INTER_LANCZOS4 -Lanczos插值(逾8×8像素邻域的Lanczos插值)

第六个参数,int类型的borderMode,边界模式,有默认值BORDER_CONSTANT,表示目标图像中“离群点(outliers)”的像素值不会被此函数修改。

第七个参数,const Scalar&类型的borderValue,当有常数边界时使用的值,其有默认值Scalar( ),即默认值为0。
 

三、实战

参数函数

首先我们要先考虑,我们要做的情况有如下四种:缩小(行与列均为原来的1/2),左右翻转,上下翻转,中心旋转。下面的图表示的就是四种变换模式:

e52d377734ff489e911cf7251e4ba53a.jpeg

最简单的是翻转了,行不变,第一列跟最后一列转换,第二列跟倒数第二列转换……这样就实现了左右翻转。同理,列不变,行转换,实现上下翻转。如果上下左右都翻转,那就是旋转180°,也就是中心旋转啦。

还有一个就是图像缩小,图像缩小就是将长跟宽变换为原来的1/2。所以只在图像的1/4处到3/4处有新图像。将图像范围控制在0原图像的0.25-0.75之间,其他的全部为0;设置图像的x和y方向的映射。对于x方向,是列的映射。图像的每个像素点,减去原图像的1/4,再×2,就表示图像缩小1/2.不过,经过我自己的实践发现,图像宽,高缩小一半不能再后面+0.5,应该是列不加,行-0.25。
 

void updata_map() {for (int row = 0; row < img.rows; row++){for (int col = 0; col < img.cols; col++){switch (index){//index = 0 ,图像的行跟列为为原来的1/2。//index = 1,为左右翻转(列变换,行不变)//index = 2,为上下翻转(行变换,列不变)//index = 3,为中心旋转case 0:if (col > (img.cols*0.25) && col<(img.cols*0.75) && row>(img.rows*0.25) && row < (img.rows*0.75)) {map_x.at<float>(row, col) = 2 * (col - (img.cols*0.25));map_y.at<float>(row, col) = 2 * (row - (img.rows*0.25) - 0.25);}else{map_x.at<float>(row, col) = 0;map_y.at<float>(row, col) = 0;}break;case 1:map_x.at<float>(row, col) = (img.cols - col - 1);map_y.at<float>(row, col) = row;break;case 2:map_x.at<float>(row, col) = col;map_y.at<float>(row, col) = (img.rows - row - 1);break;case 3:map_x.at<float>(row, col) = (img.cols - col - 1);map_y.at<float>(row, col) = (img.rows - row - 1);break;default:break;}}
}

效果如下图所示:

ecb7d84752b242a18635278c4568cb24.jpeg

x和y都加上0.5

83f4b3f5f12947faaccc9ea5f27b8b79.jpeg 

x和y都不加0.5 

2c54098148c644aa9f0c0f4f2622c1ad.jpeg 

 x不加,y-0.25

 

完整代码

#define INPUT_TITLE "input image"
#define OUTPUT_TITLE "remap image"#include<iostream>
#include<opencv2\opencv.hpp>using namespace std;
using namespace cv;Mat img, src;//img 输入图像 ; src 最终输出的图像
Mat map_x, map_y;
int index = 0;
void updata_map();int main() {img = imread("D:/测试程序/image/circle1.bmp");if (!img.data){cout << "ERROR : could not load image.";return -1;}namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);imshow(INPUT_TITLE, img);//建立映射表map_x.create(img.size(), CV_32FC1);map_y.create(img.size(), CV_32FC1);int c = 0;while (true){c = waitKey(500);index = c % 4;if ((char)c == 27){break;}updata_map();remap(img, src, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 255));imshow(OUTPUT_TITLE, src);}return 0;
}void updata_map() {for (int row = 0; row < img.rows; row++){for (int col = 0; col < img.cols; col++){switch (index){//index = 0 ,图像的行跟列为为原来的1/2。//index = 1,为左右翻转(列变换,行不变)//index = 2,为上下翻转(行变换,列不变)//index = 3,为中心旋转case 0:if (col > (img.cols*0.25) && col<(img.cols*0.75) && row>(img.rows*0.25) && row < (img.rows*0.75)) {map_x.at<float>(row, col) = 2 * (col - (img.cols*0.25));map_y.at<float>(row, col) = 2 * (row - (img.rows*0.25)-0.25);}else{map_x.at<float>(row, col) = 0;map_y.at<float>(row, col) = 0;}break;case 1:map_x.at<float>(row, col) = (img.cols - col - 1);map_y.at<float>(row, col) = row;break;case 2:map_x.at<float>(row, col) = col;map_y.at<float>(row, col) = (img.rows - row - 1);break;case 3:map_x.at<float>(row, col) = (img.cols - col - 1);map_y.at<float>(row, col) = (img.rows - row - 1);break;default:break;}}}
}

 效果图

b65783ef2f644e729f04ce58acfede70.jpeg

a474b1884bba48cab6b4693a5049a00d.jpeg

4ed94ad2f3b449f7952ac420185123d0.jpeg

ea5589bfb59b434f982544e01950cd6f.jpeg

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/194520.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2.FastRunner定时任务Celery+RabbitMQ

注意&#xff1a;celery版本和Python冲突问题 不能用高版本Python 用3.5以下&#xff0c;因为项目的celery用的django-celery 3.2.2 python3.7 async关键字 冲突版本 celery3.x方案一&#xff1a; celery3.xpython3.6方案二 &#xff1a; celery4.xpython3.7 解决celery执…

海康Visionmaster-环境配置:VB.Net 二次开发环境配 置方法

Visual Basic 进行 VM 二次开发的环境配置分为三步。 第一步&#xff0c;使用 VS 新建一个框架为.NET Framework 4.6.1&#xff0c;平台去勾选首选 32 为的工程&#xff0c;重新生成解决方案&#xff0c;保证工程 Debug 下存在 exe 文件&#xff0c;最后关闭新建工程&#xff1…

2024有哪些免费的mac苹果电脑内存清理工具?

在我们日常使用苹果电脑的过程中&#xff0c;随着时间的推移&#xff0c;可能会发现设备的速度变慢了&#xff0c;甚至出现卡顿的现象。其中一个常见的原因就是程序占用内存过多&#xff0c;导致系统无法高效地运行。那么&#xff0c;苹果电脑内存怎么清理呢&#xff1f;本文将…

Linux动静态库

文章目录 1. 静态库2. 动态库3. 动态库的加载 本章代码gitee仓库&#xff1a;动静态库 1. 静态库 Linux开发工具gcc/g篇&#xff0c;此篇文章讲过动静态库的基本概念&#xff0c;不了解的可以先看一下这篇文章。 现在我们先来制作一个简单的静态库 mymath.h #pragma once#i…

Jmeter- Beanshell语法和常用内置对象(网络整理)

在利用jmeter进行接口测试或者性能测试的时候&#xff0c;我们需要处理一些复杂的请求&#xff0c;此时就需要利用beanshell脚本了&#xff0c;BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法&#xff0c;所以它和java是可以无缝衔接的。beans…

<MySQL> 什么是数据库索引?数据库索引的底层结构是什么?

目录 一、什么是数据库索引? 1.1 索引的概念 1.2 索引的特点 1.3 索引的适用场景 1.4 索引的使用 1.4.1 创建索引 1.4.2 查看索引 1.4.3 删除索引 二、数据库索引的底层结构是什么&#xff1f; 2.1 数据库中的 B树 长啥样&#xff1f; 2.2 B树为什么适合做数据库索…

B树与B+树

B树 B树&#xff0c;又称多路平衡查找树&#xff0c;B树中所有结点的孩子个数的最大值称为B树的阶&#xff0c;通常用m表示。一颗m阶B树或为空树&#xff0c;或为满足如下特征的m叉树。 树中每个结点至多有m棵子树&#xff0c;即至多含有m-1个关键字若根结点不是终端结点&…

从0到0.01入门 Webpack| 002.精选 Webpack面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

力扣刷题篇之数与位3

系列文章目录 目录 系列文章目录 前言 数学问题 总结 前言 本系列是个人力扣刷题汇总&#xff0c;本文是数与位。刷题顺序按照[力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 - 力扣&#xff08;LeetCode&#xff09; 数学问题 204. 计数质数 - 力扣&#xff08;Le…

【开源】基于JAVA的大学兼职教师管理系统

项目编号&#xff1a; S 004 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S004&#xff0c;文末获取源码。} 项目编号&#xff1a;S004&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容三、界面展示3.1 登录注册3.2 学生教师管…

APIcloud 【现已更名 用友开发中心】 iOS发版 应用程序请求用户同意访问相机和照片,但没有在目的字符串中充分说明相机和照片的使用。

iOS 审核时 提示 首次安装软件 获取相机 相册 提示信息 怎么修改 我们注意到你的应用程序请求用户同意访问相机和照片&#xff0c;但没有在目的字符串中充分说明相机和照片的使用。 为了解决这个问题&#xff0c;修改应用信息中的目的字符串是合适的。相机和照片的Plist文件&a…

Skywalking流程分析_9(JDK类库中增强流程)

前言 之前的文章详细介绍了关于非JDK类库的静态方法、构造方法、实例方法的增强拦截流程&#xff0c;本文会详细分析JDK类库中的类是如何被增强拦截的 回到最开始的SkyWalkingAgent#premain try {/** 里面有个重点逻辑 把一些类注入到Boostrap类加载器中 为了解决Bootstrap类…

python科研绘图:P-P图与Q-Q图

目录 什么是P-P图与Q-Q图 分位数 百分位数 Q-Q图步骤与原理 Shapiro-Wilk检验 绘制Q-Q图 绘制P-P图 什么是P-P图与Q-Q图 P-P图和Q-Q图都是用于检验样本的概率分布是否服从某种理论分布。 P-P图的原理是检验实际累积概率分布与理论累积概率分布是否吻合。若吻合&#xf…

SpringBoot整合Quartz示例

数据表 加不加无所谓,如果需要重启服务器后重新执行所有JOB就把sql加上 如果不加表 将application.properties中的quartz数据库配置去掉 自己执行自己的逻辑来就好,大不了每次启动之后重新加载自己的逻辑 链接&#xff1a;https://pan.baidu.com/s/1KqOPYMfI4eHcEMxt5Bmt…

2023年05月 Python(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 明明每天坚持背英语单词,他建立了英语单词错题本文件“mistakes.txt”,将每天记错的单词增加到该文件中,下列打开文件的语句最合适的是?( ) A: f = open(“mistakes.txt”) B: …

yolov5模型代码怎么修改

yaml配置文件 深度乘积因子 宽度乘积因子 所有版本只有这两个参数的不同&#xff0c;s m l x逐渐加宽加深 各种类型层参数对照 backbone里的各层&#xff0c;在这里解析&#xff0c;只需要改.yaml里的各层参数就能控制网络结构 修改网络结构 第一步&#xff1a;把新加的模块…

家庭网络中的组网方式

家庭网络中&#xff0c;目前也衍生出了比较多的组网方式&#xff0c;也不是只有Easymesh&#xff0c;我们还是要辩证的去看&#xff0c;没有绝对的好和坏&#xff0c;需求不同&#xff0c;取舍不同。 这里博主简单的介绍几种组网方式&#xff0c;上图也比较直观 1.wds wds是…

Windows系统中搭建docker (ubuntu,Docker-desktop)

一、docker安装前的准备工作 1. 开启CPU虚拟化&#xff0c;新电脑该默认是开启的&#xff0c;如果没开启可以根据自己电脑型号品牌搜索如克开启CPU虚拟化。当开启成功后可在设备管理器中看到。 2.开通Hyper-V 通过 Windows 控制面板 --> 程序和功能 -->启用或关闭…

Windows 11 设置 wsl-ubuntu 使用桥接网络

Windows 11 设置 wsl-ubuntu 使用桥接网络 0. 背景1. Windows 11 下启用 Hyper-V2. 使用 Hyper-V 虚拟交换机管理器创建虚拟网络3. 创建 .wslconfig 文件4. 配置 wsl.conf 文件5. 配置 wsl-network.conf 文件6. 创建 00-wsl2.yaml7. 安装 net-tools 和 openssh-server 0. 背景 …

Day48 力扣动态规划 : 647. 回文子串 |516.最长回文子序列 |动态规划总结篇

Day48 力扣动态规划 : 647. 回文子串 &#xff5c;516.最长回文子序列 &#xff5c;动态规划总结篇 647. 回文子串第一印象看完题解的思路dp递推公式初始化递归顺序 实现中的困难感悟代码 516.最长回文子序列第一印象我的尝试遇到的问题 看完题解的思路dp递推公式初始化 实现中…