博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
字符画生成
阅读量:6510 次
发布时间:2019-06-24

本文共 3233 字,大约阅读时间需要 10 分钟。

字符画生成的种类

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

图像的种类:

  • 黑白
  • 灰度图

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

原理如下:

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

如何计算一个字符的灰度值?

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

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

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

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

先放上一张大大的帅照:

695653-20180924015141292-317909583.png

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 cntdef 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 ansdef map_by(a, b):    # 根据映射b,将a数组中的元素映射为新的数组    ans = []    for i in a:        ans.append(b[i])    return ansdef 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_greydef 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 sdef 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 = '\n'.join([s[i * img.size[0]:(i + 1) * img.size[0]] for i in range(img.size[1])])    return sdef toimg(s):    # 将一个多行字符串画到图片上    s = s.split('\n')    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 imgs = char_image("bitch.jpg", line_chars=200)img = toimg(s)img.save("haha.jpg")print(s)

转载地址:http://icbfo.baihongyu.com/

你可能感兴趣的文章
Eclipse 自动生成 Ant的Build.xml 配置文件
查看>>
添加一条信息到列表,如果重复就替换,
查看>>
C#基础第五天
查看>>
python 小数相加报错 invalid literal for int() with base 10
查看>>
【ubuntu】linux链接库
查看>>
uva 12325 枚举暴力 b
查看>>
多线程问题(JVM重排序)
查看>>
LeetCode 459 Repeated Substring Pattern
查看>>
POJ 3268 Silver Cow Party
查看>>
EMLS项目推进思考
查看>>
Eclipse快捷键 10个最有用的快捷键
查看>>
2018-2019-1 20165302 实验五 通讯协议设计
查看>>
Golang 知识点总结
查看>>
JAVA 8 特性
查看>>
算法设计 - LCS 最长公共子序列&&最长公共子串 &&LIS 最长递增子序列
查看>>
WebService之Axis2快速入门(7): Spring与axis整合发布为WebServic
查看>>
Uliweb查看模板调用关系
查看>>
C#与PHP通信压缩
查看>>
关于 Linux
查看>>
图文解析五大外链误区
查看>>