首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Python制作字符画(pillow,numpy的使用)

Python制作字符画(pillow,numpy的使用)

作者头像
GeekLiHua
发布2025-01-21 19:53:54
发布2025-01-21 19:53:54
3900
举报
文章被收录于专栏:JavaJava

Python制作字符画

简介:本文讲解,如何使用python制作字符画,这里使用的是pillow和numpy这两个python的库。

字符画: 简单的字符画是利用字符的形状代替图画的线条来构成简单的人物、事物等形象,它一般由人工制作而成;复杂的字符画通常利用占用不同数量像素的字符代替图画上不同明暗的点,它一般由程序制作而成。

效果展示

这个是我的胡桃老婆,我用她来给大家演示一下。

编码

安装相关的库

首先安装pillow库

再安装numpy库

如果pycharm下载的速度过慢,可以尝试下面的命令的方式,进行下载。

代码语言:javascript
复制
pip install pillow -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
代码语言:javascript
复制
pip install numpy -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
进行编码
初始代码

原理分析: 将图片中的每个像素点,转换成对应的ASCII字符。

这里我用我的老婆,胡桃给大家演示一下

这是第一版的代码,详细的过程已经在代码中写下了注释,原理并不是特别困难,主要是一个pillow和numpy的使用。

代码语言:javascript
复制
from PIL import Image
import numpy as np

def ascill_art(file):
    # 打开图片文件
    im = Image.open(file)

    # 通过灰度覆盖这张图片 降低图片的亮度
    im = im.convert("L")

    # 对图片进行降采样
    sample_rate = 0.15
    new_im_size = [int(x * sample_rate) for x in im.size]
    im = im.resize(new_im_size)

    # 将图片转换成一个numpy字符
    im = np.array(im)

    # symbols中定义了 我们字符画中的所有字符
    # 按照字符亮度升序排列
    # 文件转换的时候会不断的查询这个symbols字符集
    symbols = np.array(list(" .-vM"))

    # 设置这个字符集合的取值范围的最大和最小值[0,max_symbol_index)
    im = (im - im.min()) / (im.max() - im.min()) * (symbols.size - 1)

    # 完成字符的转换
    ascii = symbols[im.astype(int)]
    lines = "\n".join(("".join(r) for r in ascii))
    print(lines)

if __name__=="__main__":
    ascill_art("imgs/img.png")

运行结果: 还是比较大的,我们放到这个文本中观察一下。

放到文档里面之后的样子,是不是很好看了。

分析结果我们发现,做个图片还会被拉长了,希望解决这个问题,我们需要进行一点点的修改。

我们需要下载一个新的字符集,然后使用这段代码,对这个问题进行解决

代码语言:javascript
复制
 # 这段代码可以处理图片拉伸的情况
    font = ImageFont.truetype("Font/SourceCodePro-Black-1.ttf")
    aspect_ratdio = font.getsize("x")[0] / font.getsize("x")[1]

    new_im_size = np.array(
        [im.size[0] * sample_rate, im.size[1] * sample_rate * aspect_ratdio]
    ).astype(int)
第二版

文件结构

代码语言:javascript
复制
from PIL import Image
from PIL import ImageFont
import numpy as np

def ascill_art(file):
    # 打开图片文件
    im = Image.open(file)

    # 通过灰度覆盖这张图片 降低图片的亮度
    im = im.convert("L")

    # 对图片进行降采样
    sample_rate = 0.15

    # 这段代码可以处理图片拉伸的情况
    font = ImageFont.truetype("Font/SourceCodePro-Black-1.ttf")
    aspect_ratdio = font.getsize("x")[0] / font.getsize("x")[1]

    new_im_size = np.array(
        [im.size[0] * sample_rate, im.size[1] * sample_rate * aspect_ratdio]
    ).astype(int)

    # 用新的的图片大小resize之前的
    im = im.resize(new_im_size)

    # 将图片转换成一个numpy字符
    im = np.array(im)

    # symbols中定义了 我们字符画中的所有字符
    # 按照字符亮度升序排列
    # 文件转换的时候会不断的查询这个symbols字符集
    symbols = np.array(list(" .-vM"))

    # 设置这个字符集合的取值范围的最大和最小值[0,max_symbol_index)
    im = (im - im.min()) / (im.max() - im.min()) * (symbols.size - 1)

    # 完成字符的转换
    ascii = symbols[im.astype(int)]
    lines = "\n".join(("".join(r) for r in ascii))
    print(lines)

if __name__=="__main__":
    ascill_art("imgs/img.png")

运行结果

第三版

分析第二版,我们发现还是优缺点,这个版本是,灰色的,没有彩色高亮显示,这个问题如何解决了。 解决问题就是,在设置图片为灰度之前,先保留一个原来图片的彩色副本。 然后我这里还解决了如何保存字符画为图片的问题,详细可以看代码,特别是如何设置这个图片的存储位置的方法。

完整代码

代码语言:javascript
复制
from PIL import Image
from PIL import ImageFont, ImageDraw
import numpy as np

def ascill_art(file):
    # 打开图片文件
    im = Image.open(file)
    
    # 存放图片文件的位置
    file2 = file.split("/")[0] + "/"

    # 对图片进行降采样
    sample_rate = 0.15

    # 这段代码可以处理图片拉伸的情况
    # 这个truetype可以有第二个参数 也就是指定字符的大小
    font = ImageFont.truetype("Font/SourceCodePro-Black-1.ttf")
    aspect_ratdio = font.getsize("x")[0] / font.getsize("x")[1]

    new_im_size = np.array(
        [im.size[0] * sample_rate, im.size[1] * sample_rate * aspect_ratdio]
    ).astype(int)

    # 用新的的图片大小resize之前的
    im = im.resize(new_im_size)

    # 再进行图片的灰度之前,先保留一个图片的副本
    im_color = np.array(im)

    # 通过灰度覆盖这张图片 降低图片的亮度
    im = im.convert("L")

    # 将图片转换成一个numpy字符
    im = np.array(im)

    # symbols中定义了 我们字符画中的所有字符
    # 按照字符亮度升序排列
    # 文件转换的时候会不断的查询这个symbols字符集
    symbols = np.array(list(" .-vM"))

    # 设置这个字符集合的取值范围的最大和最小值[0,max_symbol_index)
    im = (im - im.min()) / (im.max() - im.min()) * (symbols.size - 1)

    # 完成字符的转换
    ascii = symbols[im.astype(int)]

    # 创建一个字符图片
    letter_size = font.getsize('x')
    im_out_size = new_im_size * letter_size
    bg_color = "black"
    im_out = Image.new("RGB", tuple(im_out_size), bg_color)
    draw = ImageDraw.Draw(im_out)

    # Draw text
    y = 0
    for i, line in enumerate(ascii):
        for j, ch in enumerate(line):
            color = tuple(im_color[i, j])
            draw.text((letter_size[0] * j, y), ch, fill=color, font=font)
        y += letter_size[1]

    lines = "\n".join(("".join(r) for r in ascii))

    im_out.save(file2  + "ascii.png")
    print(lines)

if __name__=="__main__":
    ascill_art("imgs/img.png")

最后的运行结果 一张完美的我老婆的字符画。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Python制作字符画
    • 效果展示
    • 编码
      • 安装相关的库
      • 进行编码
      • 初始代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档