关于Opencv如何将多幅图像显示在同一窗口,我查阅了许多资料,但是都是将两幅或多幅相同大小,相同通道数的图像拼接在一起显示,并不能将不同大小、通道数目的图像一起显示,这可以在python中可以利用numpy模块实现。因为图像的本质是一个多维矩阵,利用numpy的数组拼接功能可以实现将不同图像拼接成一个新矩阵,这样就像是同时显示了两幅图像。
例如:
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()
结果如下:
我们分别拼接了两个大小、通道数目相同的图像。
那么如果,图像的大小或者通道数不同会怎样呢?
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
由此我们可以看到这种方法的一些弊端,首先就是它要求图像的通道及大小必须相同,其次就是当图像太大,或者数目较多时图像的显示会超出计算机的显示范围。当然我们也可以先对图像进行缩放处理再进行拼接显示,可是仅仅只是为了显示图像,这样的操作未免太繁琐。
为了实现任意数量、任意大小、任意通道的图像一起显示,我们可以编写一个函数,函数的实现过程不再赘述,下面是源码,注释的很详细:
# 定义函数,第一个参数是缩放比例,第二个参数是需要显示的图片组成的元组或者列表
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
我们来测试一下:
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()