5.5 重映射

把一幅图像内的像素点放置到另外一幅图像内的指定位置,这个过程称为重映射, OpencV 提供了多种重映射方式,但是我们有时会希望使用自定义的方式来完成重映射。

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

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

式中

1.dst 代表目标图像,它和 src 具有相同的大小和类型
2.src 代表原始图像
3.map1参数有两种可能的值
表示(x,y)点的一个映射
表示 CV_16SC2,CV_32FC1,CV_32FC2 类型(x,y)点的x值
4.map2 参数同样有两种可能的值
当 map1 表示(x,y)时,该值为空。
当 map1 表示(x,y)点的x 值时,该值是 CV_16UC,CV_32FCl 类型(x,y)点的y值
5.Interpolation 代表插值方式,这里不支持 INTER AREA 方法。具体值参见表 5-1
6.borderMode 代表边界模式。当该值为 BORDER_TRANSPARENT时,表示目标图像内的对应源图像内奇异点( outliers)的像素不会被修改
7.borderValue 代表边界值,该值默认为0

5.5.1 映射参数的理解

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

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

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

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

【例 5.9】设计程序,使用 cv2.remap() 完成数组映射,将目标数组内的所有像素点都映射为原始图像内第0 行第3 列上的像素点,以此来了解函数cv2.remap() 内参数 map1 和 map2的使用情况

根据题目要求,可以确定:
1.用来指定列的参数 map1(mapx)内的值均为3
2.用来指定行的参数 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.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=
[[169 22 254 176 9]
[110 17 182 226 60]
[203 23 89 151 22]
[217 177 250 83 181]]
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=
[[169 22 254 176 9]
[110 17 182 226 60]
[203 23 89 151 22]
[217 177 250 83 181]]

目标图像(数组)dst内的所有值都源于原始图像中的第0行第1列上的像素值252

5.5.2 复制

为了更好地了解重映射函数 cv2.remap()的使用方法,本节介绍如何通过该函数实现图像的复制。在映射时,将参数进行如下处理
1.将 map1 的值设定为对应位置上的x 轴坐标值
2.将 map2 的值设定为对应位置上的y 轴坐标值
通过上述处理后,可以让函数 cv2.remap() 实现图像复制。下面通过一个例题来观察实现复制时,如何设置函数 cv2.remap() 内的 map1和 map2 参数的值

【例 5.10】 设计程序,使用函数 cv2.remap() 完成数组复制,了解函数 cv2.remap()内参数 map1和 map2 的使用情况

这里为了方便理解,将参数 mapl 定义为 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=
[[135 11 66 161 231]
[127 136 119 149 61]
[ 46 119 93 56 224]
[201 2 143 245 155]]
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=
[[135 11 66 161 231]
[127 136 119 149 61]
[ 46 119 93 56 224]
[201 2 143 245 155]]

通过本例可以观察到,参数 mapx 和参数 mapy 分别设置了x 轴方向的坐标和y 轴方向的坐标,函数 cv2.remap() 利用参数 mapx,mapy 所组成的数组构造的映射关系实现了图像的复制

例如,rst 中的像素点 [3,4] 在 src内的x、y 轴坐标如下:
1.x 轴坐标取决于 mapx中 mapx[3,4] 的值,为4
2.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] 的值为 240,所以目标对象src[3,4]的值为 240。

【例 5.11】设计程序,使用函数cv2.remap() 完成图像复制

根据题目要求,设计程序如下:
import cv2
import numpy as np
img=cv2.imread("C:\\Users\\Administrator\\Desktop\\opencv\\lena.bmp")
print(img)
print(img.shape)
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),i)
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow("original",img)
cv2.imshow("result",rst)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果:


1562166526(1).png

5.5.3 绕x轴翻转

如果想让图像绕着x轴翻转,意味着在映射过程中

x坐标轴的值保持不变
y坐标轴的值以x轴为对称轴进行转换

反应在map1和map2上

map1的值保持不变

