关于Opencv如何将多幅图像显示在同一窗口,我查阅了许多资料,但是都是将两幅或多幅相同大小,相同通道数的图像拼接在一起显示,并不能将不同大小、通道数目的图像一起显示,这可以在python中可以利用numpy模块实现。因为图像的本质是一个多维矩阵,利用numpy的数组拼接功能可以实现将不同图像拼接成一个新矩阵,这样就像是同时显示了两幅图像。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import cv2 import numpy as np # 读取图片 imgflower = cv2.imread("img_flower.jpg") imgroi= cv2.imread("img_roi.jpg") imgwomen = cv2.imread("img_women.jpg") # 从本质上而言,图像是一个矩阵,我们可以用numpy拼接数组的方式,将两幅 # 图像拼接成一幅图像在显示出来,效果就像是同时显示了多幅图像 # 我们查看一下图像的大小信息,并将大小相同,通道相同的图片并排显示 print(imgflower.shape) print(imgroi.shape) print(imgwomen.shape) # 水平组合 imghstack = np.hstack((imgroi, imgwomen)) # 垂直组合 imgvstack = np.vstack((imgroi, imgwomen)) # 显示一下看看 cv2.namedWindow("imgvstack") cv2.imshow("imgvstack", imgvstack) cv2.namedWindow("imghstack") cv2.imshow("imghstack", imghstack) cv2.destroyAllWindows() |
结果如下:
我们分别拼接了两个大小、通道数目相同的图像。
那么如果,图像的大小或者通道数不同会怎样呢?
1 2 3 4 | imghstack_ = imghstack = np.hstack((imgroi, imgflower)) # 会报错 # ValueError: all the input array dimensions for the concatenation axis must match exactly, # but along dimension 0, the array at index 0 has size 512 and the array at index 1 has size 978 |
由此我们可以看到这种方法的一些弊端,首先就是它要求图像的通道及大小必须相同,其次就是当图像太大,或者数目较多时图像的显示会超出计算机的显示范围。当然我们也可以先对图像进行缩放处理再进行拼接显示,可是仅仅只是为了显示图像,这样的操作未免太繁琐。
为了实现任意数量、任意大小、任意通道的图像一起显示,我们可以编写一个函数,函数的实现过程不再赘述,下面是源码,注释的很详细:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # 定义函数,第一个参数是缩放比例,第二个参数是需要显示的图片组成的元组或者列表 def ManyImgs(scale, imgarray): rows = len(imgarray) # 元组或者列表的长度 cols = len(imgarray[0]) # 如果imgarray是列表,返回列表里第一幅图像的通道数,如果是元组,返回元组里包含的第一个列表的长度 # print("rows=", rows, "cols=", cols) # 判断imgarray[0]的类型是否是list # 是list,表明imgarray是一个元组,需要垂直显示 rowsAvailable = isinstance(imgarray[0], list) # 第一张图片的宽高 width = imgarray[0][0].shape[1] height = imgarray[0][0].shape[0] # print("width=", width, "height=", height) # 如果传入的是一个元组 if rowsAvailable: for x in range(0, rows): for y in range(0, cols): # 遍历元组,如果是第一幅图像,不做变换 if imgarray[x][y].shape[:2] == imgarray[0][0].shape[:2]: imgarray[x][y] = cv2.resize(imgarray[x][y], (0, 0), None, scale, scale) # 将其他矩阵变换为与第一幅图像相同大小,缩放比例为scale else: imgarray[x][y] = cv2.resize(imgarray[x][y], (imgarray[0][0].shape[1], imgarray[0][0].shape[0]), None, scale, scale) # 如果图像是灰度图,将其转换成彩色显示 if len(imgarray[x][y].shape) == 2: imgarray[x][y] = cv2.cvtColor(imgarray[x][y], cv2.COLOR_GRAY2BGR) # 创建一个空白画布,与第一张图片大小相同 imgBlank = np.zeros((height, width, 3), np.uint8) hor = [imgBlank] * rows # 与第一张图片大小相同,与元组包含列表数相同的水平空白图像 for x in range(0, rows): # 将元组里第x个列表水平排列 hor[x] = np.hstack(imgarray[x]) ver = np.vstack(hor) # 将不同列表垂直拼接 # 如果传入的是一个列表 else: # 变换操作,与前面相同 for x in range(0, rows): if imgarray[x].shape[:2] == imgarray[0].shape[:2]: imgarray[x] = cv2.resize(imgarray[x], (0, 0), None, scale, scale) else: imgarray[x] = cv2.resize(imgarray[x], (imgarray[0].shape[1], imgarray[0].shape[0]), None, scale, scale) if len(imgarray[x].shape) == 2: imgarray[x] = cv2.cvtColor(imgarray[x], cv2.COLOR_GRAY2BGR) # 将列表水平排列 hor = np.hstack(imgarray) ver = hor return ver |
我们来测试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import cv2 import numpy as np # 导入编写的函数,函数存放在OPencv文件夹下,文件名称为manyimgs from OPencv_ import manyimgs # 读取图片 imgflower = cv2.imread("img_flower.jpg") imgroi= cv2.imread("img_roi.jpg") imgwomen = cv2.imread("img_women.jpg") # 第二种方法,调用我们自己编写的一个函数实现任意大小、任意通道数的图像堆叠显示 # 以原来的0.5倍并排显示两张图片 stackedimageh = manyimgs.ManyImgs(0.2, ([imgflower, imgwomen])) # 垂直显示 stackedimagev = manyimgs.ManyImgs(0.2, ([imgflower, imgwomen], [imgwomen, imgflower])) # 如果只有图片数量为奇数,并希望能够垂直显示,可以创建一个空白图像 Blankimg = np.zeros((200, 200), np.uint8) # 大小可以任意函数会将其强制转换 stackedimageb = manyimgs.ManyImgs(0.2, ([imgflower, imgwomen], [imgwomen, Blankimg])) cv2.namedWindow("stackedimageh") cv2.imshow("stackedimageh", stackedimageh) cv2.namedWindow("stackedimagev") cv2.imshow("stackedimagev", stackedimagev) cv2.namedWindow("stackedimageb") cv2.imshow("stackedimageb", stackedimageb) cv2.waitKey(0) cv2.destroyAllWindows() |
效果如下:
再多一些: