图片:“给你五十行代码把我变成字符画!” 程序:“太多了,一半都用不完!”

举报
灰小猿 发表于 2021/08/16 08:44:32 2021/08/16
【摘要】 利用pillow模块处理,用20多行Python代码将普通图片转为字符画操作@TOC哈喽,努力赚钱买生发水的大灰狼又来了,今天和大家分享一个简单又好玩的Python项目–“图片转字符画”。废话不多说,先上一个效果图迷惑一下众生。没错的,图片转字符画就是将我们平常所看到的的图片根据像素RGB值和灰度值传化成一个个字符串的过程。嗯…听起来有些费脑子喔。没关系,且听大灰狼为小伙伴一一分解。. 像素...

利用pillow模块处理,用20多行Python代码将普通图片转为字符画操作

@TOC

哈喽,努力赚钱买生发水的大灰狼又来了,今天和大家分享一个简单又好玩的Python项目–“图片转字符画”。废话不多说,先上一个效果图迷惑一下众生。

在这里插入图片描述

没错的,图片转字符画就是将我们平常所看到的的图片根据像素RGB值和灰度值传化成一个个字符串的过程。

嗯…听起来有些费脑子喔。没关系,且听大灰狼为小伙伴一一分解。

.

像素RGB值

什么是像素RGB值?

其实就像我们平常所看到的所有图片,无论是彩色照还是黑白照,其实它们都是有色彩的,更加神奇的是,我们肉眼所看到的所有色彩几乎都是由红(Red)、绿(Green)、蓝(Blue)经过不同深度的调色后得到的,而RGB色彩模式就是是工业界的一种颜色标准,是通过对红®、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的。

所以RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。所以也可以说,我们所看到的所有具有色彩的图片都是由这三种颜色调出来的。

而对于字符画,顾名思义是一系列字符的组合,我们可以把字符看作是比较大块的像素,一个字符能表现一种颜色,就像我们刚才所看到的那张图片转成字符画之后,画中包含着各种不同层次的字符,所以字符的种类越多,可以表现的颜色也越多,图片也会更有层次感。

那么小伙伴们可能就会问了,我们是要转换一张彩色的图片,这么多的颜色,要怎么对应到只有一种颜色而且还包括那么多字符的的字符画上去?

哈哈,不知道了吧?这里就要介绍灰度值的概念了。来来来,科普一下!

.

灰度值计算

灰度值:指黑白图像中点的颜色深度,范围一般从0到255,白色为255,黑色为0,故黑白图片也称灰度图像。

所以我们可以使用灰度值公式将像素的 RGB 值映射到灰度值,也就是下面这个公式:(注意这个公式是简化过的,真正的计算公式会复杂些)

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

这样就好办了,我们可以创建一个不重复的字符列表,然后用每一个字符表示一种颜色,灰度值小(暗)的用列表开头的符号表示,灰度值大(亮)的用列表末尾的符号表示。

注意!重点来了!敲黑板!!!

我们知道。单从黑色到白色,颜色深度的范围就是0-255,也就是说这一共有256个不同深浅的颜色,那我们如果想要将每一种颜色以不同的字符表示出来,那岂不是需要256个不同的字符嘛?

哈哈,我觉得也是,去找256个不同的字符写的你的程序里面组成一个字符串,想想都刺激,但是你会去这么做嘛?我想不会吧?

所以我们只需要想一种办法,让颜色深度相近的灰度值用不同的符号表示即可,所以我们可以定义一个存放不同字符的字符串,用来表示不同的色彩的字符。在这里定义的这个字符串的长度是70。

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

.

灰度值映射字符函数

之后我们只需要定义一个函数,将我们需要转化成字符画的图片的每一个像素找到与其相对应的字符并返回即可。

该函数如下,传入的参数是图片上某一点处的像素值,同时还有一个透明度参数:

#将256灰度映射到70个字符上
def get_char(r,g,b,alpha = 256):
    #alpha为透明度
    # 判断 alpha 值,为0表示全透明
    if alpha == 0:
        return ' '

    # 获取字符集的长度,这里为 70
    length = len(ascii_char)
    # 将 RGB 值转为灰度值 gray,灰度值范围为 0-255
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)

    # 灰度值范围为 0-255,而字符集只有 70
    # 需要进行如下处理才能将灰度值映射到指定的字符上
    #防止当灰度值为255时,输出的第70个字符超出列表索引,所以需要将(255+1)
    unit = (255.0 + 1)/length

    # 返回灰度值对应的字符
    return ascii_char[int(gray/unit)]

