您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Python中照片合成的案例,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
看電影的時候發現一個照片墻的功能,覺得這樣生成照片挺好玩的,于是就動手用Python做了一下,覺得用來作照片紀念的效果可能會不錯。
P:后面了解到我想做的功能叫蒙太奇拼圖,所以這篇博客記錄先留著,閑下來會去看一下蒙太奇拼圖的算法
https://github.com/jiandi1027/photo.git
1.獲取圖片文件夾的圖片個數N,將底圖拆分成XY塊區域,且使X * Y<N
(為了保證整體的協調,會舍棄幾張圖片,比如5張時可能只取22的4張圖片)
# 打開圖片 base = Image.open(baseImgPath) base = base.convert('RGBA') # 獲取圖片文件夾圖片并打亂順序 files = glob.glob(imagesPath + '/*.*') random.shuffle(files) # 圖片數量 num = len(files) # 底圖大小 x = base.size[0] y = base.size[1] # 每張圖片數量 這個公式是為了xNum * yNum 的總圖片數量<num又成比例的最大整數 yNum = int((num / (y / x)) ** 0.5) if yNum == 0: yNum = 1 xNum = int(num / yNum) # 圖片大小 因為像素沒有小數點 為防止黑邊所以+1 xSize = int(x / xNum) + 1 ySize = int(y / yNum) + 1
2.遍歷文件夾的圖片,依次填充生成最終合成圖
for file in files: fromImage = Image.open(file) i = int(num % xNum) j = int(num / xNum) out = fromImage.resize((xSize, ySize), Image.ANTIALIAS).convert('RGBA') toImage.paste(out, (i * xSize, j * ySize)) toImage = toImage.convert('RGBA') img = Image.blend(base, toImage, 0.3) # 顯示圖片 photo = ImageTk.PhotoImage(img) showLabel.config(image=photo) showLabel.image = photo if num < xNum * yNum: num = num + 1
3.生成結束后保存圖片
toImage.save(‘generator.png’)
img.save(“final.png”)
4.建立可視化界面
5.Pyinstaller生成exe可執行文件
安裝pyinstaller模塊,執行命令生成exe文件
pyinstaller -F -w test.py (-w就是取消窗口)
Python的語法和設計規范還沒學過,所以代碼規范代碼復用之類的可能會有點不到位,本博文主要是一個思路與整體流程的記錄。
后續又優化了一下一些特效,比如合成圖片采用隨機位置,增加黑白,流年等顯示特效,透明度自選等。
import PIL.Image as Image import glob import random import tkinter.filedialog from tkinter.filedialog import askdirectory, Label, Button, Radiobutton, Entry import threading import numpy as np from PIL import ImageTk alpha = 0.3 imagesPath = '' # 滑動條回調 修改透明度 def resize(ev=None): global alpha alpha = scale.get() / 100 # 黑白 def blackWithe(image): # r,g,b = r*0.299+g*0.587+b*0.114 im = np.asarray(image.convert('RGB')) trans = np.array([[0.299, 0.587, 0.114], [0.299, 0.587, 0.114], [0.299, 0.587, 0.114]]).transpose() im = np.dot(im, trans) return Image.fromarray(np.array(im).astype('uint8')) # 流年 def fleeting(image, params=12): im = np.asarray(image.convert('RGB')) im1 = np.sqrt(im * [1.0, 0.0, 0.0]) * params im2 = im * [0.0, 1.0, 1.0] im = im1 + im2 return Image.fromarray(np.array(im).astype('uint8')) # 舊電影 def oldFilm(image): im = np.asarray(image.convert('RGB')) # r=r*0.393+g*0.769+b*0.189 g=r*0.349+g*0.686+b*0.168 b=r*0.272+g*0.534b*0.131 trans = np.array([[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]).transpose() # clip 超過255的顏色置為255 im = np.dot(im, trans).clip(max=255) return Image.fromarray(np.array(im).astype('uint8')) # 反色 def reverse(image): im = 255 - np.asarray(image.convert('RGB')) return Image.fromarray(np.array(im).astype('uint8')) def chooseBaseImagePath(): name = tkinter.filedialog.askopenfilename() if name != '': global baseImgPath baseImgPath = name baseImageLabel.config(text=name) baseImg = Image.open(baseImgPath) widthEntry.delete(0, tkinter.END) heightEntry.delete(0, tkinter.END) widthEntry.insert(0, baseImg.size[0]) heightEntry.insert(0, baseImg.size[1]) else: baseImageLabel.config(text="您沒有選擇任何文件") def chooseImagesPath(): name = askdirectory() if name != '': global imagesPath imagesPath = name ImagesLabel.config(text=name) else: ImagesLabel.config(text="您沒有選擇任何文件") def thread_it(func, *args): # 創建 t = threading.Thread(target=func, args=args) # 守護 !!! t.setDaemon(True) # 啟動 t.start() def test(): MyThread(1, "Thread-1", 1).start() baseImgPath = '' def generator(): baseImg = Image.open(baseImgPath) baseImg = baseImg.convert('RGBA') files = glob.glob(imagesPath + '/*.*') # 獲取圖片 random.shuffle(files) num = len(files) # 模板圖片大小 x = baseImg.size[0] y = baseImg.size[1] # 每張圖片數量 這個公式是為了xNum * yNum 的總圖片數量<num又成比例的最大整數 yNum = int((num / (y / x)) ** 0.5) if yNum == 0: yNum = 1 xNum = int(num / yNum) # 圖片大小 因為像素沒有小數點 為防止黑邊所以+1 xSize = int(x / xNum) + 1 ySize = int(y / yNum) + 1 # 生成數量的隨機列表 用于隨機位置合成圖片 l = [n for n in range(0, xNum * yNum)] random.shuffle(l) toImage = Image.new('RGB', (x, y)) num = 1 for file in files: if num <= xNum * yNum: num = num + 1 else: break fromImage = Image.open(file) temp = l.pop() i = int(temp % xNum) j = int(temp / xNum) out = fromImage.resize((xSize, ySize), Image.ANTIALIAS).convert('RGBA') toImage.paste(out, (i * xSize, j * ySize)) toImage = toImage.convert('RGBA') img = Image.blend(baseImg, toImage, alpha) # 特效 但是會讀取像素會降低效率 choose = v.get() if choose == 1: img = blackWithe(img) elif choose == 2: img = fleeting(img) elif choose == 3: img = oldFilm(img) elif choose == 4: img = reverse(img) resize = img.resize((300, 300), Image.ANTIALIAS).convert('RGBA') # 顯示圖片 photo = ImageTk.PhotoImage(resize) showLabel.config(image=photo) showLabel.image = photo toImage.save('generator.png') img = img.resize((int(widthEntry.get()),int(heightEntry.get())), Image.ANTIALIAS).convert('RGBA') img.save("final.png") resize.save("resize.png") class MyThread(threading.Thread): # 繼承父類threading.Thread def __init__(self, threadID, name, counter): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.counter = counter def run(self): # 把要執行的代碼寫到run函數里面 線程在創建后會直接運行run函數 generator() root = tkinter.Tk() root.title('generator') root.geometry('500x550') baseImageLabel = Label(root, text='') baseImageLabel.place(x=10, y=10) baseImageBtn = Button(root, text="選擇底圖", command=chooseBaseImagePath).place(x=10, y=30) ImagesLabel = Label(root, text='') ImagesLabel.place(x=10, y=60) ImagesBtn = Button(root, text="選擇合成圖文件夾", command=chooseImagesPath).place(x=10, y=80) v = tkinter.IntVar() v.set(0) Radiobutton(root, variable=v, text='默認', value=0, ).place(x=10, y=120) Radiobutton(root, variable=v, text='黑白', value=1, ).place(x=110, y=120) Radiobutton(root, variable=v, text='流年', value=2, ).place(x=210, y=120) Radiobutton(root, variable=v, text='舊電影', value=3, ).place(x=310, y=120) Radiobutton(root, variable=v, text='反色', value=4, ).place(x=410, y=120) scaleLabel = Label(root, text='透明度').place(x=10, y=170) scale = tkinter.Scale(root, from_=0, to=100, orient=tkinter.HORIZONTAL, command=resize) scale.set(30) # 設置初始值 scale.pack(fill=tkinter.X, expand=1) scale.place(x=70, y=150) Label(root, text='寬(像素)').place(x=180, y=170) widthEntry = Entry(root, bd=1) widthEntry.place(x=230, y=173, width=100) Label(root, text='高(像素)').place(x=320, y=170) heightEntry = Entry(root, bd=1) heightEntry.place(x=370, y=173, width=100) generatorBtn = Button(root, text="生成", command=test).place(x=10, y=220) showLabel = Label(root) showLabel.place(x=100, y=220) root.mainloop()
關于Python中照片合成的案例就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。