python圖片合成
- 2020 年 1 月 10 日
- 筆記
python的PIL庫簡直好用的不得了,PIL下面的Image庫更是封裝了很多對圖片處理的函數,關於Image庫的介紹和使用,看這裡:http://effbot.org/imagingbook/image.htm
這裡用我半個月前看到的一篇部落格寫的demo作為背景,做一下圖片的合成
圖片可以看作是很多像素點組成的,每個像素點都是一個RGB顏色,(red, green, blue), 那麼合成兩張照片就有辦法了,我們可以在一張新的RGB色的圖片里一個像素點取圖片一的對應位置的像素,下一個像素點取圖片二的像素,直到遍歷完成,程式碼如下:
from PIL import Image ##這裡採用傳入圖片地址調用此函數 #這個方法目前不支援按比例合成,默認為1:1 #各取一個像素點合併,傳入的參數為兩張圖片的地址 def merge1(img1_address,img2_addess): status=100 #狀態碼100為正常 # 200為地址錯誤 try: img1=Image.open(img1_address) img2=Image.open(img2_address) except: status=200 img_new="" else: width=min(img1.size[0],img2.size[0]) height=min(img1.size[1],img2.size[1]) print(width,height) img_new = Image.new('RGB',(width,height)) for x in range(width): for y in range(height): if y%2==0: pixel=img1.getpixel((x,y)) img_new.putpixel((x,y),pixel) else: pixel=img2.getpixel((x,y)) img_new.putpixel((x,y),pixel) finally: return img_new,status
上述程式碼會返回一張新的圖片和一個狀態碼,接受的時候用兩個變數接受
另一種方法是每個像素點各取%50的原圖片的顏色,然後把像素點放置在對應位置,為了功能更加強大,我把兩者的混合比例設為可調,默認是50%的比例,程式碼如下:
from PIL import Image #將像素點按比例取色,然後合成一個新像素點 #傳入的參數為兩張圖片的地址和比例 #如果兩者之和不為1則以第一個圖片的比例為準 def merge2(img1_address,img2_address,percent1=0.50,percent2=0.50): status=100 #狀態碼100為正常 # 200為地址錯誤 try: img1=Image.open(img1_address) img2=Image.open(img2_address) except: status=200 img_new="" else: if percent1+percent2!=1: percent2=1-percent1 width = min(img1.size[0],img2.size[0]) height = min(img1.size[1],img2.size[1]) img_new = Image.new('RGB',(width,height)) for x in range(width): for y in range(height): r1,g1,b1=img1.getpixel((x,y)) r2,g2,b2=img2.getpixel((x,y)) r=int(percent1*r1+percent2*r2) g=int(percent1*g1+percent2*g2) b=int(percent1*b1+percent2*b2) img_new.putpixel((x,y),(r,g,b)) finally: return img_new,status
返回的參數與上述相同 如果想要保存圖片可用image.save()函數保存
總的程式碼如下:
from PIL import Image ##這裡採用傳入圖片地址調用此函數 #這個方法目前不支援按比例合成,默認為1:1 #各取一個像素點合併,傳入的參數為兩張圖片的地址 def merge1(img1_address, img2_addess, direct): status=100 #狀態碼100為正常 # 200為地址錯誤 try: img1=Image.open(img1_address) img2=Image.open(img2_address) except: status=200 img_new="" else: width=min(img1.size[0], img2.size[0]) height=min(img1.size[1], img2.size[1]) print(width,height) img_new = Image.new('RGB',(width, height)) for x in range(width): for y in range(height): if y%2 == 0: pixel = img1.getpixel((x,y)) img_new.putpixel((x,y), pixel) else: pixel = img2.getpixel((x,y)) img_new.putpixel((x,y), pixel) finally: return status #將像素點按比例取色,然後合成一個新像素點 #傳入的參數為兩張圖片的地址和比例 #如果兩者之和不為1則以第一個圖片的比例為準 def merge2(img1_address, img2_address, direction, percent1): status = 100 #狀態碼100為正常 # 200為地址錯誤 try: img1 = Image.open(img1_address) img2 = Image.open(img2_address) except: status = 200 img_new = "" else: percent2 = 1 - percent1 width = min(img1.size[0], img2.size[0]) height = min(img1.size[1], img2.size[1]) img_new = Image.new('RGB', (width,height)) for x in range(width): for y in range(height): r1,g1,b1=img1.getpixel((x,y)) r2,g2,b2=img2.getpixel((x,y)) r = int(percent1 * r1 + percent2 * r2) g = int(percent1 * g1 +percent2 * g2) b = int(percent1 * b1 +percent2 * b2) img_new.putpixel((x,y),(r,g,b)) img_new.save(direction) #img_new.show() finally: return status #切記在接受返回資訊時先判斷狀態碼是否異常,如果正確再執行相應操作 if __name__=='__main__': img1_address = "B:PictureYourName1.jpg" img2_address = "B:PictureYourName2.jpg" direction = "D:/Python/PyQt/課程設計/merges/merge9.png" status = merge2(img1_address, img2_address, direction, 0.30) print(status)
當然,我發現Image庫中有Image.blend(image1, image2, alpha)這個混合圖片的函數,還沒看源碼,不知道他是用什麼方法實現的。
原先的兩張照片:

合成後的照片:

左圖是方法一,右圖是方法二
優劣: 方法一不易造成曝光過度,因為實際的像素點並沒改動,只是間隔變大了,但這樣可能會造成輪廓不清晰 方法二在比例適當時效果是優於方式一的,但比例不合適就會看起來像曝光過度一樣,示例中方法二用的比例是0.3:0.7,又是比例不當效果會很糟糕,孰優孰劣請按效果好壞使用。
找時間我會分析一下Image中blend的源碼,到時候會更新在部落格上。 2017.12.13更新: Image庫中的blend函數確實出色,前幾天做課設看到知乎上的一段程式碼有人用過它,簡直就是一個濾鏡一樣,找時間一定看看它的源碼。
這個功能就當是課設中的一個小demo,到時候會集成在一起。
其實很想知道參考部落格中那個示例中的妹子照片是不是他的女朋友,好漂亮!!!可惜我還沒有女朋友(⊙﹏⊙)。
2017.12.22更新: 最近還在忙課設,看了一下PIL.Image中的blend函數,結果它是寫在PIL._imaging.cp35-win_amd64.pyd中的,這個是二進位文件,要看源程式碼的話只能反編譯。
參考: http://www.cnblogs.com/ThrEcho/p/4979193.html