map2的值调整为“总行数-1-当前行号”

需要注意,OpenCV中行号的下标是从0开始的,所以在对称关系中存在,“当前行号+对称行号 =总行号-1”的关系
据此,在绕着x轴翻转时,map2中当前行号调整为“总行数 -1 - 当前行号”

【例 5.12】设计程序,使用函数cv2.remap() 实现数组绕x轴翻转

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),rows-1-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=
[[ 12 167 214 239 159]
[175 94 41 75 187]
[109 172 44 160 18]
[109 236 15 172 85]]
mapx=
[[0. 1. 2. 3. 4.]
[0. 1. 2. 3. 4.]
[0. 1. 2. 3. 4.]
[0. 1. 2. 3. 4.]]
mapy=
[[3. 3. 3. 3. 3.]
[2. 2. 2. 2. 2.]
[1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0.]]
rst=
[[109 236 15 172 85]
[109 172 44 160 18]
[175 94 41 75 187]
[ 12 167 214 239 159]]

【例 5.13】设计程序,使用函数cv2.remap() 实现数组绕x轴翻转


import cv2
import numpy as np
img=cv2.imread("C:\\Users\\Administrator\\Desktop\\opencv\\lena.bmp")
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()

1562242941(1).png

5.5.4 绕y轴翻转

如果想让图像绕着y轴翻转,意味着在映射过程中

y坐标轴的值保持不变
x坐标轴的值以y轴为对称轴进行转换

反应在map1和map2上

map2的值保持不变

map1的值调整为“总行数-1-当前列号”

需要注意,OpenCV中行号的下标是从0开始的,所以在对称关系中存在,“当前行号+对称行号 =总行号-1”的关系
据此,在绕着y轴翻转时,map1中当前行号调整为“总行数 -1 - 当前行号”

【例 5.14】设计程序,使用函数cv2.remap() 实现数组绕y轴翻转


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),cols-1-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=
[[ 96 71 88 28 67]
[149 232 162 238 93]
[177 98 170 196 136]
[140 13 15 161 67]]
mapx=
[[4. 3. 2. 1. 0.]
[4. 3. 2. 1. 0.]
[4. 3. 2. 1. 0.]
[4. 3. 2. 1. 0.]]
mapy=
[[0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1.]
[2. 2. 2. 2. 2.]
[3. 3. 3. 3. 3.]]
rst=
[[ 67 28 88 71 96]
[ 93 238 162 232 149]
[136 196 170 98 177]
[ 67 161 15 13 140]]

【例 5.15】设计程序,使用函数cv2.remap() 实现数组绕y轴翻转


import cv2
import numpy as np
img=cv2.imread("C:\\Users\\Administrator\\Desktop\\opencv\\lena.bmp")
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),cols-1-j)
            mapy.itemset((i,j),i)
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow("original",img)
cv2.imshow("result",rst)
cv2.waitKey()
cv2.destroyAllWindows()


1562243462(1).png

5.5.5 绕x轴,y轴翻转

如果想让图像绕着x轴,y轴翻转,意味着在映射过程中

x坐标轴的值以y轴为对称轴进行转换
y坐标轴的值以x轴为对称轴进行转换

反应在map1和map2上

map1的值调整为“总列数-1-当前行号”
map2的值调整为“总行数-1-当前行号”

【例 5.16】设计程序,使用函数cv2.remap() 实现数组绕x轴,y轴翻转

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),cols-1-j)
           mapy.itemset((i,j),rows-1-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=
[[ 51 203 91 185 144]
[160 229 186 60 120]
[ 30 217 151 188 106]
[246 64 175 176 133]]
mapx=
[[4. 3. 2. 1. 0.]
[4. 3. 2. 1. 0.]
[4. 3. 2. 1. 0.]
[4. 3. 2. 1. 0.]]
mapy=
[[3. 3. 3. 3. 3.]
[2. 2. 2. 2. 2.]
[1. 1. 1. 1. 1.]
[0. 0. 0. 0. 0.]]
rst=
[[133 176 175 64 246]
[106 188 151 217 30]
[120 60 186 229 160]
[144 185 91 203 51]]

【例 5.17】设计程序,使用函数cv2.remap() 实现数组绕x轴,y轴翻转


import cv2
import numpy as np
img=cv2.imread("C:\\Users\\Administrator\\Desktop\\opencv\\lena.bmp")
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),cols-1-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()


