python实现图片转字符画

1 :前言

       正式开始之前呢容我多比比几句。首先什么是字符画呢?对没错,就是字符组成的画!。。。呃有点直白。。。对没错就是这么直白。一开始是在b站上看到,当时这个东西是真的火很多很多人都在做,用各种东西播放badapple ,比如示波器啦,计算器啦液晶屏啦,继电器,工控机,单片机,STM32。。。只有你想不到的,没有大佬们做不到的。但是当时自己能力不足,直到最近在实验楼里再次看到这个东西,再次激发了我的斗志。come!上一下效果图。在这里插入图片描述在这里插入图片描述

2 : 用到的工具,实验环境

(1).ubuntu 16.04
(2).python3
(3).安装pillow(PIL)库(PIL 是一个 Python 图像处理库,是本课程使用的重要工具,使用下面的命令来安装)

$ sudo pip3 install --upgrade pip
$ sudo pip3 install pillow

(4).好像没有了。。。

3 : 好的我们开始

(1) 什么是字符画?
       首先我还是详细解释一下这个字符画这个东西,字符画是一系列字符的组合我们转换图片为字符的原理就是将一个个图片里面的像素用字符来代替,不同的字符来代替不同的颜色。也就是说字符种类越多,我们将来可以表现的颜色就会越多,我们看到的效果也就会更好
(2)什么是灰度值?
       灰度值:指黑白图像中点的颜色深度,范围一半0~255,所以黑白图片也称灰度图像。
(3)什么是RGB色彩?
       RGB色彩模式是工业界的一种颜色标准,是通过对红®、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。- 来自百度百科介绍

明白了这些我们对下面的内容便有了更好的掌握和了解。

一)处理命令行参数
我们首先使用 python 中的argparse 模块,处理命令行参数,目标是获取输入的图片路径、输出字符画的宽和高以及输出文件的路径。(Argparse___这里我准备单独写一篇博客可能是下下下。。。一篇博客)代码如下:

ps:关于Argparse模块的博客已经写好了。大家可以去看我的另一篇博客。
https://blog.csdn.net/qq_41661918/article/details/102470383

def parser_image():
    
    """命令行输入参数处理"""
    #创建一个解析对象
    parser = argparse.ArgumentParser()
	#添加参数
    parser.add_argument('file') #输入文件
    parser.add_argument('-o','--output')#输出文件
    parser.add_argument('--width',type = int, default = 90)#输出字符画宽
    parser.add_argument('--height',type = int, default = 45)#输出字符画高

    #获取参数
    args = parser.parse_args()
    return args
二)实现RGB——>灰度值——>字符

        刚才知道灰度值,RGB, 字符概念之后我们怎么才可以将RGB映射到灰度值上呢?首先我们得知道灰度值才能去想办法将RGB映射到灰度值上吧?怎么求呢?
        当然不用你去算了,已经有人帮我们算好了,我们只需要拿来用就行了。我们用到的是简化过后的 sRGB IEC61966-2.1公式。(注:这里大家不用管他,想了解的可以自行问度娘。)公式如下:

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

整数运算会更快一些因此也可以改为整数最后除以10000

好吧得到这个东西我们能干什么呢?

gray / 256 = x / len(ascii_char)

256的含义就是灰度值在0~255之间,一共有256种层次x就是我们想得到的对应的字符,而 len(ascii_char)就是待会用到的字符串的长度。我们在写完这个等比公式之后就应该知道x怎么求了吧?

gray = int(0.2126 * r + 0.7152*g + 0.0722 * b)
x = gray / 256 * len(ascii_char)
当然我们需要注意的是在将x当下标返回时要强制转化一下,转为整数。

对应代码部分:

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

ps:我们要用到的70个字符

def get_char(r,g,b,alpha = 255):

	"""将256灰度映射到70个字符上"""
  	if alpha == 0:
  		return ' '
  	length = len(ascii_char)
  	gray = int(0.2126 * r + 0.7152*g + 0.0722 * b)
  	return ascii_char[int(gray/256*length)]

