前戲:
雖然PIL沒有入OpenCV那樣強大的功能,但是所提供的功能,在一般的圖像處理中足夠使用。
圖像類別:
計算機繪圖中有兩類圖像:一類是矢量圖,另一類是點陣圖(位圖)
矢量圖:
基於計算機數字對象的繪圖,其圖形的構成包括點,線,多邊形等這樣的幾何圖像。在實際顯示的時候一般都是通過數學公式計算得到的。
所以其產生的文件比較小,而且對其進行縮放,旋轉等操作后,圖像不會失真。這種圖像與分辨率無關,在輸出結果的時候不會影響到圖像的清晰度。
Flash使用的就是矢量圖。其缺點就是無法表現顏色的細節變化。所以在PIL中沒有包含對這類圖像處理的模塊。不支持矢量圖像
位圖:
基本組成單元為像素。
通過這些像素的不同顏色排列,就構成了顏色豐富的圖像。當放大圖像,可以看到像素單元,也可能會失真。
這種圖像需要保存每個像素的內容,所以文件比較大。而且,其大小是隨着像素的增加而增加的。
但是由於采用了像素這樣微小的圖形單元來下顯示色彩,使得位圖可以表現豐富的顏色,更加逼真。在處理圖像的時候需要考慮到分辨率郵箱,這對最后的輸出很重要
常見位圖格式:
(1)BMP格式:
windows下的標准圖像文件格式。是很多圖像處理軟件的中間格式。其未進行壓縮,文件占用空間較大
(2)JPEG格式:
對圖像的視覺不敏感部分進行了有損壓縮,保持了其中主要的圖像特征。文件愛你相對較小。
JPEG2000可以實現漸進傳輸,先傳遞輪廓,再傳遞細節數據
(3)GIF格式:
針對網絡傳輸帶寬限制開發的一種圖片格式。。圖像中可以包含透明區域,同時可以存儲多幅靜態圖片而形成的連續的動畫。
壓縮比高,文件較小。但是只能儲存不超過256色的圖像
(4)PNG格式:
考慮了文件大小和圖像質量的關系。采用了無損壓縮方式進行壓縮。
使得圖像在保持質量的同時,減小了文件大小。還支持透明區域,使得其在網絡設計中也具有一定的優勢。
其他概念:
1.坐標:
PIL中采用的是笛卡爾坐標系,以左上點為(0,0),水平向右為x正,垂直向下為y正
2.像素
由於位圖中是采用像素來保存顏色,所以像素的大小就是指其水平方向和垂直方向上的像素個數,1600x1200表示長為1600像素,寬為1200像素的圖像大小。
3.顏色模式
顏色模式決定了圖像如何描述和重現圖像中的色彩。在顯示和打印輸出的時候會用到這個概念。
常見顏色模式有RGB,CMYK,灰度模式等,不同表達方式用在不同的領域。
一般在計算機上進行圖像處理都是使用RGB,加色法(顏色通道疊加產生顏色)。
印刷上多用CMKY,采用青,品紅,黃,黑四種油墨。減色法,通過色素合成后吸收光線來產生不同的顏色。
灰度顏色模式值包含灰度信息,不包含彩色信息。可以看做是只由一種顏色通道組成的,一般用8比特來表示顏色信息。
4.PIL支持的4中插值算法
(1)nearest 最近鄰插值方法,將會選擇輸入圖像中最近的圖像來處理 (2)bilinear 雙線性插值方法。將會對輸入的圖像選擇2x2的區域進行線性插值 (3)bicubic 雙立方插值方法。選擇輸入的圖像4x4區域進行立方插值 (4)antialias 通過高質量的采樣器作用在所有輸入圖像的像素上,從而得到輸出圖像的方法
圖像縮小可以選擇antialias方法,bilinear和bicubic更適用於等比例變換或者是圖像放大等操作。
圖像的基本處理
1.圖像的讀寫保存
from PIL import Image img1 = Image.open("1.jpg") #使用Image模塊中的open方法,從指定的圖像文件中獲取一個Image對象,出錯觸發錯誤 img2 = Image.Image() #構造函數定義一個空的圖像對象 print(img1,type(img1)) #根據文件判別Image對象 print(img2,type(img2)) #初始Image對象 img1.show() #顯示圖像 img1.save("hhh.png") #注意這里可以用來保存圖片,而且支持不同類型文件的轉換
#保存方法 # img1.save("6.png") #根據后綴名轉換格式,並且生成的文件含有文件名 # img1.save("6","png") #一個沒有后綴名的圖片,格式在save的第二個參數中指定
注意這里的show方法被調用的時候,PIL將會生成一個臨時文件,然后使用windows中的圖像處理工具顯示。效率極低。而且若是程序先退出,臨時文件會被回收,工具顯示會出錯
2.獲取圖像的信息
當生成了Image對象后,可以通過此Image對象來獲取關於此圖像文件的信息。包括分辨率,文件格式,大小,顏色模式,文件名,讀寫屬性等。對於構造函數生成的空文件對象,大部分操作不允許,因為其文件格式為NoneType
from PIL import Image img1 = Image.open("1.jpg") #使用Image模塊中的open方法,從指定的圖像文件中獲取一個Image對象,出錯觸發錯誤 img2 = Image.open("1.gif") #獲取文件尺寸大小 print(img1.size) print(img2.size) #獲取文件的顏色模式 print(img1.mode) #RGB print(img2.mode) #P 這是啥....也是一種顏色模式 #獲取文件顏色模式的通道 print(img1.getbands()) #('R',"G","B") print(img2.getbands()) #("P",) #{'dpi': (72, 72), 'jfif': 257, 'jfif_version': (1, 1), 'jfif_density': (1, 1), 'exif': b'Exif\x00\x00', 'jfif_unit': 0} #{'duration': 0, 'extension': (b'NETSCAPE2.0', 795), 'background': 0, 'version': b'GIF89a', 'loop': 0} #獲取文件的格式 print(img1.format) print(img2.format) #獲取文件的附加信息:字典對象 print(img1.info) print(img2.info) #值為1時,代表只讀,若是想對齊操作,需要先對齊拷貝 print(img1.readonly) print(img2.readonly)

