PIL基礎

小菜菜-K發表於2020-12-31

PIL官方文件:

http://effbot.org/imagingbook/

一、PIL(Python Imaging Library)的基本概念

PIL中所涉及的基本概念有如下幾個:通道(bands)、模式(mode)、尺寸(size)、座標系統(coordinate system)、調色盤(palette)、資訊(info)和濾波器(filters)。

1、通道

每張圖片都是由一個。或者多個資料通道構成。PIL允許在單張圖片中合成相同維數和深度的多個通道。

以RGB影像為例,每張圖片都是由三個資料通道構成,分別為R、G和B通道。而對於灰度影像,則只有一個通道。

2、模式

影像的模式定義了影像的型別和畫素的位寬。當前支援如下模式:

1:1位畫素,表示黑和白,但是儲存的時候每個畫素儲存為8bit。

L:8位畫素,表示黑和白。

P:8位畫素,使用調色盤對映到其他模式。

RGB:3x8位畫素,為真彩色。

RGBA:4x8位畫素,有透明通道的真彩色。

CMYK:4x8位畫素,顏色分離。

YCbCr:3x8位畫素,彩色視訊格式。

I:32位整型畫素。

F:32位浮點型畫素。

PIL也支援一些特殊的模式,包括RGBX(有padding的真彩色)和RGBa(有自左乘alpha的真彩色)。

3、尺寸

通過size屬性可以獲取圖片的尺寸。這是一個二元組,包含水平和垂直方向上的畫素數。

4、座標系統

PIL使用笛卡爾畫素座標系統,座標(0,0)位於左上角。注意:座標值表示畫素的角;位於座標(0,0)處的畫素的中心實際上位於(0.5,0.5)。

座標經常用於二元組(x,y)。長方形則表示為四元組,前面是左上角座標。例如,一個覆蓋800x600的畫素影像的長方形表示為(0,0,800,600)。

5、調色盤

調色盤模式 ("P")使用一個顏色調色盤為每個畫素定義具體的顏色值

6、資訊

使用info屬性可以為一張圖片新增一些輔助資訊。這個是字典物件。載入和儲存影像檔案時,多少資訊需要處理取決於檔案格式。

7、濾波器

對於將多個輸入畫素對映為一個輸出畫素的幾何操作,PIL提供了4個不同的取樣濾波器:

NEAREST:最近濾波。從輸入影像中選取最近的畫素作為輸出畫素。它忽略了所有其他的畫素。

BILINEAR:雙線性濾波。在輸入影像的2x2矩陣上進行線性插值。注意:PIL的當前版本,做下采樣時該濾波器使用了固定輸入模板。

BICUBIC:雙立方濾波。在輸入影像的4x4矩陣上進行立方插值。注意:PIL的當前版本,做下采樣時該濾波器使用了固定輸入模板。

ANTIALIAS:平滑濾波。這是PIL 1.1.3版本中新的濾波器。對所有可以影響輸出畫素的輸入畫素進行高質量的重取樣濾波,以計算輸出畫素值。在當前的PIL版本中,這個濾波器只用於改變尺寸和縮圖方法。

注意:在當前的PIL版本中,ANTIALIAS濾波器是下采樣(例如,將一個大的影像轉換為小圖)時唯一正確的濾波器。BILIEAR和BICUBIC濾波器使用固定的輸入模板,用於固定比例的幾何變換和上取樣是最好的。

二、PIL模組中常用的類

PIL模組中常用的最重要的類是Image類,需要在程式中引入Image。Image常用的方法有:

Open():開啟一張圖片,方法內需傳入圖片的名稱,即:路徑+檔名.字尾名,例如:Image.open(“pic14.jpg”),open()方法會返回一個Image物件,我們可以使用Image的方法來獲取該物件的屬性。

物件名.format():獲取影像的格式,如:jpg,jpeg,ppm等。

物件名.size:獲取影像的大小尺寸

物件名.mode:獲取影像的顏色屬性,灰度圖或RGB

物件名.show():將圖片顯示出來

物件名.save(arg1,arg2):將圖片儲存,arg1是圖片儲存的名稱,即:路徑+檔名,arg2是圖片儲存的格式。

物件名.crop(arg):擷取圖片的某一部分,引數arg是一個元組型別的變數,形式為:(left,upper,right,lower)。在PIL的座標系中,圖片的左上角是座標系的原點。這裡的(left,upper,right,lower)代表的是擷取部分的座標,用(left,upper)座標表示擷取區域的左上角點,用(right,lower)座標代表擷取區域的右下角點,這樣的話,區域的位置和大小就都確定了。

物件名.split():將圖片的幾個通道分開,例如:r,g,b=im.split()

Image.merge(“RGB”,(b,g,r)):將圖片的通道分開後重新組合得到一張新的圖片。

三、案例程式碼

1、開啟一張圖片,然後顯示並獲取圖片的尺寸大小,並生成縮圖