1562244031(1).png

5.5.6 x轴,y轴互换

如果想让图像的x 轴、y 轴互换,意味着在映射过程中,对于任意一点,都需要将其x轴、y 轴坐标互换

反映在 mapx和 mapy上

mapx 的值调整为所在行的行号
mapy 的值调整为所在列的列号。

需要注意的是,如果行数和列数不一致,上述运算可能存在值无法映射的情况。默认情况
下,无法完成映射的值会被处理为0

【例 5.18】设计程序,使用函数cv2.remap() 实现数组的x 轴、y 轴互换

根据题目要求,设计程序如下


import cv2
import numpy as np
img=np.random.randint(0,256,size=[4,6],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),i)
           mapy.itemset((i,j),j)
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=
[[164 88 104 97 24 96]
[163 40 87 24 62 155]
[174 188 141 213 48 120]
[225 255 1 132 102 115]]
mapx=
[[0. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1.]
[2. 2. 2. 2. 2. 2.]
[3. 3. 3. 3. 3. 3.]]
mapy=
[[0. 1. 2. 3. 4. 5.]
[0. 1. 2. 3. 4. 5.]
[0. 1. 2. 3. 4. 5.]
[0. 1. 2. 3. 4. 5.]]
rst=
[[164 163 174 225 0 0]
[ 88 40 188 255 0 0]
[104 87 141 1 0 0]
[ 97 24 213 132 0 0]]

在本例中,行数和列数不一致,运算中存在值无法映射的情况。通过程序运行结果可知,完成映射的值都被处理为0了

【例 5.19】设计程序,使用函数cv2.remap() 实现图像的x 轴、y 轴互换

根据题目要求,设计程序如下

import cv2
import numpy as np
img=cv2.imread("C:\\Users\\Administrator\\Desktop\\opencv\\lena.bmp")
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),i)
           mapy.itemset((i,j),j)
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow("original",img)
cv2.imshow("result",rst)
cv2.waitKey()
cv2.destroyAllWindows()


1562244666(1).png

5.5.7 图像缩放
上述介绍的映射都是直接完成的整数映射,处理起来比较方便。在处理更复杂的问题时就需要对行、列值进行比较复杂的运算来实现。

【例 5.20】设计程序,使用函数 cv2.remap()缩小图像

缩小图像后,可以将图像固定在围绕其中心的某个区域。例如,将其x 轴、y 轴设置为

在目标图像的x轴(025·x 轴长度,0.75·x 轴长度)区间内生成缩小图像:x 轴其余区城的点取样自x 轴上任意一点的值。
在目标图像的y轴(025·y 轴长度,0.75·y 轴长度)区间内生成缩小图像:y 轴其余区城的点取样自y 轴上任意一点的值。

为了处理方便,我们让不在上述区域的点都取(0,0)坐标点的值。

根据题目要求,设计程序如下

import cv2
import numpy as np
img=cv2.imread("C:\\Users\\Administrator\\Desktop\\opencv\\lena.bmp")
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):
       if 0.25*cols< i <0.75*cols and 0.25*rows< j <0.75*rows:
               mapx.itemset((i,j),2*( j - cols*0.25 ) + 0.5)
               mapy.itemset((i,j),2*( i - rows*0.25 ) + 0.5)
       else:     
               mapx.itemset((i,j),0)
               mapy.itemset((i,j),0)
rst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow("original",img)
cv2.imshow("result",rst)
cv2.waitKey()
cv2.destroyAllWindows()

1562245396(1).png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容