# official modes "1": ("L", "L", ("1",)), "L": ("L", "L", ("L",)), "I": ("L", "I", ("I",)), "F": ("L", "F", ("F",)), "P": ("RGB", "L", ("P",)), "RGB": ("RGB", "L", ("R", "G", "B")), "RGBX": ("RGB", "L", ("R", "G", "B", "X")), "RGBA": ("RGB", "L", ("R", "G", "B", "A")), "CMYK": ("RGB", "L", ("C", "M", "Y", "K")), "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")), "LAB": ("RGB", "L", ("L", "A", "B")), "HSV": ("RGB", "L", ("H", "S", "V")),
3.顏色模式的轉換:
from PIL import Image img1 = Image.open("1.png") #使用Image模塊中的open方法,從指定的圖像文件中獲取一個Image對象,出錯觸發錯誤 #L:這是一種8位的灰度圖像,保留了原圖除顏色外的大部分圖像細節 img2 = img1.convert("L") img2.show() #灰色 #1:除了顏色外,對圖像本身像素也進行了修改 img3 = img1.convert("1") img3.show()
4.圖像裁剪和合成
使用Image類中的crop方法可以從圖像中獲取一個矩形空間。
注意:其裁剪是延時的,即只有當實際操作的時候,才會從圖像中獲取對應區域的數據。
裁剪
from PIL import Image img1 = Image.open("1.gif") #使用Image模塊中的open方法,從指定的圖像文件中獲取一個Image對象,出錯觸發錯誤 w,h = img1.size rec = (w/3,h/3,w*2/3,h*2/3) #圖片九等分中間的那部分 region = img1.crop(rec) region.show()
為避免對源圖像的操作,可以對其先進行拷貝。
合成:
from PIL import Image img1 = Image.open("1.png") #使用Image模塊中的open方法,從指定的圖像文件中獲取一個Image對象,出錯觸發錯誤 w,h = img1.size rec = (w/3,h/3,w*2/3,h*2/3) #圖片九等分中間的那部分 rec = tuple(map(int,rec)) region = img1.crop(rec) region = region.convert('L') #------------上面是獲取裁剪區域------------------------ #------------下面是開始合成圖像------------------------ img2 = Image.open("1.png") img2 = img2.copy() #拷貝源圖像 # rec = tuple(map(lambda x:x+10,rec)) img2.paste(region,(10,10)) #box是第二個參數,我們可以只定義左上頂點 img2.show()
設置合成時的透明度(遮罩層):
mask = region.point(lambda i:i<100 and 255) #當值為255代表不透明,為0代表完全透明 mask = mask.convert("1") img2.paste(im = region,box = (10,10),mask = mask)

