opencv-25 图像几何变换04- 重映射-函数 cv2.remap()

news2024/11/28 8:29:01

什么是重映射?

重映射(Remapping)是图像处理中的一种操作,用于将图像中的像素从一个位置映射到另一个位置。重映射可以实现图像的平移、旋转、缩放和透视变换等效果。它是一种基于像素级的图像变换技术,可以通过定义映射关系来改变图像的几何形状和外观。

在重映射中,我们需要定义一个映射表(Map),这个映射表指定了源图像中每个像素点在目标图像中的位置。对于每个像素点 (x, y),映射表告诉我们在目标图像中的新位置 (x’, y’)。通过对所有像素点进行映射,我们就可以得到经过重映射变换后的新图像。

在OpenCV中,可以使用 cv2.remap() 函数来执行重映射操作。cv2.remap() 接受输入图像和一个表示映射关系的两个浮点型数组(map_x 和 map_y)。数组 map_x 和 map_y 的大小必须与输入图像的大小相同,并且每个元素 (x, y) 表示源图像中的像素点 (x, y) 在目标图像中的新位置 (x’, y’)。

重映射应用场景?

重映射在图像处理和计算机视觉领域有许多应用场景。以下是一些常见的重映射应用场景:

图像畸变校正:相机镜头引起的畸变(如透视畸变、鱼眼畸变等)会导致图像中的直线弯曲或形状失真。通过重映射技术,可以校正这些畸变,使图像看起来更加自然和真实。

图像配准:在多幅图像中找到对应点,并将它们对齐,使得它们在相同视角或坐标系下表现一致。这在图像拼接、全景图像合成和多视角图像处理中非常有用。

图像稳定:在视频处理中,当相机存在抖动或运动时,可以使用重映射技术来稳定视频,保持图像内容相对稳定,减少抖动效应。

视角变换:通过重映射,可以改变图像的视角,实现缩放、旋转、平移和透视等效果,从而得到不同角度或大小的图像。

增强现实 (AR) 应用:在AR应用中,通过对现实世界图像进行重映射,将虚拟物体或信息叠加到真实世界中,实现真实与虚拟的交互效果。

图像处理与滤波:重映射技术可以应用于图像处理中的滤波、图像增强和特效处理,从而实现各种图像变换和处理效果。

视频流处理:在实时视频流处理中,可以使用重映射技术对图像进行实时变换和校正,以满足特定的需求。

这些只是重映射在图像处理和计算机视觉中的一些常见应用场景。实际上,重映射技术非常灵活和强大,可以在许多不同的领域中发挥重要作用,帮助我们处理和改善图像数据。

映射参数的理解

OpenCV 内的重映射函数 cv2.remap()提供了更方便、更自由的映射方式,其语法格式如下:

dst = cv2.remap( src, map1, map2, interpolation[, borderMode[, borderValue]] )

式中:
 dst 代表目标图像,它和 src 具有相同的大小和类型。
 src 代表原始图像。
 map1 参数有两种可能的值:
 表示(x,y)点的一个映射。
 表示 CV_16SC2 , CV_32FC1, CV_32FC2 类型(x,y)点的 x 值。
 map2 参数同样有两种可能的值:
 当 map1 表示(x,y)时,该值为空。
 当 map1 表示(x,y)点的 x 值时,该值是 CV_16UC1,
CV_32FC1 类型(x,y)点的 y 值。
 Interpolation 代表插值方式
 borderMode 代表边界模式。当该值为 BORDER_TRANSPARENT 时,表示目标图像内
的对应源图像内奇异点(outliers)的像素不会被修改。
 borderValue 代表边界值,该值默认为 0。

重映射通过修改像素点的位置得到一幅新图像。在构建新图像时,需要确定新图像中每个像素点在原始图像中的位置。因此,映射函数的作用是查找新图像像素在原始图像内的位置。该过程是将新图像像素映射到原始图像的过程,因此被称为反向映射。在函数 cv2.remap()中,参数 map1 和参数 map2 用来说明反向映射,map1 针对的是坐标 x,map2 针对的是坐标 y。