--------->getpixel 返回4个参数 即(R(red), G(green), B(blue), A(alpha))<----------
alpha来命名是源于经典的线性插值方程αA + (1-α)B所用的就是这个希腊字母。
alpha通道一般用作不透明度参数

(注意 alpha 值为 0 的时候表示图片中该位置为空白: alpha 给的默认值是255)

三)处理图片
  1. 首先使用 PIL 的 Image.open 打开图片文件,获得对象 im
  2. 使用 PIL 库的 im.resize()
    【ps:这个函数img.resize((width, height),Image.ANTIALIAS)
    第二个参数:
    Image.NEAREST :低质量
    Image.BILINEAR:双线性
    Image.BICUBIC :三次样条插值
    Image.ANTIALIAS:高质量)】
    调整图片大小对应到输出的字符画的宽度和高度,注意这个函数第二个参数使用Image.NEAREST,表示输出低质量的图片。
  3. 遍历提取图片中每行的像素的 RGB 值,调用 getchar 转成对应的字符
  4. 将所有的像素对应的字符拼接在一起成为一个字符串 txt
  5. 打印输出字符串 txt
  6. 如果执行时配置了输出文件,将打开文件将 txt 输出到文件,如果没有,则默认输出到 output.txt 文件

这个过程中需要注意的是调用 getchar 时候的参数是通过 PIL 库的 getpixel 获取的,见如下代码:

char = get_char(*im.getpixel((j,i)))

其中 im.getpixel((j,i)) 获取得到坐标 (j,i) 位置的 RGB 像素值(有的时候会包含 alpha 值),返回的结果是一个元组,例如 (1,2,3) 或者 (1,2,3,0)。我们使用 * 可以将元组作为参数传递给 get_char,同时元组中的每个元素都对应到 get_char 函数的每个参数。(ps:这里值得注意的是在用for循环进行遍历时 j 相当于x坐标,i相当于y坐标,一次im.getpixel(j,i))

该部分的代码实现如下:

def main():
    args = parser_image()
    
    IMG = args.file

    WIDTH = args.width
    
    HEIGHT = args.height

    OUTPUT = args.output
    im = Image.open(IMG)
    im = im.resize((WIDTH,HEIGHT),Image.NEAREST)

    txt = ""
    for i in range(HEIGHT):
        for j in range(WIDTH):
            txt += get_char(*im.getpixel((j,i)))
        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)


if __name__ == '__main__':
        main()
四 :学会该图片大家也可以自己想一想如何改视频简单提醒一下 “视频是由一帧一帧。。。。” 聪明的你是不是想到了什么?下一篇我将会分享badapple怎么实现字符画动画的效果。python图片转字符画实现动画效果

附上完整代码如下,在下 溜了溜了~~~~:

from PIL import Image
import argparse

ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
def get_char(r,g,b,alpha = 256):

    """将256灰度映射到70个字符上"""

    if alpha == 0:

        return ' '
    length = len(ascii_char)
    gray = int(0.2126 * r + 0.7152*g + 0.0722 * b)

    unit = 256*1.0/length
    return ascii_char[int(gray/unit)]
    
    """ gray = int(0.2126 * r + 0.7152*g + 0.0722 * b)
    
    return ascii_char[int(gray/256*length)]

    """
def parser_image():
    
    #命令行输入参数处理
    parser = argparse.ArgumentParser()

    parser.add_argument('file') #输入文件
    parser.add_argument('-o','--output')#输出文件
    parser.add_argument('--width',type = int, default = 90)#输出字符画宽
    parser.add_argument('--height',type = int, default = 45)#输出字符画高

    #获取参数
    args = parser.parse_args()
    return args
    

def main():
    args = parser_image()
    
    IMG = args.file

    WIDTH = args.width
    
    HEIGHT = args.height

    OUTPUT = args.output
    im = Image.open(IMG)
    im = im.resize((WIDTH,HEIGHT),Image.NEAREST)

    txt = ""
    for i in range(HEIGHT):
        for j in range(WIDTH):
            txt += get_char(*im.getpixel((j,i)))
        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)


if __name__ == '__main__':
        main()
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值