""" If a mask is given, this method updates only the regions indicated by the mask. You can use either "1", "L" or "RGBA" images (in the latter case, the alpha band is used as mask). Where the mask is 255, the given image is copied as is. Where the mask is 0, the current value is preserved. Intermediate values will mix the two images together, including their alpha channels if they have them. """
也可以將圖像分解為多個顏色通道,來進行單獨處理
r,g,b = region.split() #分解為多個顏色通道 img2.paste(im = region,box = (10,10),mask = b) #img2.paste(im = region,box = (10,10),mask = r) #img2.paste(im = region,box = (10,10),mask = g)
使用merge方法合成
merge_im4 = Image.merge("RGB",(g,r,b)) #不同,將顏色轉變R->g G->r B->b merge_im5 = Image.merge("RGB",(r,g,b)) #原圖 merge_im4.save("mm4.png") merge_im5.save("mm5.png")
5.圖像的變換
縮放
img1 = Image.open("1.png") img2 = img1.resize((200,200)) #默認nearest img2.show()
上面resize不止可以縮小,還可以放大
但是thumbnail方法總是會得到一個不超過圖像自身尺寸大小的縮略圖,注意他是對源圖像進行設置。所以需要copy先拷貝源圖像
img1 = Image.open("1.png") #(400,380) img1.thumbnail((200,200)) #按最大的比例進行縮放(200,190) img1.save("2.png")
旋轉
img1 = Image.open("1.png") img2 = img1.rotate(-45) #負數代表順時針 img2.save("3.png") #大小不變,空區域為黑色
設置rotate參數expand,可以調整圖片大小,為真會調整大小去容納所有,默認為假
翻轉
img1 = Image.open("1.png") #使用Image模塊中的open方法,從指定的圖像文件中獲取一個Image對象,出錯觸發錯誤 # img2 = img1.transpose(Image.FLIP_LEFT_RIGHT) #左右翻轉 # img2 = img1.transpose(Image.FLIP_TOP_BOTTOM) #上下翻轉 # img2 = img1.transpose(Image.ROTATE_90) #逆時針90 # img2 = img1.transpose(Image.ROTATE_180) #逆時針180 img2 = img1.transpose(Image.ROTATE_270) #逆時針270 img2.save("3.png")
圖像處理的高級應用
1.圖像的通道操作ImageChopsticks模塊
填充內容
from PIL import Image import PIL.ImageChops as IC img1 = Image.Image() img1.mode = "RGB" img1.size = (300,300) img2 = IC.constant(img1,100) #像素值為100,鋪滿 img2.save("3.png")
圖像反色處理
from PIL import Image import PIL.ImageChops as IC img1 = Image.open("1.png") img3 = IC.invert(img1) #反色處理 img3.save("3.png")
其他常見的混合模式
lighter:亮化,返回兩個圖像對象中更亮的像素點
darker:暗化,返回更暗的點
difference:差值模式,返回兩個圖像的差值對象。
multiply:正片疊底模式,若與黑混合,則輸出黑,與白色不變
screen:屏幕模式。與上面的正片疊底模式相反
add:相加模式,對應像素相加
subtract:相減模式
from PIL import Image import PIL.ImageChops as IC img1 = Image.open("7.png") img2 = Image.open("5.png")
#亮化 IC.lighter(img1,img2).save("8.png") #是以img1為源,所以以img1的尺寸為准
注意:對於我們操作的圖像,其顏色模式必須一致
print(img2.mode,img1.mode)
#暗化 IC.darker(img1,img2).save("8.png")
#差值 IC.difference(img1,img2).save("8.png")
#正片疊底 IC.multiply(img1,img2).save("8.png")
#屏幕模式 IC.screen(img1,img2).save("8.png")
#相加模式 IC.add(img1,img2).save("8.png")
#相減模式 IC.subtract(img1,img2).save("8.png")
有遮罩效果
2.圖像的增強處理ImageEnhance模塊
含有色彩平衡,明亮度,對比度,銳度
在其模塊中都有一個公有接口enhance方法,其中一個參數factor,當其為1.0,不是保持源圖像的數據;較小,不是更少的色彩,較大,更多的色彩
調整色彩平衡Color
from PIL import Image import PIL.ImageEnhance as IE img1 = Image.open("7.png") en = IE.Color(img1) # en.enhance(0.0).save("9.png") #0.0黑白 # en.enhance(0.4).save("9.png") #0.4暗 # en.enhance(0.8).save("9.png") #0.8較亮 # en.enhance(1.0).save("9.png") #1.0正常 en.enhance(1.6).save("9.png") #1.6顏色更加深
調整明亮度Brightness
from PIL import Image import PIL.ImageEnhance as IE img1 = Image.open("7.png") en = IE.Brightness(img1) # en.enhance(0.0).save("9.png") #0.0全黑 # en.enhance(0.4).save("9.png") #0.4灰暗 # en.enhance(0.8).save("9.png") #0.8較亮 # en.enhance(1.0).save("9.png") #1.0正常 en.enhance(1.6).save("9.png") #1.6非常亮
調整對比度Contrast
from PIL import Image import PIL.ImageEnhance as IE img1 = Image.open("7.png") en = IE.Contrast(img1) # en.enhance(0.0).save("9.png") #0.0全灰 # en.enhance(0.4).save("9.png") #0.4灰暗 # en.enhance(0.8).save("9.png") #0.8較亮 # en.enhance(1.0).save("9.png") #1.0正常 en.enhance(1.6).save("9.png") #1.6非常亮
調整銳度Sharpness
from PIL import Image import PIL.ImageEnhance as IE img1 = Image.open("7.png") en = IE.Sharpness(img1) # en.enhance(0.0).save("9.png") #0.0模糊 # en.enhance(0.4).save("9.png") #0.4灰暗 # en.enhance(0.8).save("9.png") #0.8較亮 # en.enhance(1.0).save("9.png") #1.0正常 en.enhance(2.0).save("9.png") #2.0銳化
3.內置濾鏡ImageFilter
In the current version, kernels can only be applied to "L" and "RGB" images.
from PIL import Image import PIL.ImageFilter as IF img1 = Image.open("7.png") # img2 = img1.filter(IF.BLUR) #變模糊 # img2.save("9.png") # img2 = img1.filter(IF.CONTOUR) #黑白邊框素描 # img2.save("9.png") # img2 = img1.filter(IF.DETAIL) #變清晰 # img2.save("9.png") # img2 = img1.filter(IF.EDGE_ENHANCE) #邊緣明顯 # img2.save("9.png") # img2 = img1.filter(IF.EMBOSS) #灰色浮雕 # img2.save("9.png") img2 = img1.filter(IF.SHARPEN) #銳化 img2.save("9.png")
大多不易看出