ErikTse Runtime

  • 首页 / Home
  • | 算法学习 / Algorithm
    • 所有 / All
    • 简单 / Easy
    • 中等 / Medium
    • 困难 / Hard
  • | 技术分享 / Technology
    • 所有 / All
    • 网络技术 / NetWork
    • 资源共享 / Resource
    • 项目实践 / Event
Keep Going.
温故而知新.
  1. 首页
  2. 技术分享
  3. 正文

[Python入门项目]字符画(PIL)

2022年6月13日 428点热度 1人点赞 2条评论

字符画就是将一幅图片用字符来表示,保存为一个txt文本文档,主要的效果如图。

效果图

安装PIL / install Pillow

我们需要用到Pthon的PIL第三方库,PIL是一个python的强大的图形库。

PIL在Python2.7的时候就停止维护了,在Python3中维护使用的PIL叫作Pillow,可以将这俩看作同一个库。

我这里使用的Pycharm平台,在左上角设置 - 文件 - Python解释器 - 加号 - 搜索pillow - 选择第一个并点击左下角安装。

Python解释器界面
安装Pillow第三方库

在安装完成后引入PIL库并命名为Image(这只是一个编程习惯,并不一定要重新命名)。

#引入第三方库
from PIL import Image

读取图片并转换成灰度图片 / open & convert

准备一张图片(这张图片用了超分辨率算法进行增强)。

首先用一个变量来存下原图片,这里用im来表示,将其按照一定比例缩小,因为字符普遍高度比宽度更大,所以注意缩小比例时高度应该缩小更多以保证字符画的比例正常,这个需要根据图片原本比例和字符宽高比例调整,这里就不那么严谨了,写一个差不多的比例就好了。

im = Image.open('src.png')
k = 3 # 缩小倍数,需要保证 k >= 1
im = im.resize((im.width // k,im.height // (k + 2)), Image.Resampling.LANCZOS)# 最高精度转换
im = im.convert('L')    # 转为黑白图, 每个像素都一个灰度值,从0到255, 0是黑色, 255是白色

open参数为一个字符串表示图片地址。这里需要提前将图片放到和py文件同一个目录下保证相对路径正确。

resize参数第一个是一个二元组(宽度,高度),第二参数为转换模式,Image.Resampling.LANCZOS表示最高精度转换。

convert参数一般有'1'(二值图,非黑即白), 'L'(灰度图片,每一个像素的灰度0 ~ 255), 'P'(8位彩色), 'RGBA'(32位彩色), 'CMYK'等。

设定字符集 / char_set

字符集的作用是,将不同灰度的像素点用不同的字符去代替。比如灰度越高(越黑)的像素点就用@$等单位覆盖率高的字符,而越白的像素点就用. / ( ) 空格等单位覆盖率低的字符去表示。

这里这个字符集出处请见文末参考文档。

# 创建字符集
char_set = '''$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. '''

遍历图片并构造出字符文本 / construct the text

通过双重循环来遍历图片的每一个像素点,再根据像素点的灰度值来选择一个字符加入到字符串后面即可。

for i in range(im.height):
    for j in range(im.width):
        gray = im.getpixel((j, i)) # 一个二元组,这里的坐标(x, y)和遍历的顺序相反,所以要用 (j ,i)
        if isinstance(gray, tuple): # 如果这个灰度值不是一个整数而是一个三元组,就算出一个整型来表示灰度值
            gray = int(0.2 * gray[0] + 0.6 * gray[1] * 0.2 * gray[2])
        buf += get_char(gray)
    buf += '\n'

写入文件 / wirte to file

# 将buf内容写入pic.txt
open('pic.txt', 'w').write(buf)

完整代码 / complete code

from PIL import Image

#设定字符集
char_set = '''$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. '''

#打开图片
im = Image.open('src.png')
k = 2 # 缩小倍数,需要保证 k >= 1,如果倍数为1,需要调整下一行的 k + 2 改成 k 即可
im = im.resize((im.width // k,im.height // (k + 2)), Image.Resampling.LANCZOS)# 最高精度转换
im = im.convert('L')    # 转为黑白图, 每个像素都一个灰度值,从0到255, 0是黑色, 255是白色


def get_char(gray: int)->str: # 将灰度值对应到字符集中
    return ' ' if gray > 240 else char_set[int(gray / 257.0 * len(char_set))]


buf = '' # 最终结果将存入 buf 再保存到 pic.txt 中

#遍历图片
for i in range(im.height):
    for j in range(im.width):
        gray = im.getpixel((j, i)) # 一个二元组,这里的坐标(x, y)和遍历的顺序相反,所以要用 (j ,i)
        if isinstance(gray, tuple): # 如果这个灰度值不是一个整数而是一个三元组,就算出一个整型来表示灰度值
            gray = int(0.2 * gray[0] + 0.6 * gray[1] * 0.2 * gray[2])
        buf += get_char(gray)
    buf += '\n'

# 将buf内容写入pic.txt
open('pic.txt', 'w').write(buf)

注意最后要用浏览器打开txt文件,否则显示比例会不协调。

参考文档:python实战练手项目---字符画及其原理 | 酷python (coolpython.net)

本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可
标签: pillow python 开源 有趣 第三方库 项目
最后更新:2022年7月9日

Eriktse

19岁,性别未知,ACM-ICPC现役选手,ICPC亚洲区域赛银牌选手,CCPC某省赛铜牌蒟蒻,武汉某院校计算机科学与技术专业本科在读。

点赞
< 上一篇
下一篇 >

文章评论

  • Eriktse

    Python3为什么这么牛逼!为什么为什么为什么!还要什么自行车c++ :drooling:

    2022年6月13日
    回复
  • ChrisKim

    hhhh,要是效率高点就好了,我之前用 Pillow 写的原神抽卡,一张图要渲染大概 3 秒才结束,完全不够过瘾。

    2022年6月19日
    回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    取消回复

    订阅本站
    Loading
    文章目录
    • 安装PIL / install Pillow
    • 读取图片并转换成灰度图片 / open & convert
    • 设定字符集 / char_set
    • 遍历图片并构造出字符文本 / construct the text
    • 写入文件 / wirte to file
    • 完整代码 / complete code

    COPYRIGHT © 2022 ErikTse Runtime. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang

    赣ICP备2022001555号-1

    赣公网安备 36092402000057号