需要说明的是,map1 和 map2 的值都是浮点数。因此,目标图像可以映射回一个非整数的值,这意味着目标图像可以“反向映射”到原始图像中两个像素点之间的位置(当然,该位置是不存在像素值的)。这时,可以采用不同的方法实现插值,函数中的 interpolation 参数可以控制插值方式。正是由于参数 map1 和参数 map2 的值是浮点数,所以通过函数 cv2.remamp()所能实现的映射关系变得更加随意,可以通过自定义映射参数实现不同形式的映射。

需要注意的是,函数 cv2.remap()中参数 map1 指代的是像素点所在位置的列号,
参数 map2 指代的是像素点所在位置的行号。例如,我们想将目标图像(映射结果图像)中某个点 A 映射
为原始图像内处于第 0 行第 3 列上的像素点 B,那么需要将 A 点所对应的参数 map1 对应位置上的值设为 3,参数 map2 对应位置上的值设为 0。

所以,通常情况下,我们将 map1 写为 mapx,并且将 map2 写成 mapy,以方便理解。

同样,如果想将目标图像(映射结果图像)中所有像素点都映射为原始图像内处于第 0 行
第 3 列上的像素点 B,那么需要将参数 map1 内的值均设为 3,将参数 map2 内的值均设为 0。

实验:

使用 cv2.remap()完成数组映射,将目标数组内的所有像素点都映射为原始图像内第 0 行第 3 列上的像素点,以此来了解函数 cv2.remap()内参数 map1 和 map2 的使
用情况。
根据题目要求,可以确定:

 用来指定列的参数 map1(mapx)内的值均为 3。
 用来指定行的参数 map2(mapy)内的值均为 0。

import cv2
import numpy as np
img=np.random.randint(0,256,size=[4,5],dtype=np.uint8)
rows,cols=img.shape
mapx = np.ones(img.shape,np.float32)*3
mapy = np.ones(img.shape,np.float32)*0
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print("img=\n",img)
print("mapx=\n",mapx)
print("mapy=\n",mapy)
print("rst=\n",rst)

运行结果:

img=
 [[253  90  32  65 181]
 [187 184 148  12 212]
 [157 229 255 138 115]
 [156  38  62  89 241]]
mapx=
 [[3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]
 [3. 3. 3. 3. 3.]]
