把一张图像内的像素点放置到另一幅图像内指定的位置,这个操作叫做重映射。
前两节学习的仿射变换和透视变换,是通过变换矩阵来指定映射方式。
有时我们希望通过自定义的方式来指定重映射。opencv 就为我们提供了一个自定义映射的函数 cv2.remap()
函数原型:
cv2.remap(src_img, map1, map2, interpolation)
参数:
说明:
目标图像的第一个像素,取原始图像中坐标为(2,2)的像素值 7
举例:
将目标图像中所有像素点的值都取原图像中的第0行第3列上的像素点
import cv2
import numpy as np
# 随机生成原始图像,大小为[4, 5]
src_img = np.random.randint(0, 256, size=[4, 5], dtype=np.uint8)
rows, cols = src_img.shape
# 指定原始图像的第3列,第0行
map1 = np.ones((4, 5), dtype=np.float32) * 3
map2 = np.ones((4, 5), dtype=np.float32) * 0
# 插值方式可解决索引值为float的问题
dst_img = cv2.remap(src_img, map1, map2, cv2.INTER_LINEAR)
print("src_img=\n", src_img)
print("\nmap1=\n", map1)
print("\nmap2=\n", map2)
print("\ndst_img=\n", dst_img)
# 输出为:
# src_img=
# [[252 39 25 186 19]
# [209 225 13 176 133]
# [ 43 115 92 110 144]
# [ 3 176 208 8 232]]
#
# map1=
# [[3. 3. 3. 3. 3.]
# [3. 3. 3. 3. 3.]
# [3. 3. 3. 3. 3.]
# [3. 3. 3. 3. 3.]]
#
# map2=
# [[0. 0. 0. 0. 0.]
# [0. 0. 0. 0. 0.]
# [0. 0. 0. 0. 0.]
# [0. 0. 0. 0. 0.]]
#
# dst_img=
# [[186 186 186 186 186]
# [186 186 186 186 186]
# [186 186 186 186 186]
# [186 186 186 186 186]]
复制图片
import cv2
import numpy as np
src_img = np.random.randint(0, 256, (4, 5), dtype=np.uint8)
rows, cols = src_img.shape[:2]
map1 = np.zeros_like(src_img, dtype=np.float32)
map2 = np.zeros_like(src_img, dtype=np.float32)
for i in range(rows):
for j in range(cols):
map1[i, j] = j
map2[i, j] = i
dst_img = cv2.remap(src_img, map1, map2, cv2.INTER_LINEAR)
print(src_img)
# [[116 0 67 144 69]
# [237 62 3 70 232]
# [206 213 5 142 196]
# [156 14 175 252 73]]
print(dst_img)
# [[116 0 67 144 69]
# [237 62 3 70 232]
# [206 213 5 142 196]
# [156 14 175 252 73]]
说明:
1、map1, map2 的值都是浮点数,因此,目标图像可以映射回一个非整数的值,这意味着目标图像可以“反向映射”到原始图像中两个像素之间的位置(当然,该位置是不存在像素值的)。这时,可以采用不同的方法实现插值,函数中的interpolation 参数可以控制插值方式;正是由于 参数map1 和 参数map2 的值是浮点数,所以通过函数 cv2.remap() 所能实现的映射关系变得更加随意,可以通过自定义映射参数实现不同形式的映射。
2、定义 map1, map2 的时候,数据类型一定要指定为浮点数(dtype=np.float32), 否则会报错