Image模塊應(yīng)用實例之彩色圖像轉(zhuǎn)黑白圖像
說在前面
PIL庫的Image模塊是浙教版《信息技術(shù)必修一數(shù)據(jù)與計算》第三章的重要內(nèi)容,教材中好幾個“實踐與體驗”案例都涉及到Image模塊,答題卡填涂識別項目更是Image模塊的經(jīng)典應(yīng)用實例。
我在備課過程中發(fā)現(xiàn)這些案例都非常精彩,但由于課時的限制,不可能全部在課堂上呈現(xiàn),于是打算把他們整理出來,作為拓展閱讀資料,讓學(xué)生在課后自主學(xué)習(xí)。
“Image模塊應(yīng)用實例分析”是一個專題系列,展示了我在備課過程中的一些思考和教學(xué)思路,有不成熟之處,敬請各位老師批評指正。

圖像處理庫PIL有九種不同模式:1、L、P、RGB、RGBA、CMYK、YCbCr、I、F。其特征描述如下:
(二)使用Image內(nèi)置方法轉(zhuǎn)換圖像模式
我們今天主要學(xué)習(xí)RGB彩色圖像、灰度圖像和黑白圖像。
首先我們來查看Image對象的基本屬性,例如已知有彩色圖像boy_RGB.jpg和灰度圖像boy_L.jpg,運行下列代碼:
#【示例程序1】from PIL import Imageimg = Image.open('boy_RGB.jpg')print(img.format, img.size, img.mode)img2 = Image.open('boy_L.jpg')print(img2.format, img2.size, img2.mode)
則程序輸出結(jié)果為:
JPEG (357, 287) RGB
JPEG (357, 287) L
分別輸出了圖像的格式、大?。▽?、高)和模式。


然后我們使用convert()方法來獲取不同模式的圖像,例如下列代碼能夠?qū)⒉噬珗D像boy_RGB.jpg轉(zhuǎn)換成灰度圖像boy_L.jpg:
#【示例程序2】from PIL import Imageimg = Image.open('boy_RGB.jpg')img2 = img.convert("L") # 轉(zhuǎn)換成“L”模式灰度圖像img2.save("boy_L.jpg")

當(dāng)convert()方法的參數(shù)mode=”1”時,可以將"L"或“RGB”圖像轉(zhuǎn)換為二值黑白圖像,其參數(shù)dither默認(rèn)值為None(改成1也有相同效果),表示使用弗洛伊德-斯坦伯格抖動來近似原始圖像的亮度級別。如果dither=0,表示抖動為無,則所有大于128的值設(shè)置為255(白色) ,所有其他值設(shè)置為0(黑色)。效果圖如圖3和圖4所示。

下面的代碼可以實現(xiàn)將彩色圖像boy_RGB.jpg轉(zhuǎn)換成黑白圖像boy_10.jpg(無抖動效果)和boy_11.jpg(有抖動效果)功能:
#【示例程序3】from PIL import Imageimg = Image.open('boy_RGB.jpg')img2 = img.convert("1", dither=0) #參數(shù)dither=0表示無抖動效果img2.save("boy_10.jpg")img3 = img.convert("1", dither=1) #參數(shù)dither=1表示有抖動效果img3.save("boy_11.jpg")
(三)使用自定義函數(shù)將彩色圖像轉(zhuǎn)換成黑白圖像
除了直接使用convert()方法將彩色圖像轉(zhuǎn)換成黑白圖像,我們也可以利用圖像模式轉(zhuǎn)換原理,設(shè)置自定義函rgb_bw()來實現(xiàn)轉(zhuǎn)換功能。
首先根據(jù)由“RGB”轉(zhuǎn)換為“L”模式的公式:L = R*0.299 + G*0. 587 + B*0.114,計算出每個像素點的灰度值gray,再判斷gray與閾值的關(guān)系,若gray小于閾值,設(shè)置為黑色,否則設(shè)置為白色。閾值通常取值為128,也可以根據(jù)需要設(shè)置不同的閾值。
#【示例程序4】from PIL import Image# 將“RGB”彩色圖像轉(zhuǎn)換為二值黑白圖像def rgb_bw(img):for i in range(img.width):for j in range(img.height):R, G, B = img.getpixel((i, j))# 計算像素點顏色的灰度值gray = 0.299 * R + 0.587 * G + 0.114 * Bif gray < 128: # 小于閾值,設(shè)置為黑色img.putpixel((i, j), (0, 0, 0))else:img.putpixel((i, j), (255, 255, 255))return imgimg = Image.open('boy_RGB.jpg')img2 = rgb_bw(img)img2.save('boy_bw_128.jpg')
設(shè)置不同的閾值,獲得不同黑白圖像的效果圖如圖5、6、7所示。