当我们写好像素映射字符串的函数方法之后,我们就可以对不同的像素获取到不同的字符表示了。

.

图片导入及尺寸设置

那么接下来就是我们应该如何获取图片上某一点处的像素了。这个时候我们需要调用pillow库,这个库的作用就是对图片进行基本的处理,在这里我们需要使用的是pillow库下的Image类,使用Image下的resize方法,我们可以对图片进行缩放,并设置输出的图片质量。

哈哈,以大灰狼自己经过图像动漫化处理后的照片为例,

在这里插入图片描述

进行图片缩放和输出质量设置

IMG = 't01b2a945701805d7f1.jpg'      #设置图片文件
WIDTH = 150     #设置字符画的宽
HEIGHT = 80     #设置字符画的高
im = Image.open(IMG)
im = im.resize((WIDTH,HEIGHT), Image.NEAREST)

.

遍历图片获取字符

之后可以调用Image.getpixel()方法,给其传入坐标参数就可以返回该坐标处的像素值,值得注意的地方是,如果这个坐标处的像素是具有透明属性的,那么还会返回alpha透明度参数,这就是为什么我们在映射字符串函数方法的参数中传入透明度参数并进行判断的原因。

#将 (j,i) 坐标的 RGB 像素转为字符后添加到 txt 字符串
txt += get_char(*im.getpixel((j,i)))

现在我们要做的就是对该尺寸的图片进行横向和纵向的坐标遍历,获取到每一个坐标点处映射的字符,并将其在存储在我们设定的存放图片字符串的列表中即可。

#遍历图片中的每一行
for i in range(HEIGHT):
    # 遍历该行中的每一列
    for j in range(WIDTH):
        # 将 (j,i) 坐标的 RGB 像素转为字符后添加到 txt 字符串
        txt += get_char(*im.getpixel((j,i)))
    # 遍历完一行后需要增加换行符
    txt += '\n'

.

字符画输出和导入文件

最后将该字符列表在屏幕输出或者存放到文本文件中,为了可以更好的看到字符画的效果,在这里大灰狼建议将该字符列表存放到一个文本文件中。

OUTPUT = 'output5.txt'      #设置存放字符画的文本文件
#保存到文本文件
with open(OUTPUT,'w') as f:
    f.write(txt)

将图片转字符画处理后保存在文本文件中,我们可以在文本文件中找到被字符化后的照片了。

在这里插入图片描述

好了,到这里图片转字符画的过程就基本结束了。

最后附上完整源码,除去注释最后不到25行,使用的小伙伴只需要将程序最上面的图片路径修改成自己的图片即可!

#-*- coding=utf-8 -*-

from PIL import Image

IMG = 't01b2a945701805d7f1.jpg'      #设置图片文件
WIDTH = 150     #设置字符画的宽
HEIGHT = 80     #设置字符画的高
OUTPUT = 'output5.txt'      #设置存放字符画的文本文件
ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")    #设置显示的字符集

#将256灰度映射到70个字符上
def get_char(r,g,b,alpha = 256):
    #alpha为透明度
    # 判断 alpha 值,为0表示全透明
    if alpha == 0:
        return ' '

    # 获取字符集的长度,这里为 70
    length = len(ascii_char)
    # 将 RGB 值转为灰度值 gray,灰度值范围为 0-255
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)

    # 灰度值范围为 0-255,而字符集只有 70
    # 需要进行如下处理才能将灰度值映射到指定的字符上
    #防止当灰度值为255时,输出的第70个字符超出列表索引,所以需要将(255+1)
    unit = (255.0 + 1)/length

    # 返回灰度值对应的字符
    return ascii_char[int(gray/unit)]

if __name__ == '__main__':

    # 打开并调整图片的宽和高
    im = Image.open(IMG)
    im = im.resize((WIDTH,HEIGHT), Image.NEAREST)

    # 初始化输出的字符串
    txt = ""

    # 遍历图片中的每一行
    for i in range(HEIGHT):
        # 遍历该行中的每一列
        for j in range(WIDTH):
            # 将 (j,i) 坐标的 RGB 像素转为字符后添加到 txt 字符串
            txt += get_char(*im.getpixel((j,i)))
        # 遍历完一行后需要增加换行符
        txt += '\n'
    # 输出到屏幕
    print(txt)
    with open(OUTPUT,'w') as f:
        f.write(txt)

==觉得不错记得点赞关注哟!==

==同时你也可以关注我的微信公众号“灰狼洞主”,回复 “Python笔记”获取Python从入门到精通笔记分享和常用函数方法速查手册!==

在这里插入图片描述

==大灰狼期待与你一同进步!==

在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。