图像在计算机中的表示
图像在计算机中的采用RGB加色模型显示的。在计算机内部,图像拥有4个属性
- R: 红色
- G: 绿色
- B: 蓝色
- A: 透明度(alpha)
- RGB: 取值范围 0 − 255 0-255 0−255,数值越大,颜色越深
- A: 取值范围 0 − 255 0-255 0−255,0表示完全透明,255表示完全不透明
任意一种颜色,在计算机中都可以用4个数字表示。
from PIL import ImageColor
# 查看各种颜色的RGBA值
print(ImageColor.getcolor('red', 'RGBA'))
# (255, 0, 0, 255)
# 黑色表示没有任何颜色,所以RGB值都是0
print(ImageColor.getcolor('BLACK', 'RGBA'))
# (0, 0, 0, 255)
print(ImageColor.getcolor('blue', 'RGBA'))
# (0, 0, 255, 255)
# 白色代表RGB全部的混合
print(ImageColor.getcolor('white', 'RGBA'))
# (255, 255, 255, 255)
不同的颜色,RGB三个数值之和肯定不同,因此就可以建立起RGB之和关于字符集合中每个字符的一一映射关系。但实际上,由于RGB之和最大为765,而输入的ASCII字符远远没有这么多。所以,需要对RGB之和进行同等比例缩小映射。
还有,对于RGB之和的数值,不能简单地将三者相加,需对RGB各个数值分配权重再相加。借助灰度值公式可以得到比较恰当的RGB转灰度值结果
0.2126 * r + 0.7152 * g + 0.0722 * b
可以计算每个像素点的灰度值之后,就需要对整个图像所有像素点进行处理。在计算机中,图像可以理解为一个二维数组(矩阵),数组每个值是对于某个像素点的RGB值。因此,只需要遍历计算数组中每个值就行了。
处理图像
Python中的提供了PIL
模块来实现对图像的处理
from PIL import Image
load_image = Image.open('./test.png')
print(load_image.size) #获取图像得到宽和高
获取图像二维数组中每个坐标的RGBA的值
width, height = load_image.size
image_RGBA = []
for row in range(height):
row_RGBA = []
for col in range(width):
# getpixel((x, y))获取坐标的RGBA值
row_RGBA.append(image.getpixel((row, col)))
image_RGBA.append(row_RGBA.copy())
row_RGBA.clear()
print(image_RGBA)
# [[(255, 255, 255, 0), (255, 255, 255, 0), (255, 255, 255),...
接下来计算图像的灰度值,并将其等比映射到ASCII字符集中
# 计算灰度值
gray_value = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
# 计算放缩比例
ratio = 256 / len(ascii_char)
# 返回索引所对应的ASCII
ascii = ascii_char[int(gray_value / ratio)]
输出ASCII字符图像
将灰度值映射到ASCII字符集的数值,视为ASCII字符集的索引值index
。打印时,依次读取ascii_char[index]
的再输出即可。
ascii_print = ""
for row in ascii_list:
for col in row:
ascii_print += ascii_char[col]
ascii_print += '\n'
print(ascii_print)
重构代码
整个处理过程分三步走
- 读取图像每个像素RGB值
- 计算图像每个像素对应的灰度值,并得到映射字符集合的索引
- 根据索引值获取字符,保存并输出
重构一下整个代码,并添加保存字符图像文本的功能。
运行结果
对应稍微“复杂”的图像,转成ASCII文本显示效果并不好。因为每种颜色都会计算出一个灰度值,然后对应一个字符,这样会显得密密麻麻的。只有颜色单调,且图像轮廓清晰,有无太多背景色的图像,效果比较好。