Image模块应用实例之彩色图像转黑白图像

Python算法之旅

共 4583字,需浏览 10分钟

 ·

2022-07-07 17:21

说在前面

PIL库的Image模块是浙教版《信息技术必修一数据与计算》第三章的重要内容,教材中好几个“实践与体验”案例都涉及到Image模块,答题卡填涂识别项目更是Image模块的经典应用实例

我在备课过程中发现这些案例都非常精彩,但由于课时的限制,不可能全部在课堂上呈现,于是打算把他们整理出来,作为拓展阅读资料,让学生在课后自主学习。

“Image模块应用实例分析”是一个专题系列,展示了我在备课过程中的一些思考和教学思路,有不成熟之处,敬请各位老师批评指正。

项目实践过程
(一)了解图像模式

图像处理库PIL有九种不同模式:1、L、P、RGB、RGBA、CMYK、YCbCr、I、F。其特征描述如下:

模式
特点
“RGB”
RGB色彩模式,图像中的每个像素都分成R、G、B三个基色分量(通道),使用3*8个bit表示,利用这3个通道的变化和相互叠加来表现各种颜色。
“L”
灰色图像,每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。它只有一个通道,可以显示为从暗黑到亮白的灰度。
从“RGB”转换为“L”模式公式:L = R*0.299 + G*0. 587 + B*0.114。
“1”
二值图像,每个像素用8个bit表示。它相当于只取灰度图像中0和255两种值,分别代表纯黑和纯白。
“P”
8位彩色图像,每个像素用8个bit表示,其对应彩色值是按照调色板查询出来的。
“RGBA”
32位彩色图像,它的每个像素用32个bit表示,其中24bit表示R、G、B三个通道;另外8bit表示alpha通道,分别用0和255表示完全透明和完全不透明。
“CMYK”
32位彩色图像,即印刷四分色模式,利用色料的三原色混色原理,加上黑色油墨,共计四种颜色混合叠加,形成所谓“全彩印刷”。
“YCbCr”
24位彩色图像,彩色视频格式。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。
“I”
32位整型灰色图像,每个像素用32个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。从“RGB”转换为“I”模式公式:I = R*0.299 + G*0. 587 + B*0.114。
“F”
32位浮点型灰色图像,每个像素用32个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。从“RGB”转换为“F”模式公式:F = R*0.299+G*0. 587+B*0.114


(二)使用Image内置方法转换图像模式

我们今天主要学习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)

则程序输出结果为:

JPEG (357, 287) RGB

JPEG (357, 287) L

分别输出了图像的格式、大小(宽、高)和模式。

然后我们使用convert()方法来获取不同模式的图像,例如下列代码能够将彩色图像boy_RGB.jpg转换成灰度图像boy_L.jpg:

#【示例程序2】from PIL import Imageimg = Image.open('boy_RGB.jpg')img2 = img.convert("L") # 转换成“L”模式灰度图像img2.save("boy_L.jpg")

当convert()方法的参数mode=”1”时,可以将"L"或“RGB”图像转换为二值黑白图像,其参数dither默认值为None(改成1也有相同效果),表示使用弗洛伊德-斯坦伯格抖动来近似原始图像的亮度级别。如果dither=0,表示抖动为无,则所有大于128的值设置为255(白色) ,所有其他值设置为0(黑色)。效果图如图3和图4所示。

下面的代码可以实现将彩色图像boy_RGB.jpg转换成黑白图像boy_10.jpg(无抖动效果)和boy_11.jpg(有抖动效果)功能:

#【示例程序3】from PIL import Imageimg = Image.open('boy_RGB.jpg')img2 = img.convert("1", dither=0) #参数dither=0表示无抖动效果img2.save("boy_10.jpg")img3 = img.convert("1", dither=1) #参数dither=1表示有抖动效果img3.save("boy_11.jpg")

(三)使用自定义函数将彩色图像转换成黑白图像

