天天看點

python圖檔合成

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:\Picture\YourName\1.jpg"
    img2_address = "B:\Picture\YourName\2.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)這個混合圖檔的函數,還沒看源碼,不知道他是用什麼方法實作的。

原先的兩張照片:

python圖檔合成

合成後的照片:

python圖檔合成

左圖是方法一,右圖是方法二

優劣:

方法一不易造成曝光過度,因為實際的像素點并沒改動,隻是間隔變大了,但這樣可能會造成輪廓不清晰

方法二在比例适當時效果是優于方式一的,但比例不合适就會看起來像曝光過度一樣,示例中方法二用的比例是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