用 Python 实现“连字成字” 写作“明天”读作“未来”
什么是“连字成字“,写作“明天”读作“未来”呢?先来看个示例,一看就明白了,
再比如,
有点意思吧,而且使用 Python 实现这个效果并不难,只需要 4 步,
- 将字符串(1 行 m 列的字符数组)转换成白底黑字的图片
- 将白底黑字的图片转换成 0、1 的二维数组,字符笔画经过的地方是 1,没有经过的地方是 0
- 在二维数组中 1 的位置上填上想要的汉字,0 的位置上填上空白字符,最终得到一个汉字的二维数组
- 将这个汉字的二维数组转换为白底黑字的图片
下面我们就来看一看每一步的 Python 代码。
第 1 步
我们先来看看如何将字符串转换为白底黑字的图片。
这一步要用到 Pillow 这个图像处理库。Pillow 派生自 Python Imaging Library(PIL),支持多种格式的图像文件。虽然原始的 PIL 已停止维护,但派生版的 Pillow 不但保留了 PIL 的易用性,还添加了诸多功能。
from PIL import Image, ImageDraw, ImageFont # pip install pillow
# 将字符的二维数组(共 rows 行,每行 cols 个字符)转换成白底黑字的图片
def char_matrix2img(str_matrix, char_size):
rows = len(str_matrix)
cols = len(str_matrix[0])
# 创建白底图片
img = Image.new('RGB', (char_size * cols , char_size * rows), 'white')
# 创建一个 ImageDraw 对象,用于在图像上绘制形状和文本
draw = ImageDraw.Draw(img)
# 黑体字
myfont = ImageFont.truetype("/System/Library/Fonts/STHeiti Medium.ttc", char_size)
# 逐一将字符“画”到图片上,
# 每个字符的左上角坐标为 (col * char_size, row * char_size)
# 颜色为黑色,字体为黑体
# fill=(0, 0, 0) 表示 RGB(0, 0, 0) 即黑色
for row in range(rows):
for col in range(cols):
char = str_matrix[row][col]
draw.text((col * char_size, row * char_size), char, fill=(0, 0, 0), font = myfont)
return img
我们定义了一个名为 char_matrix2img()
的函数,执行结果如下,
第 2 步
接下来,我们要将白底黑字的图片转换成 0、1 的二维数组,笔画经过的地方是 1,没有经过的地方是 0。
这一步其实可以很简单,只需要调用 Pillow 库中的 convert()
方法修改图像的模式为二值图像即可。只不过,在二值图像中,每个像素对应的值要么是 0(黑色)要么是 255(白色),而不是 0(没有笔画经过)或 1(有笔画经过)。为了将有无笔画经过和黑白对应起来,我们可以做一个简单的变换。
def img2binary_matrix(img):
# 将图片转换为二值矩阵
img = img.convert('1')
# 读取图片的宽和高
img_width, img_height = img.size
print(img_width, 'x', img_height)
result = []
for y in range(img_height):
row = []
for x in range(img_width):
row.append(0 if img.getpixel((x, y)) == 255 else 1)
result.append(row)
return result
该函数先读取图像的宽度和高度,然后遍历图像的每个像素,将像素值转换为 0 或 1,并存储在结果二维数组 result
中。转换结果如下(为了便于查看,这里将 0 替换成了▫️;将 1 替换成了◼️),
16 x 16
[▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️]
[▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️]
[▫️, ▫️, ◼️, ◼️, ◼️, ◼️, ▫️, ▫️, ◼️, ◼️, ◼️, ◼️, ◼️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ◼️, ▫️, ◼️, ▫️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ◼️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ▫️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ◼️, ◼️, ◼️, ◼️, ▫️, ◼️, ◼️, ◼️, ◼️, ◼️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ▫️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ◼️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ◼️, ▫️, ◼️, ◼️, ◼️, ◼️, ◼️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ▫️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ◼️, ◼️, ◼️, ▫️, ▫️, ◼️, ▫️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ▫️, ▫️, ◼️, ◼️, ◼️, ◼️, ▫️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️]
[▫️, ▫️, ◼️, ▫️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️, ▫️, ▫️, ◼️, ◼️, ▫️, ▫️]
[▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ◼️, ◼️, ▫️, ▫️, ▫️, ◼️, ◼️, ◼️, ▫️, ▫️]
[▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ◼️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️, ▫️]
第 3 步
得到了 0、1 的二维数组后,就可以用喜欢的汉字替换其中的 1,并用空白字符替换其中的 0 了。例如,我们反复用“未来”这两个字替换其中的 1,
def binary_matrix2char_matrix(binary_matrix, replace_str):
result = []
idx = 0
for row in binary_matrix:
char_row = []
for x in row:
if x == 0:
char_row.append(' ')
else:
char_row.append(replace_str[idx])
idx = (idx + 1) % len(replace_str)
result.append(char_row)
return result
result = binary_matrix2char_matrix(result, '未来')
最后一步
最后一步就很简单了,其实和第一步要解决的问题一模一样,还是将 n 行 m 列(第 1 步中是 1 行 m 列)的字符二维数组转换成白底黑字的图片。所以,只需要再次调用 char_matrix2img()
函数即可,只是这一次需要调小每个字符的大小。
从最初的字符串,到“连字成字”的完整步骤如下,
img = char_matrix2img([['明', '天']], 48)
img.show()
result = img2binary_matrix(img)
result = binary_matrix2char_matrix(result, '未来')
char_matrix2img(result, 16).show()
怎么样,挺有意思的吧。掌握了这个方法,不仅可以“连字成字”,还能“连字成图”,
赶紧发挥你的创意吧!
转载自:https://juejin.cn/post/7399564369229332518