mapy=
 [[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]
rst=
 [[65 65 65 65 65]
 [65 65 65 65 65]
 [65 65 65 65 65]
 [65 65 65 65 65]]

通过观察上述结果可知,目标图像(数组)dst 内的所有值都来源于原始图像中第 0 行第 3
列上的像素值 65。

复制

为了更好地了解重映射函数 cv2.remap()的使用方法,本节介绍如何通过该函数实现图像的复制。在映射时,将参数进行如下处理:

 将 map1 的值设定为对应位置上的 x 轴坐标值。
 将 map2 的值设定为对应位置上的 y 轴坐标值。

通过上述处理后,可以让函数 cv2.remap()实现图像复制。下面通过一个例题来观察实现复
制时,如何设置函数 cv2.remap()内的 map1 和 map2 参数的值。

使用函数 cv2.remap()完成数组复制,了解函数 cv2.remap()内参数 map1和 map2 的使用情况。

这里为了方便理解,将参数 map1 定义为 mapx,将参数 map2 定义为 mapy。后续程序中都采用了这种定义方式,后面不再重复说明。

import cv2
import numpy as np
img=np.random.randint(0,256,size=[4,5],dtype=np.uint8)
rows,cols=img.shape
mapx = np.zeros(img.shape,np.float32)
mapy = np.zeros(img.shape,np.float32)
for i in range(rows):
 for j in range(cols):
 	mapx.itemset((i,j),j)
	mapy.itemset((i,j),i)
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
print("img=\n",img)
print("mapx=\n",mapx)
print("mapy=\n",mapy)
print("rst=\n",rst)

运行程序,出现如下结果:

img=
 [[151 137  24  88 216]
 [  8 112 205 130  44]
 [ 78 106   1 134  85]
 [190  55 135  56  64]]
mapx=
 [[0. 1. 2. 3. 4.]
 [0. 1. 2. 3. 4.]
 [0. 1. 2. 3. 4.]
 [0. 1. 2. 3. 4.]]
mapy=
 [[0. 0. 0. 0. 0.]
 [1. 1. 1. 1. 1.]
 [2. 2. 2. 2. 2.]
 [3. 3. 3. 3. 3.]]
rst=
 [[151 137  24  88 216]
 [  8 112 205 130  44]
 [ 78 106   1 134  85]
 [190  55 135  56  64]]

通过本例可以观察到,参数 mapx 和参数 mapy 分别设置了 x 轴方向的坐标和 y 轴方向的
坐标。函数 cv2.remap()利用参数 mapx、mapy 所组成的数组构造的映射关系实现了图像的复制。
例如,rst 中的像素点[3,4]在 src 内的 x、y 轴坐标如下:
 x 轴坐标取决于 mapx 中 mapx[3,4]的值,为 4。
 y 轴坐标取决于 mapy 中 mapy[3,4]的值,为 3。

这说明 rst[3,4]来源于原始图像 src 的第 4 列(x 轴方向,由 mapx[3,4]决定)、第 3 行(y
轴方向,由 mapy[3,4]决定),即 rst[3,4]=src[3,4]。原始对象 src[3,4]的值为 64,所以目标对象
rst[3,4]的值为 64。

像绕 x 轴的翻转

import cv2
import numpy as np
img=cv2.imread("lena.png")
rows,cols=img.shape[:2]
mapx = np.zeros(img.shape[:2],np.float32)
mapy = np.zeros(img.shape[:2],np.float32)
for i in range(rows):
 for j in range(cols):
    mapx.itemset((i,j),j)
    mapy.itemset((i,j),rows-1-i)
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow("original",img)
cv2.imshow("result",rst)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述
,左图是原始图像,右图是翻转结果图像

还有绕Y 翻转,绕X,Y 轴翻转,更多操作多动作试试

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为什么需要GP(Global Platform)认证?

TEE之GP(Global Platform)认证汇总 一、为什么需要认证? 二、为什么是GP? 参考: GlobalPlatform Certification - GlobalPlatform

Unity光照相关知识和实践 (烘焙光照,环境光设置,全局光照)

简介 本文将会通过一个简单的场景搭建,介绍如何使用烘焙光照以及相关的注意事项。另外还介绍了Unity内全局光照(GI)的知识和GI实际在游戏内的表现效果。 Unity关于光照相关的参考文档地址:https://docs.unity.cn/cn/current/Man…

黑客自学笔记(网络安全)

一、黑客是什么 原是指热心于计算机技术,水平高超的电脑专家,尤其是程序设计人员。但后来,黑客一词已被用于泛指那些专门利用电脑网络搞破坏或者恶作剧的家伙。 二、学习黑客技术的原因 其实,网络信息空间安全已经成为海陆空之…

使用goldengate 迁移Oracle到postgresql

环境: --源端: IP:10.0.4.16 hostname:tencent Oracle数据库版本:12.2.0.1.0 ogg for oracle版本:19.1.0.0.4 SID:orcl --目标端: IP:10.0.4.16 hostname&#…

Spring 6【p命名空间和c命名空间】(五)-全面详解(学习总结---从入门到深化)

目录 十、p命名空间和c命名空间 十、p命名空间和c命名空间 老版本的Spring框架XML配置文件是使用DTD的,但是在目前Spring框架中多使用XSD。因为在XSD扩 展支持。这也是为什么Spring框架配置文件由原来的DTD更换成XML Schema,毕竟Spring现在是模块化了&…

java 锁详解

死锁有四个条件 1. 互斥性 某个锁单元只能被某个运算单元占用 2. 不可以剥夺 线程获取某个资源, 这个资源不可以被其他资源剥夺, 只能自己释放, 3. 请求并保持 请求别的资源的同时却保持占有某个资源 4. 形成循环链路 一般锁都有互斥性, 读锁没有互斥性. 一般的锁都不…

视觉系统相关的网站

1.视觉系统设计 视觉系统设计网址:http://www.vision-systems-china.com/emag/emag.asp

宿主可以访问公网 Docker容器里无法访问 Temporary failure in name resolution

宿主可以访问公网 Docker容器里无法访问 Temporary failure in name resolution 容器参数 docker-compose.yml 的 dns我也设置,按理来说应该可以访问,然而就是不断的按在地上摩擦 web:build: .restart: alwaysports:- "6699:80"dns:- 114.11…

公司内部重要文件如何加密防止泄露?

现如今,是互联网时代,数据安全在互联网时代中的数据安全岌岌可危,企业中,都会拥有终端,终端中每天都要处理文档,文件,表格,产生一系列的数据问题等,这个时候就要先企业中…

Windows OS CMD 常用工具 の 命令合集

# First Of All 每次想要修改环境变量都要按部就班点开系统属性、高级系统设置、环境变量。这种操作实在是太繁琐了,对于我一个懒人来讲实在是 忍无可忍 。如果可以使用 WINR 或 CMD 直接打开系统内的一些工具,是不是就可以节省很多时间;是不…

自己写的程序创建开机自启

1、winr 2、输入shell:startup 3、把需要启动的程序快捷方式放在此文件夹下面即可

最详细的编译paddleOcrGPU C++版本指南(包含遇到坑的解决办法)

前言: 我是之前编译过调用CPU的paddleOcr的C版本,其实CPU版本与GPU版本并无太大不同,只不过是调用库版本的不同,然后原项目中几个相关参数改一下就可以,但是在这个过程中我找不到关于编译paddleOcrGPU C版本的详细教程…

【Docker】Consul的容器服务更新与发现

目录 一、Consul二、什么是服务注册与发现1.2什么是consul1.3consul提供的一些关键特性 二、Consul部署2.1环境配置2.2Consul服务器配置1. 建立 Consul 服务2. 查看集群信息3. 通过 http api 获取集群信息 2.3 registrator服务器配置1. 安装 Gliderlabs/Registrator2. 测试服务…

如何设置Axure中文版 Mac系统下axurerp10怎么设置成中文

有许多小伙伴肯定想知道axure rp 10怎么转换为中文版,接下来就为大家带来最详细的汉化教程,大家可以根据教程一步一步操作,保证可以汉化成功! 准备工作 安装好axurerp10 axurerp10汉化包 百度网盘链接: 百度网盘 请输入提取码 …

【C++】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值

最近想用c做一个小游戏,游戏的主要内容是利用键盘控制一个飞机躲避和击落屏幕顶部随机掉落敌方炮弹,飞机被敌方炮弹击中则减掉一条命,飞机也可以发射炮弹反击,每击落一个敌方炮弹,则有相应积分。 游戏的思路就是利用w…

Docker配置阿里云容器镜像加速

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

目录操作在C语言中:一个全面的指南

(꒪ꇴ꒪ ),hello我是祐言博客主页:C语言基础,Linux基础,软件配置领域博主🌍快上🚘,一起学习!送给读者的一句鸡汤🤔:集中起来的意志可以击穿顽石!作者水平很有限,如果发现错误&#x…

7.26 Qt

用QT制作一个登陆界面 运行代码 login.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug> //信息调试类&#xff0c;用于输出 #include <QIcon> //图标类头文件 #include <QPushButton&…

更新合集 | 七月功能上新记

点击链接了解详情 七月来临&#xff0c;正式开启 2023 下半年的新征途&#xff01;这个盛夏&#xff0c;腾讯云 CODING 上线了微信扫码注册、微信通知、Go 制品管理等重点能力&#xff0c;为企业及团队研发管理带来更多便利&#xff01;以下是 CODING 新功能速递&#xff0c;快…

一文搞定IP地址

IP编址系列文章&#xff08;上&#xff09; 目录 一&#xff0c;什么是IP地址&#xff1f; 二&#xff0c;IP地址的表示方式 问题&#xff1a;计算机能识别二进制&#xff1f;十进制&#xff1f;十六进制&#xff1f; 三&#xff0c;二进制如何转换为十进制呢&#xff1f; …