使用numpy进行9宫格图像拼接

本节内容要用到opencv-python模块,请先行安装。本例程中使用到的图片保存在pictures子目录下。本例的任务是要将9张JPG格式图片按三行三列拼接成下述九宫格。

版权声明

本文可以在互联网上自由转载,但必须:注明出处(作者:海洋饼干叔叔)并包含指向本页面的链接。

本文不可以以纸质出版为目的进行改编、摘抄。

本文节选自作者的《Python编程基础及应用》视频教程。

微实践:九宫格图像拼接

本节内容要用到opencv-python模块,请先行安装。本例程中使用到的图片保存在pictures子目录下。本例的任务是要将9张JPG格式图片按三行三列拼接成下述九宫格。
在这里插入图片描述

#pictures9.py
import glob
import numpy as np
from cv2 import imread,imwrite			#cv2来自OpenCV-Python扩展库

imgs,heights,widths = [],[],[]
for f in glob.glob("pictures/*.jpg"):
    img = imread(f,-1)
    print("original:",img.shape)
    h,w = img.shape[:2]
    heights.append(h)
    widths.append(w)
    imgs.append(img)

控制台输出:

original: (960, 1280, 3)
...
original: (793, 1280, 3)
...
original: (960, 1280, 3)

glob.glob(“pictures/*.jpg”)返回一个序列,该序列包括当前目录之pictures子目录下的所有扩展名为jpg的图片文件的文件名(含路径)。读者可以在上述循环中加上print(f)把这些文件名打出来看看。

imread()函数来自opencv-python扩展库,它读取一个图片,并返回一个多维数组。我们打印了这些多维数组的形状,典型如(960,1280,3):它表示对应图片高960个像素,宽1280个像素,每个像素由3个值构成,分别表示该像素红、绿、蓝三个通道的颜色值。请读者注意,本例中的9张图片的高度值并不相等。

img.shape[:2]取出了图像/多维数组的高度和宽度,分别赋值给h和w。所有的图片高、宽均存入heights、widths列表备用。所有的图片/多维数组均存入imgs列表备用。

显然,(960,1280)的图片尺寸对于九宫格拼接而言太大了,需要分别提取缩略图。

#pictures9.py
#制作缩略图,纵横向每3个像素抽一个
minHeight = min(heights)
minWidth = min(widths)
for i,x in enumerate(imgs):
    imgs[i] = x[:minHeight:3,:minWidth:3,:]
    print("thumbnail:",imgs[i].shape)

#横向沿轴1拼接
img = np.concatenate(imgs,1)
print("concatenated by axis1:",img.shape)
imwrite("concatenated_1.jpg",img)

控制台输出:

thumbnail: (265, 427, 3)
...
thumbnail: (265, 427, 3)
concatenated by axis1: (265, 3843, 3)

我们首先获得了全部图像的最小高度 - min(heights)和最小宽度 - min(widths)。然后,遍历并逐一使用多维数组的切片下标语法提取缩略图:横纵向都从每3个像素中抽1个像素。根据打印出来的值,我们可以看到,所有的缩略图都是265 x 427个像素。

接下来,我们使用np.concatenate()函数将imgs列表中的9张图沿1轴拼接(横向拼接)至img。根据打印的结果,横向拼接后的图片尺寸为265 x 3843。imwrite()则将img存至文件"concatenated_1.jpg"。读者可以在项目目录中找到这个照片,如下:
在这里插入图片描述

下述代码及其执行结果可以帮助读者理解concatenate()函数的作用:可以看到,对于二维数组而言,沿0轴拼接相当于纵向延长数组,沿1轴拼接则相当于横向延长数组。

#con.py
import numpy as np

a = np.array([[1,2],[3,4]])
b = np.array([[11,22],[33,44]])
print("a=\n",a)
print("b=\n",b)

c = np.concatenate([a,b],0)  #沿0轴拼接,纵向延长
print("np.concatenate([a,b],0)=\n",c)
c = np.concatenate([a,b],1)  #沿1轴拼接,横向延长
print("np.concatenate([a,b],1)=\n",c)

执行结果:

a=
 [[1 2]
 [3 4]]
b=
 [[11 22]
 [33 44]]
np.concatenate([a,b],0)=
 [[ 1  2]
 [ 3  4]
 [11 22]
 [33 44]]
np.concatenate([a,b],1)=
 [[ 1  2 11 22]
 [ 3  4 33 44]]

借助于concatenate()函数,我们可以先将图片0-2横向拼接,再将图片3-5横向拼接,接着再将图片6-8横向拼接。最后再将拼接结果纵向拼接,即得3x3的九宫格:

#pictures9.py
#方法1
img0 = np.concatenate(imgs[:3],1)			#沿1轴横向拼接
img1 = np.concatenate(imgs[3:6],1)
img2 = np.concatenate(imgs[6:],1)
img9 = np.concatenate([img0,img1,img2],0)   #沿0轴纵向拼接
print("3x3_0, shape:",img9.shape)
imwrite("3x3_0.jpg",img9)

控制台输出:

3x3_0, shape: (795, 1281, 3)

上述3x3_0.jpg应该与本例开始处的图片相同,该文件也存入了当前项目目录,读者自行查证。除了上面这个方法外,下面这个方法也可以达到相同的效果,但真的很难理解。在下述代码中,img1.swapaxes(1,2)将img1的1轴与2轴进行了交换。

#方法2
img = np.concatenate(imgs,0)				      #将9图沿0轴纵向拼
img1 = img.reshape(3,3,265,427,3)                 #改变形状至5维数组
img9 = img1.swapaxes(1,2).reshape(795,1281,3)	  #1轴和2轴交换,再改变形状
print("3x3_1, shape:",img9.shape)
imwrite("3x3_1.jpg",img9)

控制台输出:

3x3_1, shape: (795, 1281, 3)

读者可以查证3x3_1.jpg的最终效果。

读者可以试着执行下述代码来观察轴交换的效果:

#swapaxes.py
import numpy as np
a = np.array([[1,2],[3,4]])
print("a=\n",a)
print("a.swapaxes(0,1):\n",a.swapaxes(0,1))

b = np.array([[1,2,3,4],[5,6,7,8]])
print("b=\n",b)
print("b.reshape(2,2,2)=\n",b.reshape(2,2,2))
print("b.reshape(2,2,2).swapaxes(1,2))=\n",b.reshape(2,2,2).swapaxes(1,2))

与多维数组操作有关的函数列表如下:

函数名作用函数名作用
concatenate()拼接多个数组vstack/hstack()沿0/1轴拼接数组
column_stack()按列连接多个一维数组split,array_split()将数组分为多段
transpose()重设轴的顺序swapaxes()交换两个轴的顺序

本文节选自作者的《Python编程基础及应用》视频教程及同名教科书。想完整零基础学习Python程序设计,欢迎使用此免费视频教程。

在这里插入图片描述

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值