python实现图片转字符画

一.介绍什么是图片转字符画

字符画是一系列字符组合成的文本,看起来就像一幅画一样,如图1所示。

手动绘制肯定是不现实的,但是我们可以使用python来实现图片转字符画如下面的示意图一般:

 这样转换出来的效果还是不错的自我感觉良好。

二.实现过程

首先认清,一张图片是由一个一个像素点组成的,我们转换成字符画就需要将其每个像素点转换成合适的字符。

1.彩色图片我们一般是先转换成黑白色的再进行转换

有两种方案可以实现彩色图片转为灰度图片

方案一:利用灰度公式将像素的 RGB 值映射到灰度值

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

方案二:利用PIL库所带的convert(“L”)函数转化图片

2.将图片与自己准备的字符集建立映射,也就是使灰度值和字符集建立映射

字符集可以自己设置,也可以在网上找,以下给出两种方案:

方案一:

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

方案二:

code_list = list("qwertyuiop[]asdfghjkl;'zxcvbnm,./`~!@#$%^&<()*+{}:"?> |")

两种字符集我都使用过,在我的代码和测试图片下是方案一的字符集转换出来图片更加真实

3.将转换后的字符串保存进txt文档中

三、代码实现

1.完整代码如下:

class ASCIIart(object):
    def __init__(self, file):
        """
        传入参数为文件名进行一个赋值方便后续调用,codelist是字符集,用于替换每像素点的灰度值
        count计算字符集的长度
        :param file:
        """
        self.file = file
        self.codelist = """$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. """
        self.img = Image.open(file)
        self.count = len(self.codelist)

    def get_char(self, r, g, b, alpha=256):
        """
        用来处理灰度值和字符集的关系
        :return:
        """
        if alpha == 0:
            return " "
        length = self.count  # 获取字符集的长度
        gary = 0.2126 * r + 0.7152 * g + 0.0722 * b  # 将RGB值转为灰度值
        unit = 265 / length
        return self.codelist[int(gary / unit)]

    def get_new_img(self):
        """
        用于处理图片是转换的字符画不至于失真
        :return:
        """
        w, h = self.img.size
        print(f"图片的原始宽度和高度为:{w},{h}")
        if not w or not h:
            pass
        else:
            if w <= 299 or h <= 299:
                w = int(w / 1.4)
                h = int(h / 1.4)
            if 300 <= w <= 500 or 300 <= h <= 500:
                w = int(w / 2)
                h = int(h / 2)
            if 500 < w < 1000 or 500 < h < 1000:
                w = int(w / 3.8)
                h = int(h / 3.8)
            if 1000 <= w or 1000 <= h:
                w = int(w / 10)
                h = int(h / 10)
            print(f"修改后图片的宽度和高度为:{w},{h}")
            """
            Image.ANTIALIAS: 高质量
            Image.NEAREST: 低质量
            Image.BILINEAR: 双线性
            Image.BICUBIC: 三次样条插值
            """
            im = self.img.resize((w, h), Image.ANTIALIAS)
            return im

    def get_str_img(self, im, output=None):
        """
        获取字符串图片
        :return:
        """
        w, h = im.size
        txt = ""
        for i in range(h):
            for j in range(w):
                txt += self.get_char(*im.getpixel((j, i)))
            txt += "\n"
        # 字符画输出到文件
        if output:
            with open(output, "w") as file:
                file.write(txt)
        else:
            with open("output/output3.txt", "w") as file:
                file.write(txt)


if __name__ == '__main__':
    file = "image/thing.jpg"
    img = ASCIIart(file)
    im = img.get_new_img()
    img.get_str_img(im)

 2.各个函数(方法)的讲解

    def __init__(self, file):
        """
        传入参数为文件名进行一个赋值方便后续调用,codelist是字符集,用于替换每像素点的灰度值
        count计算字符集的长度
        :param file:
        """
        self.file = file
        self.codelist = """$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. """
        self.img = Image.open(file)
        self.count = len(self.codelist)

 __init__其实是面向对象一个类中的内置方法,用于给类的属性传递参数

file图片文件的名字

codelist用于存储字符集

img是PIL库中Image实例出来的对象,调用open方法打开文件file

count用于保存字符集的长度

    def get_char(self, r, g, b, alpha=256):
        """
        用来处理灰度值和字符集的关系
        :return:
        """
        if alpha == 0:
            return " "
        length = self.count  # 获取字符集的长度
        gary = 0.2126 * r + 0.7152 * g + 0.0722 * b  # 将RGB值转为灰度值
        unit = 265 / length # 由于灰度值有256,但是字符集只有70多个
        return self.codelist[int(gary / unit)]

此函数用来获取每个灰度值对应的字符

由于灰度值有256,但是字符集只有70多个,所以需要相邻的几个灰度值对应相同的字符

 gary得到的结果就是灰度值,返回值实际上就是一个字符

    def get_new_img(self):
        """
        用于处理图片是转换的字符画不至于失真
        :return:
        """
        w, h = self.img.size
        print(f"图片的原始宽度和高度为:{w},{h}")
        if not w or not h:
            pass
        else:
            if w <= 299 or h <= 299:
                w = int(w / 1.4)
                h = int(h / 1.4)
            if 300 <= w <= 500 or 300 <= h <= 500:
                w = int(w / 2)
                h = int(h / 2)
            if 500 < w < 1000 or 500 < h < 1000:
                w = int(w / 3.8)
                h = int(h / 3.8)
            if 1000 <= w or 1000 <= h:
                w = int(w / 10)
                h = int(h / 10)
            print(f"修改后图片的宽度和高度为:{w},{h}")
            """
            Image.ANTIALIAS: 高质量
            Image.NEAREST: 低质量
            Image.BILINEAR: 双线性
            Image.BICUBIC: 三次样条插值
            """
            im = self.img.resize((w, h), Image.ANTIALIAS)
            return im

get_new_img函数的作用是裁剪图片将其变为合适的尺寸,这样转换出来的字符画更接近真实

 not w or not h这里是为了将损坏的图片检查出来

Image中的size方法可以直接返回这张图片的宽和高

Image.ANTIALIAS: 高质量
Image.NEAREST: 低质量
Image.BILINEAR: 双线性
Image.BICUBIC: 三次样条插值

这几个方法可以修改图片的质量

返回值是一个新的im对象

    def get_str_img(self, im, output=None):
        """
        获取字符串图片
        :return:
        """
        w, h = im.size
        txt = ""
        for i in range(h):
            for j in range(w):
                txt += self.get_char(*im.getpixel((j, i)))
            txt += "\n"
        # 字符画输出到文件
        if output:
            with open(output, "w") as file:
                file.write(txt)
        else:
            with open("output/output3.txt", "w") as file:
                file.write(txt)

get_str_img此函数用于遍历黑白图片的每一个像素点,并使用Image中的getpixel方法获得其r,g.b和alpha(并不是每个像素点都有)三个值

使用for循环的嵌套,将每个像素点对应的字符获取从到并拼接起来,一行一行拼接。

最后将txt这个字符串输出到文件中即可

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值