一、所需库

PIL:python的一个图形处理库

os:python的一个标准库,提供操作系统功能的一些函数

二、思路

我们都知道图片都是由一个一个的像素点组成的(如下图所示),每个像素点又由三种颜色R红色、G绿色、B蓝色各自按0到255组合而成,颜色所代表的数字越大,这个颜色在这个像素点中越亮,反之越暗,比如白色的RGB值为(255,255,255),黑色的RGB值为(0,0,0)。RGB一共有256×256×256=16777216种组合!

如果我们将图片变为灰度图

看起来是不是像黑白图片,但是在灰度图中其实不止有纯黑纯白这两种颜色,灰度图的像素在黑色和白色中间还有许多过渡的颜色,分为256阶,0到255,数字越大越亮,越小越暗,因为灰度图的像素只用一个整数表示,所以一个像素就只有256种可能,那样对于图片转为字符画来说那将变得非常容易。

我们可以列出一串字符串表示灰度值从暗到亮的像素(最后一个字符为空格)

$#%@&MNBEFRWYLIkbtj?*984532menocvzst{}[]1|()<>=+~-;:i^"'.

这个没有固定数量与排序,不一定要非常多个,不过如果排列得当且数量多一些,最后呈现出来的字符画会更加精细一些。

看到这里原理已经非常地明显了,将每个像素点按灰度值的大小选择相对黑白像素密集程度的字符,并按原图片的像素顺序排序,这样字符画就可以出现啦!那么,我们开始动手吧!

三、操作

首先第一步,我们要知道像素的灰度值,我们平时用到的图片基本上都是用RGB表示像素的,不知道灰度值怎么办呢?所以这里我们要引入一个公式:

Gray=R*0.299 + G*0.587 + B*0.114

这个公式可以让我们根据像素的RGB的值算出对应的灰度值,

比如纯黑色(0,0,0)的灰度值为0*0.299+0*587+0*0.114=0 ,

纯白色(255,255,255)的灰度值为255*0.299+255*0.587+255*0.114=255

灰度值的问题解决了,接下来我们来解决一下如何将灰度值转换为对应复杂程度的字符

def g2s(gray):#设置参数输入像素的灰度值
    pixel_str='''$#%@&MNBEFRWYLIkbtj?*984532menocvzst{}[]1|()<>=+~-;:i^"'. '''
    length=len(pixel_str)
    plus=255/length #字符之间的灰度区间
    str_gray=0 #str_gray表示字符所代表的灰度值
    for i in range(length):
        str_gray = str_gray + plus
        if gray <=str_gray:
            return pixel_str[i]

我们来测试一下

>>>g2s(255)
' '
>>>g2s(0)
'$'
>>>g2s(250)
'.'

可以了!不过这里需要注意一点的是plus的结果是浮点数,根据pixel_str的长度计算出浮点数,若你写的长度跟我的不一样就可能会出现plus全部加完了还是比255小的情况,从而导致函数无法输出结果,这时可以将str_gray的初始值设置为1就可以正常运行了。

下一步我们开始写主函数

from PIL import Image
import os

def img2str(img_path,save_path,num=0):
    txt_path=os.path.join(save_path,'img.txt')
    f=open(txt_path,'w')
    f.write('')
    f.close() #因为此目录有可能已有内容,所以先清空
    f=open(txt_path,'a') #a表示在文件的末尾添加

    im=Image.open(img_path)
    if num==0:#因为有些图片尺寸过于大,所以添加了一个修改大小的功能
        pass
    else:
        im=im.resize( ( int(im.size[0]/num),int(im.size[1]/num) ) )

    im=im.convert('RGB')#因为有些图片不是RGB格式的,所以我们先要将其转换成RGB格式
    for y in range(im.size[1]):
        for x in range(im.size[0]):
            r,g,b=im.getpixel((x,y))[0],im.getpixel((x,y))[1],im.getpixel((x,y))[2]
            gray=r*0.299+g*0.587+b*0.114 #代入公式
            s=g2s(gray) #我们在上面实现的函数
            f.write(s)
        f.write('\n') #每一行结束后换行
    f.close()

当然,还有更简单的写法

    im=im.convert('L')#直接将图片转换成灰度模式
    for y in range(im.size[1]):
        for x in range(im.size[0]):
            s=g2s(im.getpixel((x,y)))
            f.write(s)
        f.write('\n')
    f.close()

不过为了运用上面所学到知识,这里就用上面那一版。

四、测试

准备一张图片test.jpg

在文档末尾添加以下代码,根据你的路径修改参数

if __name__=='__main__':
    img2str(r'C:\\Users\\Felix\\Desktop\\test.jpg',r'C:\Users\Felix\Desktop',4)

运行程序,在桌面生成文件img.txt,打开查看,成功!如果你的字符画看起来很混乱的话,请将自动换行关闭。

总结

图片转字符画的讲解就到这里了,代表像素的字符串如果设置得合理的话,那么生成的字符画会更加地细致一些。你可以为这个程序打造一个gui界面,我之前就用过tkinter为这个程序写了一个简单的界面,你还可以用pyinstaller打包成exe文件,这样就可以和朋友们分享啦!

评论

Felix 管理员

2020博客第一篇文章

回复

  • 最新随笔

  • 对我来说,写东西很好的一点是,自己写的东西,后面基本都会再看,一遍或者很多遍。这样就可以很好地发现自己之前的漏洞,并看看现在有什么变化。
  • 前段时间应该是百度更新了页面结构,那个黑帽泛目录网站我也没有去更新代码,就导致了文章页没有相关推荐,没想到这时候谷歌开始收录了,而且效果还不错。其实之前在谷歌一直不收录的时候就有怀疑过没有尽头的相关推荐很可能是导致不收录的原因,不过也一直没有去管它,而这次误打误撞的收录也恰恰证实了这个想法。(btw,其实这个网站从出现固定链接开始叫泛目录应该不太准确)
  • 最近吉他谱网站iloveguitar上线了,这几天在填充一些内容花了一些时间,这个网站也是使用flask作为后端框架的,前端UI框架使用的是bootstrap4,喜欢吉他的小伙伴欢迎来这里逛一逛哟,有什么建议欢迎在留言板提一下哟。
  • 那个泛目录网站发布了几个星期了,百度没怎么来爬,收了一个首页,谷歌直接就不收了,倒是一个查外链的网站天天来爬(笑哭),还有建议一点就是泛目录还是用在有建站历史的域名比较好(因为已经过了审核期),新域名就尽量不要用了。
  • 刚刚又发了一篇,最近文章百度都不太收录,orz,哈哈
  • 之前那个用python做的静态资源服务器,我又发现了一大用处,现在我都用来在局域网里的不同电脑之间传输文件,真的好用哈哈
  • 今天交换到了博客有史以来第一条友情链接
  • 刚刚更新了一下博客,修复了一些bug,添加了一个项目页