zoukankan      html  css  js  c++  java
  • 字符画生成

    字符画生成的种类

    • 生成图片:文字大小不一样大,像词云一样
    • 生成文字:纯文本

    图像的种类:

    • 黑白
    • 灰度图

    之前用Java实现过一个用字符写字符,那个只能画出黑白图像。本文用python PIL库实现纯文本字符画,它能够用字符画出灰度图像。

    原理如下:

    • 首先定义一个字符集,本程序使用ASCII码中的可打印字符:32~126
    • 其次,每一个字符都对应一个灰度值,不同字符灰度值不同,具体如何计算一个字符的灰度值见下文
    • 传入一张彩色图片,先对它进行灰度化、放缩处理(能够使得宽度合适,每行字符串避免太长)、直方图均衡化(使得图像灰度均匀,增强对比度)。经过以上步骤,得到一个灰度数组。
    • 根据图像的灰度数组和字符的灰度值,将灰度数组映射为字符串

    如何计算一个字符的灰度值?
    将字符画在一张纸上,统计这个字符所占的面积,面积越大,说明字符灰度值越大(或者恰恰相反也是可以的)。

    关于直方图均衡化,请查看直方图均衡化

    本程序可以进行如下配置:

    • 更改字符集,可以包含汉字
    • 更改导出图片的字体、字符间距

    先放上一张大大的帅照:

    from PIL import ImageFont, Image, ImageDraw
    
    # 字符集使用ascii码中的可打印字符
    charset = [chr(i) for i in range(32, 127)]
    # 计算字符灰度时,字体使用默认字体
    font = ImageFont.load_default()
    
    
    def histogram(a):
        # 统计各个颜色出现的频率
        cnt = [0] * 256
        for i in a:
            cnt[i] += 1
        return cnt
    
    
    def transform(a):
        # 为各个颜色赋予新的颜色值
        su = sum(a)
        ans = [0] * 256
        s = 0
        for i in range(len(a)):
            s += a[i]
            ans[i] = int(255 * s / su)
        return ans
    
    
    def map_by(a, b):
        # 根据映射b,将a数组中的元素映射为新的数组
        ans = []
        for i in a:
            ans.append(b[i])
        return ans
    
    
    def get_grey(char):
        # 获取单个字符的灰度
        sz = font.getsize(char)
        img = Image.new('1', sz)
        draw = ImageDraw.Draw(img)
        draw.text((0, 0), char, fill='white')
        white_cnt = 0
        for i in range(sz[0]):
            for j in range(sz[1]):
                if img.getpixel((i, j)):
                    white_cnt += 1
        return white_cnt / (sz[0] * sz[1])
    
    
    def get_charset_grey():
        # 获取字符集中各个字符的灰度
        charset_grey = []
        for i in charset:
            grey = get_grey(i)
            charset_grey.append((i, grey))
        charset_grey = sorted(charset_grey, key=lambda it: it[1])
        max_grey = charset_grey[-1][1]  # 最大灰度的字符
        charset_grey = list(map(lambda it: (it[0], it[1] / max_grey * 255), charset_grey))
        return charset_grey
    
    
    def near(a, x):
        # 根据灰度x在“字符-灰度”列表中查找灰度最接近的字符,此处使用二分查找
        lo, hi = 0, len(a) - 1
        while lo < hi:
            mid = (hi + lo) // 2
            if a[mid][1] == x:
                return a[mid][0]
            elif a[mid][1] < x:
                lo = mid + 1
            else:
                hi = mid
        ind = lo
        if ind == 0: return a[0][0]
        if abs(a[ind][1] - x) < abs(a[ind + 1][1] - x):
            return a[ind][0]
        else:
            return a[ind + 1][0]
    
    
    def draw_char(charset_grey, img_data):
        # 根据“字符-灰度”列表将图像数据映射成字符串
        s = ""
        for i in img_data:
            s += near(charset_grey, i)
        return s
    
    
    def char_image(img_path, line_chars=100):
        # 传入图片路径,将图片映射成为字符串
        # 首先将原图片进行灰度化、放缩、直方图均衡化
        img = Image.open(img_path).convert('L')
        height = int(line_chars / img.size[0] * img.size[1])
        img = img.resize((line_chars, height))
        data = list(img.getdata())
        new_data = map_by(data, transform(histogram(data)))
        charset_grey = get_charset_grey()
        s = draw_char(charset_grey, new_data)
        s = '
    '.join([s[i * img.size[0]:(i + 1) * img.size[0]] for i in range(img.size[1])])
        return s
    
    
    def toimg(s):
        # 将一个多行字符串画到图片上
        s = s.split('
    ')
        ch_sz = font.getsize(' ')  # 先测试一下单字符宽高(以空格为例)
        ch_sz = (ch_sz[0] + 2, ch_sz[1] + 2)  # 字符之间空闲两格
        img = Image.new('1', (ch_sz[0] * len(s[0]), ch_sz[1] * len(s)))  # 创建新图片
        draw = ImageDraw.Draw(img)
        for i in range(len(s)):
            for j in range(len(s[0])):
                draw.text((j * ch_sz[0], i * ch_sz[1]), s[i][j], fill='white')
        return img
    
    
    s = char_image("bitch.jpg", line_chars=200)
    img = toimg(s)
    img.save("haha.jpg")
    print(s)
    
    
  • 相关阅读:
    SCP测试服务器的上行/下行带宽
    React-Native 之 GD (四)使用通知方式隐藏或显示TabBar
    React-Native 之 GD (五)属性声明和属性确认 及 占位图
    React-Native 之 GD (三)近半小时热门
    React-Native 之 GD (二)自定义共用导航栏样式
    React-Native 之 GD (一)目录结构与第三方框架使用与主题框架搭建
    React Native商城项目实战16
    React Native商城项目实战15
    React Native商城项目实战14
    React Native商城项目实战13
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/7421283.html
Copyright © 2011-2022 走看看