python中调用np.hstack对两张图片进行水平拼接时提示:“ValueError: all the input array dimensions except for the concatenation axis must match exactly” 代码:
import numpy as np
import cv2
imgname1 = '1.jpg'
imgname2 = '2.jpg'
img1 = cv2.imread(imgname1)
img2 = cv2.imread(imgname2)
hmerge = np.hstack((img1 , img2)) #水平拼接
cv2.imshow("merge", hmerge) #拼接显示为merge
cv2.waitKey(0)
cv2.destroyAllWindows()
此时python会报错:
Traceback (most recent call last):
File "D:/xxxx/xxxx.py", line xx, in
hmerge = np.hstack((gray1, gray2)) #水平拼接
File "D:\xxxx\venv\lib\site-packages\numpy\core\shape_base.py", line 280, in hstack
return _nx.concatenate(arrs, 1)
ValueError: all the input array dimensions except for the concatenation axis must match exactly
这是因为拼接的两个图片的大小不一致,在使用numpy中的hstack()函数时,必须使所有输入数组具有相同的维数(数量和尺寸)才能进行拼接合并,否则就会提示上述错误。
解决方法:
1、利用opencv的其他方法,这里给出一些参考文档,不够都是使用C++或其他语言实现的,还没有找到python实现。
参考1:https://blog.csdn.net/u014581740/article/details/54983674(利用opencv将两张图像在同一窗口上显示,并在图片上显示文字)
参考2:https://blog.csdn.net/csd_ct/article/details/51686100(opencv2 一个窗口显示多幅图片)
参考3:https://my.oschina.net/u/1426828/blog/368838(OpenCV 在同一窗口显示多幅图片)
参考4:https://blog.csdn.net/chen232450061/article/details/72920644(opencv 将两张图片显示到一幅图片中)
2、使用matplotlib,能够将多张图片排列在一个窗口并且可以不用在意图片大小尺寸和颜色通道一样,具体又可以分为两种方法:一种是定位图片顶点坐标,相当于直接将图片拷贝到新的画布上;另一种是建立画布,按照类似matlab的subplot的样子显示图片。
(1)第一种方法为:
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
# 1. 将两张icon图标显示在同一张图上面并保存;
def combine_photo(arr):
#arr是一个列表,里面是两个图片的路径,例如["p1.png", 'p2.png']
toImage = Image.new('RGB', (128, 64))
img1 = Image.open(arr[0])
img12 = Image.open(arr[1])
toImage.paste(img1, (0, 0))
toImage.paste(img12, (64, 0, 64 + img1.size[0], 0 + img1.size[1]))
#函数描述:toImage:背景图片,paste()函数四个变量分别为:起始横轴坐标,起始纵轴坐标,横轴结束坐标,纵轴结束坐标;
toImage.save( + "merged.png")
plt.imshow(toImage)
plt.title(level)
#plt.show()
效果图:
如图实现了将两个icon组合在一起的样式,其中,输入参数为两张图片的路径。参考文档:https://blog.csdn.net/weixin_41765699/article/details/83097429(python两张图片显示在一张图上)
(2)使用matplotlib方法
#-*- coding: UTF-8 -*-
import matplotlib.pyplot as plt # plt 用于显示图片
import matplotlib.image as mpimg # mpimg 用于读取图片
img1=mpimg.imread('1.png')#读取图片
img2=mpimg.imread('2.png')#读取图片
plt.gcf().canvas.set_window_title('Test')#设置窗口名称
plt.gcf().suptitle("multi pic test")#设置图片标题
plt.subplot(121), plt.imshow(img1), plt.title("first")
plt.subplot(122), plt.imshow(img2), plt.title("second")
plt.show()
效果如下:
其中subplot()函数中传入的三个数字的含义分别为:行数、列数和序号(按照先行后列进行排序),需要先设定图片所在位置,然后才能使用imshow()展示在相应位置上,否则,后展示的图片会覆盖之前图片。subplot()的参数也可以写为:
plt.subplot(1, 2, 1), plt.imshow(img1), plt.title("first")
plt.subplot(1, 2, 2), plt.imshow(img2), plt.title("second")
此外,还需要说明的是:
①使用的imread方法只能读取png等几种格式的图片,不能读取jpg类型的图片,对于此问题,可以换用opencv来读取图片,不过由于opencv的初创者使用的是BGR模式,而现在一般使用的是RGB模式,所以需要将opencv中的BGR、GRAY格式转换为RGB,使matplotlib中能正常显示opencv的图像。具体代码如下:
#-*- coding: UTF-8 -*-
import cv2
import matplotlib.pyplot as plt # plt 用于显示图片
img1 = cv2.imread('7.jpg',cv2.IMREAD_COLOR)
img2 = cv2.imread('7.jpg',cv2.IMREAD_GRAYSCALE)
img3 = cv2.imread('7.jpg',cv2.IMREAD_UNCHANGED)
img4 = cv2.imread('7.jpg')
# 将opencv中的BGR、GRAY格式转换为RGB,使matplotlib中能正常显示opencv的图像
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
#上条语句可以替换为img1 = img1[:, :, ::-1]
#img[:,:,0]表示图片的蓝色通道,熟悉Python的同学应该知道,对一个字符串s进行翻转用的是s[::-1],同样img[:,:,::-1]就表示BGR通道翻转,变成RGB
img2 = cv2.cvtColor(img2, cv2.COLOR_GRAY2RGB)
img3 = cv2.cvtColor(img3, cv2.COLOR_BGR2RGB)
img4 = cv2.cvtColor(img4, cv2.COLOR_BGR2RGB)
fig = plt.figure()
plt.gcf().canvas.set_window_title('Test')#设置窗口名称
plt.gcf().suptitle("multi pic test")#设置图片标题
plt.subplot(221)
plt.imshow(img1)
plt.title('img1')
plt.subplot(222)
plt.imshow(img2)
plt.title('img2')
plt.subplot(223)
plt.imshow(img3)
plt.title('img3')
plt.subplot(224)
plt.imshow(img4)
plt.title('img4')
plt.show()
效果图为:
②可以看到,使用这种方式后,对图片进行排布就变得非常简单方便了。但是如果仅仅需要展示图片的话,我们还需要去掉坐标轴,使用如下语句:
plt.xticks([])
plt.yticks([])
#使用上面两行代码将坐标比例尺置空,或者下面一行代码关闭坐标轴,都可以实现想要的效果
axis('off')
加上上述代码后:
#-*- coding: UTF-8 -*-
import cv2
import matplotlib.pyplot as plt # plt 用于显示图片
img1 = cv2.imread('7.jpg')
img2 = cv2.imread('11.jpg')
# 将opencv中的BGR、GRAY格式转换为RGB,使matplotlib中能正常显示opencv的图像
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)
fig = plt.figure()
plt.gcf().canvas.set_window_title('Test')#设置窗口名称
plt.gcf().suptitle("multi pic test")#设置图片标题
plt.subplot(121)
plt.imshow(img1)
plt.title('img1')
plt.xticks([])
plt.yticks([])
plt.subplot(122)
plt.imshow(img2)
plt.title('img2')
plt.xticks([])
plt.yticks([])
plt.show()
效果为:
③可以看到,效果已经美观了很多,但还是有一些问题,我们可以使用下面的代码调整子图间距和整体空白:
fig.tight_layout()#调整整体空白
plt.subplots_adjust(wspace =0, hspace =0)#调整子图间距
④此外,观察到生成的图片在清晰度上还有一些问题,我们可以使用一些语句对清晰度进行调整:
plt.rcParams['figure.figsize'] = (12.5, 4.0) # 设置figure_size尺寸
# 默认的像素:[6.0,4.0],分辨率为100,图片尺寸为 600&400
# 设置figsize可以在不改变分辨率情况下改变比例
#或者使用语句:plt.figure(figsize=(12.5,4))
#或者使用语句:plt.figsize(12.5, 4)
plt.rcParams['savefig.dpi'] = 300 #设置保存时的图片分辨率
plt.rcParams['figure.dpi'] = 300 #设置绘制时的图片分辨率
# 指定dpi=200,图片尺寸为 1200*800
# 指定dpi=300,图片尺寸为 1800*1200
plt.rcParams['image.interpolation'] = 'nearest' # 设置 interpolation style
plt.rcParams['image.cmap'] = 'gray' # 设置 颜色 style
⑤以上的设置基本都是针对显示图片时,如果仅对保存文件设置而不需要查看图片,可以使用以下语句:
plt.savefig('1.png', bbox_inches='tight', dpi=300) #去掉多余的padding空白区域,并按指定分辨率保存
最终效果:
参考文献:
python将多幅图片显示在一张图片上:
https://blog.csdn.net/wugui1111/article/details/80706411
如何使用opencv和matplotlib把多个图片显示在一个窗体内:
https://blog.csdn.net/u010454030/article/details/80312809
python使用opencv或matplotlib把多张图片显示在一个窗口内的方法:
https://blog.csdn.net/ITBigGod/article/details/87009082
基于Python中的matplotlib图片的灰度处理:
https://blog.csdn.net/qq1815145797/article/details/78835573
如有不当之处,欢迎指正交流!