(四)更高效的修改像素點元素值方法
示例程序4中使用img.getpixel((i, j))方法來獲取像素點(i, j)的RGB顏色值,其結(jié)果返回一個包含RGB三原色的元組,例如紅色(255,0,0);使用img.putpixel((i, j), (0, 0, 0))方法來為像素點(i, j)設(shè)置顏色,(0, 0, 0)表示黑色,你也可以設(shè)置其他的不同顏色。
這個兩個方法的名稱都很長,不便于記憶,效率也不高。更常見的做法是先使用pix = img.load()方法獲取整個圖像所有的像素點顏色,再利用pix[i, j]來表示像素點(i, j)的顏色值,這樣既可以讀取其顏色值,也可以設(shè)置其顏色值,方便且高效。參考代碼如下:
from PIL import Imagedef rgb_bw(img):pix = img.load()for i in range(img.width):for j in range(img.height):R, G, B = pix[i, j]gray = 0.299 * R + 0.587 * G + 0.114 * Bif gray < 128:pix[i, j] = (0, 0, 0)else:pix[i, j] = (255, 255, 255)return imgimg = Image.open('boy_RGB.jpg')img2 = rgb_bw(img)img2.save('boy_bw_128.jpg')
(五)使用matplotlib模塊生成黑白圖像
教材中使用numpy和matplotlib模塊來處理圖像,也可以達(dá)到相同的效果,參考代碼如下:
#【示例程序6】from PIL import Imageimport numpy as npimport matplotlib.pyplot as plt# 打開圖像并轉(zhuǎn)換成數(shù)字矩陣img = Image.open('boy_RGB.jpg')img.show()img = np.array(img.convert('L'))# 調(diào)整每個像素的RGB值rows, cols = img.shape # 圖像尺寸分別賦值for i in range(rows): # 依次取每個像素的坐標(biāo)for j in range(cols):if img[i, j] < 128: # 小于閾值,設(shè)置為黑色img[i, j] = 0else:img[i, j] = 1# 生成新的圖像plt.figure('lena') # 指定當(dāng)前繪圖對象plt.imshow(img, cmap='gray') # 顯示灰度圖像plt.axis('off') # 關(guān)閉圖像坐標(biāo)plt.savefig('boy_bw_2.jpg') # 保存圖片plt.show() # 彈出圖片窗口
教材提供的代碼導(dǎo)入了numpy模塊,并將圖像轉(zhuǎn)換成數(shù)字矩陣,然后通過二重循環(huán)遍歷所有像素點,實現(xiàn)了將灰度圖像轉(zhuǎn)換成黑白圖像的功能。這種算法雖然簡單易懂,但是沒有充分發(fā)揮numpy模塊快速處理數(shù)組的優(yōu)勢,效率不高。
如果你熟悉numpy模塊,就沒有必要編寫二重循環(huán)來修改像素點的顏色值了,完全可以調(diào)用numpy模塊的where()方法,直接一行語句搞定。
你知道該怎么做嗎?
需要本文word文檔、源代碼和拓展思考答案的,可以加入“Python算法之旅”知識星球參與討論和下載文件,“Python算法之旅”知識星球匯集了數(shù)量眾多的同好,更多有趣的話題在這里討論,更多有用的資料在這里分享。
我們專注Python算法,感興趣就一起來!
相關(guān)優(yōu)秀文章:
