之前写QQ机器人时一直想实现一个抽卡功能,其中的十连需要将10张图片以两行五列的方式拼接成一张大图。话不多说,直接上代码和结果。
import os
from PIL import Image
from random import sample, choices
COL = 5 #指定拼接图片的列数
ROW = 2 #指定拼接图片的行数
UNIT_HEIGHT_SIZE = 900 #图片高度
UNIT_WIDTH_SIZE = 600 #图片宽度
PATH = "" #需要拼接的图片所在的路径
NAME = "" #拼接出的图片保存的名字
RANDOM_SELECT = False #设置是否可重复抽取图片
SAVE_QUALITY = 50 #保存的图片的质量 可选0-100
#进行图片的复制拼接
def concat_images(image_names, name, path):
image_files = []
for index in range(COL*ROW):
image_files.append(Image.open(path + image_names[index])) #读取所有用于拼接的图片
target = Image.new('RGB', (UNIT_WIDTH_SIZE * COL, UNIT_HEIGHT_SIZE * ROW)) #创建成品图的画布
#第一个参数RGB表示创建RGB彩色图,第二个参数传入元组指定图片大小,第三个参数可指定颜色,默认为黑色
for row in range(ROW):
for col in range(COL):
#对图片进行逐行拼接
#paste方法第一个参数指定需要拼接的图片,第二个参数为二元元组(指定复制位置的左上角坐标)
#或四元元组(指定复制位置的左上角和右下角坐标)
target.paste(image_files[COL*row+col], (0 + UNIT_WIDTH_SIZE*col, 0 + UNIT_HEIGHT_SIZE*row))
target.save(path + name + '.jpg', quality=SAVE_QUALITY) #成品图保存
#获取需要拼接图片的名称
def get_image_names(path):
image_names = list(os.walk(path))[0][2] #获取目标文件夹下的所有文件的文件名
#先用list将iterator转成list,再[0]取出里面的三元元组元素,再[2]取出元组中的由文件夹名组成的列表
#从所有文件中随机抽取需要数量的文件,可设置是否能重复抽取
#random库中的choices函数用于可放回抽取,第一个参数指定用于抽取的对象,k参数指定抽取数量
#sample函数用于不放回抽取,参数同上
selected_images = choices(image_names, k=COL*ROW) if RANDOM_SELECT else sample(image_names, COL*ROW)
return selected_images
if __name__ == '__main__':
concat_images(get_image_names(PATH), NAME, PATH)
2行5列拼接10行10列拼接
代码中涉及到PIL库中一些常用的函数,下面我们来介绍它们。
1.读取和保存图像
from PIL import Image #导入Image类
img = Image.open(path)
open函数从path(绝对路径或相对路径)加载图像,返回Image类的实例对象。
im.format, im.size, im.mode
分别返回图片的文件类型,大小和模式。
format属性标识图像的类型。如果未能从文件中读取图像,则为"无"。size属性是包含宽度和高度(以像素为单位)的 2 元组。mode属性定义图像中通道的数量和名称,以及像素类型和深度。常见模式为灰度图像的"L"(亮度),彩色图像的"RGB"和"CMYK"。
img.show()
show函数用于新建一个窗口显示img图片对象
img.save(file_name,[mode])
img.save('C:/photos/image.jpg','JEPG') #示例
save函数用将图片以指定名称和类型保存到指定路径。可以直接在第一个参数指定路径+文件名+扩展名,不加路径时将默认保存到当前目录;第二个参数可用于显示指定文件格式。除非通过第二个参数指定格式,否则库将使用文件名扩展名来获取要使用的文件存储格式。
2.图像的切割,粘贴以及拼接
Image.new(mode, size, color=0)
new函数用于生成一个新的图片对象,第一个参数mode指定图片模式,size指定大小,可选参数color指定颜色,默认为0(即黑色)
box = (0,0, 100,100)
region = img.crop(box)
crop函数用于从图像中切割出子图像,需要传入一个四元元组,元组中前两个元素指定左上角切割点的坐标,后两个元素指定右下角坐标。另需注意,坐标是指像素间的位置,原图片左上角为坐标原点,水平向右为x轴正向,竖直向下为y轴正向。
box = (0,0, 100,100)
img.paste(region, box=box, mask = None)
paste函数将region图像对象粘贴到img图像对象的指定位置,第一个参数指定要进行复制的图像,第二个参数为二元或四元数组,用于指定粘贴位置的左上角坐标(和右下角坐标)。使用paste函数时,区域的大小必须与给定区域完全匹配,且该区域不能扩展到图像之外。原始图像和被粘贴的图像的模式不需要匹配。如果模式未匹配,则在粘贴之前会自动转换成当前图像的模式。粘贴方法还可以将透明度mask作为可选参数。mask可选范围0-255,0表示透明粘贴,mask值越大粘贴透明度越低,255为不透明粘贴。
r, g, b = img.split()
#例子中使用的RGB图像,拆成R,G,B三个通道
#(,
#,
#)
img = Image.merge("RGB", (b, g, r))
split函数将图像对象拆成多个Image对象组成的一个元组(每个对象对应一个颜色通道),对于单通道图像会返回本身。
merge函数可用于将多个Image对象合并。
3.图像变换
im.resize((100, 100))
im.rotate(45)
resize函数传入一个二元元组,将图像调整为指定的大小。
rotate函数将图像进行旋转,传入参数指定角度,默认为逆时针旋转。
img.transpose(Image.FLIP_LEFT_RIGHT) #沿左边边缘进行对称变换
img.transpose(Image.FLIP_TOP_BOTTOM) #沿上边缘对称变换
img.transpose(Image.ROTATE_90) #逆时针旋转90度
img.transpose(Image.ROTATE_180)
img.transpose(Image.ROTATE_270)
transpose函数进行图像旋转或转置操作
l_img = img.convert("L") #将图像模式转成L(即灰度图)
convert函数可用于不同模式图像之间的转换