26 - 打造专属字符画
本帖最后由 不二如是 于 2022-7-8 17:38 编辑在线讲解:
https://www.bilibili.com/video/BV1HT4y1K7DY?p=29
作为一名程序员都应该拥有一副自己的字符画,用字符代替线条来构建图像。
这次我们就通过代码实现将指定图像变成“字符画”。
先观察一下这个序列:“#!@O0CF?>3-”。
可以看到每个字符的留白是不一样的,我们就可以利用这一点实现字符画的明暗效果。
这里我们要先说明两个概念:灰度值和 RGB。
灰度值:
指黑白图像中点的颜色深度,范围一般从 0 到255,白色为 255,黑色为 0,故黑白图片也称灰度图像。
RGB:
RGB 色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。
正常情况下,我们可以通过下面的换算公式,将 RGB 值转为灰度值:
gray = 0.2126 * r + 0.7152 * g + 0.0722 * b
除了这种方式外,我们还可以直接用 Pillow 图像库将我们传入的图像转为灰度图像,然后调整为我们需要的图像尺寸。
没有安装的读者记得自己去安装:
pip3 install pillow
根据各个像素点的灰度值生成字符数据,并保存到本地 txt 中。
先来导入 Pillow 库的 Image 模块,注意在 Python3 中该库的名字用 Python Imaging Librar 的缩写 PIL:
from PIL import image
创建主程序 myPaint(),然后从程序中打开 FishC.jpg 图片:
照片也可以自己准备:
def myPaint():
img = Image.open('FishC.jpg')
Image.open() 方法用于打开指定路径的图像文件。
由于我们将图片直接和脚本放在同个文件中,就不需要指定图片所在位置的完整路径:
如果图片放在 E 盘中的 Images 文件夹中,路径就是:
img = Image.open('E:\\Images\\FishC.jpg')
或者:
img = Image.open(r'E:\Images\FishC.jpg')
接下来我们调整图片尺寸为 50*48
width, height = 50, 48
img = img.resize(width,height)
由于生成的字符画最后要在文本中显示,各行之间以及字符本身的大小不同,效果就不同。
resize() 方法通过制定宽高参数重新调整图像大小,这里要注意该方法需传入元组类型的参数。
然后就可以将图像转为“灰度”了:
img = img.convert('L')
convert() 方法通过制定的颜色模式参数 'L' 将图像图像的颜色模式。
'L' 表示灰度图像,'RGB' 真彩色图像,'CMYK' 表示出版图像。
由于 Image 对象的 open(),resize(),convert() 方法返回相同类型的对象,就可以用“链式写法”将他们写在一行内:
img = Image.open('FishC.jpg').resize((width,height)).convert('L')
接下来就是重点了,根据灰度图像各个像素的灰度值生成字符画。
我们肯定先要获得各个像素的灰度值,就需要从左到右,从上到下全方位获取,然后将灰度值转为不同的字符。
按照上面的描述,获取过程就需要循环嵌套:
for y in range(height):
for x in range(width):
text += getchar(img.getpixel((x,y)))
text += '\n'
getpixel() 通过指定 x 和 y 坐标读取图像某个未知的像素颜色值。
此时我们已经将图像转为灰度图像,因此这里返回的就是灰度值。
代码中 getchar() 用于把一个灰度值转为一个字符,方便我们进行判断。
判断部分稍后来实现,现在假设已完成, text 中存放的就是根据灰度值转换得到的字符。
我们可以将结果存入本地文件:
final = open('myPaint.txt','w')
final.write(text)
final.close()
open() 根据指定的文件名创建一个可写的文本文件,并返回一个文件对象。
write() 用于将指定的字符串变量中的内容写入文本文件中。
最后用 close() 将文本文件关闭。
创建 getchar() 实现当灰度值小于 128 的部分用 “¥” 代替,大于部分用空格表示:
def getchar(gray):
return '¥' if gray<128 else' '
然后激活程序入口:
if __name__ == '__main__':
myPaint()
运行看结果:
源码:**** Hidden Message *****
一开始我们有说过字符本身的明暗程度不一样,“M-NH$OC>?3:;” 是一串效果比较好的序列。
我们还可以将 256 个灰度值与这些字符建立关系,优化 getchar():
asciiNice = list('M-NH$OC>?3:;')
def getchar(gray):
unit = 256 / len(asciiNice)
return asciiNice
效果:
最后视觉上我们看图会觉得被拉长了,这是为什么呢?
这是因为咱字符的宽度跟高度通常都是不一样的,要不然你看到的字符就都会是个胖墩儿。
这个我们可以在调整图片比例的时候,给它的高度再减少一些:
def myPaint():
#获取原图高度
width, height = Image.open('FishC.jpg').convert('L').size
#增加缩放系数
img = Image.open('FishC.jpg').convert('L').resize((int(width*0.5),int(height*0.25)))
text = ''
for y in range(img.height):
for x in range(img.width):
text += getchar(img.getpixel((x,y)))
text += '\n'
final = open('myPaint.txt','w')
final.write(text)
final.close()
完整代码留给你们当课后作业啦! {:10_327:} 学习学习{:10_332:} {:5_95:} 开始能快速看了 拿来做头像? 是否
{:10_254:} 学习了
{:10_256:} 学习学习!!! {:10_277:} 学习 哇 憨憨学不会啊 {:10_256:}{:10_256:}{:10_256:} 111
页:
[1]