Python字符画生成详解
- 字符画的原理
- 方案设计
-
- 设计思路
- 整体流程
- 代码实现
- 成品展示
- 提示
字符画的原理
顾名思义,字符画就是由字符组成的画
日常我们在网上看到的彩色图片一般有3个颜色通道:R(红)、G(绿)、B(蓝)。你没看错,就是初中物理你学过的那个“色光三原色,以此构成颜色鲜明的图片。
而当绘图的颜色只有一种的情况下,如素描的时候,则通过线条颜色的密集程度不同进行明暗区分,即灰度值区分。
同理,对于字符画,我们也可以根据字符笔画的密集程度进行字符画的明暗区分,以此实现对字符画各部分的灰度区分。
方案设计
设计思路
首先,每个字符中线条的密集程度进行排序,用于生成字符画时的明暗区分。这里我采用的字符是“MNHQ$OC?7>!:-; “,各位可以更具自己的需求进行更改。
基础的字符画是单色画,既然如此,我们则没必要针对彩色图片进行方案设计,可以将图片将图片整体修改为灰色,根据灰色图片中每个像素点的灰度值将对应像素替换成对应字符。
考虑到一般情况下,一个字符的高度大于它的宽度,并且每行字符之间都会有固定的间隙,为了保证最终成品的与原图的宽高比,可以将转换后的灰图的宽度进行拉伸,用于抵消由于字符宽高不一致和行间间隙造成的误差。

然后,生成一个和灰图相同的数组
pixels,遍历
pixels每个像素,根据该像素的灰度获取对应字符并进行拼接,最后返回拼接后字符串。
整体流程
- 设置字符串chars用于区分不同灰度。
- 通过PIL(需安装pillow)的Image包读取img并进行图片宽度拉伸。
- 将img转换为灰图。
- 使用numpy生成与img相同的数组pixels。
- 定义空串result。
- 循环遍历pixels像素点,获取该像素灰度在chars中对应的字符,并将该字符拼接至result,一行遍历完成后拼接换行符。
- 返回result。
代码实现
import numpy as np
from PIL import Image
def chars_image(path, result_path, widen, chars):
img = Image.open(path) # 获取图片
img_width, img_height = img.size # 获取图片原始宽高
# img_width, img_height = img_width // 10, img_height // 10 #根据需求进行压缩
img_width = int(img_width * widen) # 图片宽度拉伸,拉伸程度根据图片大小自行修改
img = img.resize((img_width, img_height), Image.ANTIALIAS) # 修改图片尺寸
img = img.convert("L") # 将图片转换为灰图
pixels = np.array(img) # 生成img的copy数组pixels
N = len(chars)
step = 256 // N
result = ""
for i in range(img_height):
for j in range(img_width):
index1 = pixels[i][j] // step # 获取灰度对应字符
result += chars[index1] # 字符拼接
result += "\n" # 一层遍历完成后添加换行符
with open(result_path, "w", encoding="utf-8") as f:
f.write(result)
if __name__ == '__main__':
chars_image(path="./img.png", result_path="./result.txt", widen=1.8, chars="MNHQ$OC?7>!:-; ")
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
成品展示
原图
成品图
提示
如果遇到以下这种由于字符宽度不一致导致成品效果差的情况。
将显示字体修改为Courier或Courier New后缩小即可。
修改后