python学习之手把手教你将图片变成黑白或彩色字符画(骚操作)


前言

字符画这个话题,似乎早在贴吧时代就已经被玩烂了。在百度图片随便一搜索,就能够看到非常多。然后在这个时代,会编程的人越来越多(尤其是 MATLAB,Python 等非常适合图像处理的脚本语言),类似的教程更是数不胜数。
在这里插入图片描述


一、字符画的实现原理

字符画是一系列字符的组合,我们可以把字符看作是比较大块的像素,一个字符能表现一种颜色(暂且这么理解吧),字符的种类越多,可以表现的颜色也越多,图片也会更有层次感。

问题来了,我们是要转换一张彩色的图片,这么多的颜色,要怎么对应到单色的字符画上去?这里就要介绍灰度值的概念了。

灰度值:指黑白图像中点的颜色深度,范围一般从0到255,白色为255,黑色为0,故黑白图片也称灰度图像
我们可以使用灰度值公式将像素的 RGB 值映射到灰度值:

gray = 0.2126 * r + 0.7152 * g + 0.0722 * b

这样就好办了,我们可以创建一个不重复的字符列表,灰度值小(暗)的用列表开头的符号,灰度值大(亮)的用列表末尾的符号。
在这里插入图片描述
在这里插入图片描述

二、黑白字符画实现代码

demo.py test.jpg -o outfile.txt --width 90 --height 90

代码如下(示例):

from PIL import Image
import argparse

def get_char(r,g,b,a=256):
    if a == 0:
        return ' '
    gray = 0.2126 * r + 0.7152 * g + 0.0722 * b
    length = len(ascii_str)
    unit = 256/length
    return ascii_str[int(gray/unit)]

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('file')  # 需要设置输入文件
    parser.add_argument('-o', '--output')  # 输出文件
    parser.add_argument('--width', type=int, default=80)  # 输出字符画宽
    parser.add_argument('--height', type=int, default=80)  # 输出字符画高

    # 获取参数
    args = parser.parse_args()
    IMG = args.file
    WIDTH = args.width
    HEIGHT = args.height
    OUTPUT = args.output

    ascii_str = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
    im = Image.open(IMG)
    im = im.resize((WIDTH,HEIGHT))
    txt = ''
    for i in range(HEIGHT):
        for j in range(WIDTH):
            txt += get_char(*im.getpixel((j,i))) # (r,g,b,a)
        txt += '\n'

    print(txt)
    #字符画输出到文件
    if OUTPUT:
        with open(OUTPUT,'w') as f:
            f.write(txt)
    else:
        with open("output.txt",'w') as f:
            f.write(txt)

三、彩色字符画生成

在这里插入图片描述

代码实现:

import numpy as np
import cv2
from PIL import Image, ImageFont, ImageDraw, ImageFilter
import random
from pathlib import Path
import time
from tqdm import tqdm

def color(
    input: str,
    output: str = None,
    rows: int = 100,
    alphabet='uppercase',
    background='origin7',
    out_height: int = None,
    scale: float = None,
):
    """output colorful text picture"""
    input_path = Path(input)
    # the original image
    origin = Image.open(input_path)
    width, height = origin.size
    print(f'input size: {origin.size}')
    # text amount of the output image
    text_rows = rows
    text_cols = round(width / (height / text_rows) * 1.25)  # char height-width ratio
    origin_ref_np = cv2.resize(
        np.array(origin), (text_cols, text_rows), interpolation=cv2.INTER_AREA
    )
    origin_ref = Image.fromarray(origin_ref_np)
    # font properties
    fontsize = 17
    font = ImageFont.truetype('courbd.ttf', fontsize)
    char_width = 8.88
    char_height = 11
    # output size depend on the rows and cols
    canvas_height = round(text_rows * char_height)
    canvas_width = round(text_cols * char_width)
    # a canvas used to draw texts on it
    canvas = get_background(background, origin, canvas_width, canvas_height)
    print(f'canvas size: {canvas.size}')
    # start drawing
    since = time.time()
    print(f'Start transforming {input_path.name}')
    draw = ImageDraw.Draw(canvas)
    charlist = get_alphabet(alphabet)
    length = len(charlist)

    for i in tqdm(range(text_cols)):
        for j in range(text_rows):
            x = round(char_width * i)
            y = round(char_height * j - 4)
            char = charlist[random.randint(0, length - 1)]
            color = origin_ref.getpixel((i, j))
            draw.text((x, y), char, fill=color, font=font)
    # resize the reproduct if necessary
    if out_height:  # height goes first
        canvas_height = out_height
        canvas_width = round(width * canvas_height / height)
        canvas = canvas.resize((canvas_width, canvas_height), Image.BICUBIC)
    elif scale:
        canvas_width = round(width * scale)
        canvas_height = round(height * scale)
        canvas = canvas.resize((canvas_width, canvas_height), Image.BICUBIC)
    # output filename
    if output:
        output_path = Path(output)
    else:
        output_path = input_path.with_name(
            f'{input_path.stem}_{canvas_width}x{canvas_height}_D{text_rows}_{background}.png'
        )
    canvas.save(output_path)

    print(f'Transformation completed. Saved as {output_path.name}.')
    print(f'Output image size: {canvas_width}x{canvas_height}')
    print(f'Text density: {text_cols}x{text_rows}')
    print(f'Elapsed time: {time.time() - since:.4} second(s)')





代码比较多,这里不做展示,需要的可以去下载。
python代码实现把图片生成字符画(黑白色、彩色图片)




总结

关于python代码学习手把手教你将图片变成字符画(骚操作)就介绍到这了,上述实例对大家学习使用Python有一定的参考价值,希望大家阅读完这篇文章能有所收获。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逃逸的卡路里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值