程式碼:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
im=Image.open("pic01.jpg")
im.show()
xsize,ysize=im.size
im.thumbnail((xsize//2,ysize//2))
im.save("thumb_pic01.jpg","JPEG")

程式結果:

(1024, 638)

程式會使用系統預設的圖片檢視器將圖片顯示出來,並以二元組的形式將圖片的尺寸列印出來。在生成縮圖時,需要將縮圖的尺寸以元組的形式傳入,然後儲存。

2、將圖片旋轉90°並儲存

程式碼:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
im = Image.open("pic01.jpg")
im=im.resize((im.size[0]//2,im.size[1]//2))
out=im.rotate(90).save("pic01_rotate_90.jpg")

程式結果:

程式執行結果:將rotate方法返回的圖片以指定的名稱儲存起來,開啟圖片發現圖片被裁剪了。也可以使用transpose()方法對圖片進行上下翻轉、左右翻轉,旋轉等操作。示例如下:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
im = Image.open("pic01.jpg")
out=im.transpose(Image.FLIP_LEFT_RIGHT)#將圖片進行左右翻轉操作
out.show()
out=im.transpose(Image.FLIP_TOP_BOTTOM)#將圖片進行上下翻轉操作
out.show()
out=im.transpose(Image.ROTATE_180)#將圖片旋轉180°
out.show()

3、 擷取圖片並實現將圖片沿著某一方向滑動的效果

首先我們需要定義一個函式以實現讓圖片沿著x方向滑動,程式碼如下:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
def roll_x_side(image, delta):
        "Roll an image sideways"
        xsize, ysize = image.size
        delta = delta % xsize
        if delta == 0: return image
        part1 = image.crop((0, 0, delta, ysize))
            part2 = image.crop((delta, 0, xsize, ysize))
        image.paste(part2, (0, 0, xsize-delta, ysize))
        image.paste(part1, (xsize-delta, 0, xsize, ysize)
        return image

在這裡我們指定了滑動的距離。然後使用了crop方法,將要擷取區域的左上角頂點的座標和右下角頂點的座標以一個四元組的形式傳入該方法,crop()方法會返回該區域的圖片。在獲取需要擷取的區域後,再將該區域貼上到滑動後的區域。這樣就實現了沿著x軸的滑動。實現沿著y軸滑動的函式與之類似,程式碼如下:

def roll_y_side(image, delta):
        "Roll an image sideways"
        xsize, ysize = image.size
        delta = delta % ysize
        if delta == 0: return image
        part1 = image.crop((0, 0, xsize, delta))
           part2 = image.crop((0, delta, xsize, ysize))
        image.paste(part2, (0, 0, xsize, ysize-delta))
        image.paste(part1, (0, ysize-delta, xsize, ysize))
        return image

完整的程式碼如下:

import os, sys
from PIL import Image,ImageFilter,ImageDraw
def roll_x_side(image, delta):
        "Roll an image sideways"
        xsize, ysize = image.size
        delta = delta % xsize
        if delta == 0: return image
        part1 = image.crop((0, 0, delta, ysize))
            part2 = image.crop((delta, 0, xsize, ysize))
        image.paste(part2, (0, 0, xsize-delta, ysize))
        image.paste(part1, (xsize-delta, 0, xsize, ysize)
        return image
def roll_y_side(image, delta):
        "Roll an image sideways"
        xsize, ysize = image.size
        delta = delta % ysize
        if delta == 0: return image
        part1 = image.crop((0, 0, xsize, delta))
           part2 = image.crop((0, delta, xsize, ysize))
        image.paste(part2, (0, 0, xsize, ysize-delta))
        image.paste(part1, (0, ysize-delta, xsize, ysize))
        return image
im = Image.open("pic01.jpg")
im_01=roll_x_side(im,300)
im_01.save("pic01_x_roll.jpg")
im_01.show()
im_02=roll_y_side(im,300)
im_02.save("pic01_y_roll.jpg")
im_02.show()

4、 將彩色圖片分開成單個通道再合併

程式碼:

im=Image.open("pic01.jpg")
im.show()
r, g, b = im.split()
r.show()
g.show()
b.show()#將這幾個單通道的圖片重新組合成一張新的圖片
im = Image.merge("RGB", (b, r, g))
im.show()

5、 顏色變換:將彩色圖片轉換為灰度圖

程式碼:

im = Image.open("pic01.jpg")
im.show()
out=im.convert("L")#將RGB格式的圖片轉換為灰度圖
out.show()
print(out.mode,out.format,out.size)

6、 影像濾波

程式碼:

im = Image.open("pic01.jpg")
out=im.filter(ImageFilter.DETAIL)#細節增強
out.show()
out=im.filter(ImageFilter.BLUR)#模糊化
out.show()
out=im.filter(ImageFilter.CONTOUR)#輪廓濾波,將圖片的輪廓提取出來
out.show()
out=im.filter(ImageFilter.EDGE_ENHANCE)#邊緣強化
out.show()
out=im.filter(ImageFilter.EDGE_ENHANCE_MORE)#深度邊緣增強濾波,會使得影像中邊緣部分更加明顯
out.show()
out=im.filter(ImageFilter.EMBOSS)#浮雕濾波,會使影像呈現出浮雕效果
out.show()
out=im.filter(ImageFilter.SMOOTH)#平滑濾波
out.show()

 

相關文章