除了直接使用convert()方法将彩色图像转换成黑白图像,我们也可以利用图像模式转换原理,设置自定义函rgb_bw()来实现转换功能。

首先根据由“RGB”转换为“L”模式的公式:L = R*0.299 + G*0. 587 + B*0.114,计算出每个像素点的灰度值gray,再判断gray与阈值的关系,若gray小于阈值,设置为黑色,否则设置为白色。阈值通常取值为128,也可以根据需要设置不同的阈值。

#【示例程序4】from PIL import Image# 将“RGB”彩色图像转换为二值黑白图像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 * B             if gray < 128: # 小于阈值,设置为黑色                img.putpixel((i, j), (0, 0, 0))             else:                img.putpixel((i, j), (255, 255, 255))    return img        img = Image.open('boy_RGB.jpg')img2 = rgb_bw(img)img2.save('boy_bw_128.jpg')

设置不同的阈值,获得不同黑白图像的效果图如图5、6、7所示。


(四)更高效的修改像素点元素值方法

示例程序4中使用img.getpixel((i, j))方法来获取像素点(i, j)的RGB颜色值,其结果返回一个包含RGB三原色的元组,例如红色(255,0,0);使用img.putpixel((i, j), (0, 0, 0))方法来为像素点(i, j)设置颜色,(0, 0, 0)表示黑色,你也可以设置其他的不同颜色。

这个两个方法的名称都很长,不便于记忆,效率也不高。更常见的做法是先使用pix = img.load()方法获取整个图像所有的像素点颜色,再利用pix[i, j]来表示像素点(i, j)的颜色值,这样既可以读取其颜色值,也可以设置其颜色值,方便且高效。参考代码如下:

#【示例程序5】from PIL import Image
# 将“RGB”彩色图像转换为二值黑白图像def 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 * B if gray < 128: # 小于阈值,设置为黑色 pix[i, j] = (0, 0, 0) else: pix[i, j] = (255, 255, 255) return img img = Image.open('boy_RGB.jpg')img2 = rgb_bw(img)img2.save('boy_bw_128.jpg')

(五)使用matplotlib模块生成黑白图像

教材中使用numpy和matplotlib模块来处理图像,也可以达到相同的效果,参考代码如下:

#【示例程序6】from PIL import Imageimport numpy as npimport matplotlib.pyplot as plt
# 打开图像并转换成数字矩阵img = Image.open('boy_RGB.jpg')img.show()img = np.array(img.convert('L'))# 调整每个像素的RGB值rows, cols = img.shape # 图像尺寸分别赋值for i in range(rows): # 依次取每个像素的坐标 for j in range(cols): if img[i, j] < 128: # 小于阈值,设置为黑色 img[i, j] = 0 else: img[i, j] = 1# 生成新的图像plt.figure('lena') # 指定当前绘图对象plt.imshow(img, cmap='gray') # 显示灰度图像plt.axis('off') # 关闭图像坐标plt.savefig('boy_bw_2.jpg') # 保存图片plt.show() # 弹出图片窗口

拓展思考

教材提供的代码导入了numpy模块,并将图像转换成数字矩阵,然后通过二重循环遍历所有像素点,实现了将灰度图像转换成黑白图像的功能。这种算法虽然简单易懂,但是没有充分发挥numpy模块快速处理数组的优势,效率不高。

如果你熟悉numpy模块,就没有必要编写二重循环来修改像素点的颜色值了,完全可以调用numpy模块的where()方法,直接一行语句搞定。

你知道该怎么做吗?

需要本文word文档、源代码和拓展思考答案的,可以加入“Python算法之旅”知识星球参与讨论和下载文件,Python算法之旅”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。

我们专注Python算法,感兴趣就一起来!

相关优秀文章:

阅读代码和写更好的代码

最有效的学习方式

Python算法之旅文章分类

浏览 47
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报