什么是重映射
把一副图像内的像素点放置到另一幅图像内的指定位置,这个过程我们称为重映射。简单点理解,也就是copy一个图像到另一个图像中。
在OpenCV中,它给我们提供了cv2.remap()函数作为重映射,其定义如下:
def remap(src, map1, map2, interpolation, dst=None, borderMode=None, borderValue=None):
src:代表原始图像
map1:可以表示(x,y)点的一个映射,也可以表示CV_16SC2、CV_32FC1、CV_32FC2类型(x,y)点的x值
map2:当前map1表示(x,y)点的一个映射时,该值为空。当map1表示CV_16SC2、CV_32FC1、CV_32FC2类型(x,y)点的x值时,该值时CV_16UC1、CV_32FC1类型(x,y)点的y值。
interpolation,borderMode,borderValue与前文类似。
需要注意,map1指代的是像素点所在位置的列号,map2指代的是像素点所在位置的行号。
copy像素点
现在我们假设有一个需求,将目标图像内的所有像素点都映射为原始图像内的第100行,200列上的像素点。具体实现如下:
import cv2 import numpy as np img = cv2.imread("4.jpg") rows, cols, ch = img.shape mapx = np.ones(img.shape[:2], np.float32) * 200 mapy = np.ones(img.shape[:2], np.float32) * 100 result_img = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR) cv2.imshow("img", img) cv2.imshow("result_img", result_img) cv2.waitKey() cv2.destroyAllWindows()
如上面代码所示,我们将所有像素点都设置为原始图像(100,200)点的像素点,会得到一个非常纯色的图像,效果如下所示:
copy整个图像
那么既然能copy某个像素点,那么也肯定能copy整个图像。下面,我们将上图左边的图像全部copy到右边,具体代码如下:
import cv2 import numpy as np img = cv2.imread("4.jpg") rows, cols, ch = img.shape mapx = np.ones(img.shape[:2], np.float32) mapy = np.ones(img.shape[:2], np.float32) for i in range(rows): for j in range(cols): mapx.itemset((i,j),j)#设置每个点映射原图的Y坐标 mapy.itemset((i,j),i)#设置每个点映射原图的X坐标 result_img = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR) cv2.imshow("img", img) cv2.imshow("result_img", result_img) cv2.waitKey() cv2.destroyAllWindows()
这里,我们将所有点映射到所有点,每个像素点一一对应,就完成了copy原图像。运行之后,效果如下所示:
绕X轴翻转
通过cv2.remap()函数,我们不仅可以重映射像素点,还可以翻转过来映射,也就是通过它实现X轴的翻转效果,只要保证X轴不变,并且Y坐标值以X轴为对称进行交换即可。
修改上面代码中的某一行,代码如下:
import cv2 import numpy as np img = cv2.imread("4.jpg") rows, cols, ch = img.shape mapx = np.ones(img.shape[:2], np.float32) mapy = np.ones(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)#修改这一行即可,对称 result_img = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR) cv2.imshow("img", img) cv2.imshow("result_img", result_img) cv2.waitKey() cv2.destroyAllWindows()
运行之后,我们得到了绕X轴翻转的图像,效果如下:
绕Y轴翻转
既然我们可以通过cv2.remap()函数绕X翻转,那么肯定的也可以绕Y轴翻转,只要将X坐标值以Y轴为对称进行交换即可。
话不多说,直接上代码:
import cv2 import numpy as np img = cv2.imread("4.jpg") rows, cols, ch = img.shape mapx = np.ones(img.shape[:2], np.float32) mapy = np.ones(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)# result_img = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR) cv2.imshow("img", img) cv2.imshow("result_img", result_img) cv2.waitKey() cv2.destroyAllWindows()
运行之后,我们得到绕Y轴翻转的图像:
绕XY轴翻转
那么绕XY轴一起翻转呢?这里二行代码一起更改:
import cv2 import numpy as np img = cv2.imread("4.jpg") rows, cols, ch = img.shape mapx = np.ones(img.shape[:2], np.float32) mapy = np.ones(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) result_img = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR) cv2.imshow("img", img) cv2.imshow("result_img", result_img) cv2.waitKey() cv2.destroyAllWindows()
运行之后,效果如下所示:
压缩一半
也就是将原图缩小一般,按将Y轴缩小一般,只需要将X轴设置为2倍即可。具体代码如下所示:
import cv2 import numpy as np img = cv2.imread("4.jpg") rows, cols, ch = img.shape mapx = np.ones(img.shape[:2], np.float32) mapy = np.ones(img.shape[:2], np.float32) for i in range(rows): for j in range(cols): mapx.itemset((i,j),j) mapy.itemset((i,j),2*i)#修改这行代码即可 result_img = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR) cv2.imshow("img", img) cv2.imshow("result_img", result_img) cv2.waitKey() cv2.destroyAllWindows()
运行之后,效果显示如下:
既然能压缩,意味着也可以实现缩小,缩小的具体实现,可以当作训练的习题,方便大家巩固掌握,博主在这里就不在赘述了。