图像的字符画绘制

这个图像的字符画绘制,是在嵩天老师的《Python 语言程序设计基础》里的一小节,当初我把代码全码上去的时候,发现能运行成功,但是和书上的效果图完全不一样。恩,图片如下:
远远的看
远远的看,还是有点像原图的模样,原图如下:
在这里插入图片描述
生产图片的代码如下:

#DrawCharImage.py
from PIL import Image
ascil_char = list('"$_&WM#*oahkbdpqwmZO0QLCJUYXzcvunxr\
                    jft/\|()1{}[]?-/+@<>i!:;,\^`.')
def get_char(r, b, g, alpha=256):
    if alpha == 0:
        return ' '
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
    unit = 256 / len (ascil_char)
    return ascil_char[int(gray//unit)]
def main():
    im = Image.open('astro.jpg')
    WIDTH, HEIGHT = 100, 60
    im = im.resize((WIDTH, HEIGHT))
    txt =' '
    for i in range(HEIGHT):
        for j in range(WIDTH):
            txt += get_char(*im.getpixel((j, i)))
        txt += '\n'
    fo = open('pic_char.txt', 'w')
    fo.write(txt)
    fo.close()
main()

后来我百度了一个大佬的代码,链接:https://blog.csdn.net/wait_nothing_alone/article/details/52901531
我把我的图片放到他的代码上运行一下,发现OK,运行后的图片如下:
在这里插入图片描述
我用的是 宋体,八号,最小的字体都还那么大。
他的代码如下。我稍微改了一处:

# -*- coding: utf-8 -*-
from PIL import Image

codeLib = '''@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^`'. '''#生成字符画所需的字符集
count = len(codeLib)

def transform1(image_file):
    image_file = image_file.convert("L")#转换为黑白图片,参数"L"表示黑白模式
    codePic = ''
    for h in range(0,image_file.size[1]):  #size属性表示图片的分辨率,'0'为横向大小,'1'为纵向
        for w in range(0,image_file.size[0]):
            gray = image_file.getpixel((w,h)) #返回指定位置的像素,如果所打开的图像是多层次的图片,那这个方法就返回一个元组
            codePic = codePic + codeLib[int(((count-1)*gray)/256)]#建立灰度与字符集的映射
        codePic = codePic+'\r\n'
    return codePic

def transform2(image_file):
    codePic = ''
    for h in range(0,image_file.size[1]):
        for w in range(0,image_file.size[0]):
            g,r,b = image_file.getpixel((w,h))
            gray = int(r* 0.299+g* 0.587+b* 0.114)
            codePic = codePic + codeLib[int(((count-1)*gray)/256)]
        codePic = codePic+'\r\n'
    return codePic


fp = open(u'暴走.jpg','rb')
image_file = Image.open(fp)
image_file=image_file.resize((int(image_file.size[0]*0.75), int(image_file.size[1]*0.5)))#调整图片大小
#print u'Info:',image_file.size[0],' ',image_file.size[1],' ',count

tmp = open('tmp.txt','w')
tmp.write(transform1(image_file))
tmp.close()

今晚已经太晚了,已经十二点了,明天再仔细研究一下代码吧。12/03 0:06

首先自定义一个字符集,将这个字符集替代图像中的像素点,是的每个字符对应图像中的不同颜色。字符的种类越多越能还原图像中的图像中的色彩变化,图片也更加富有层次感。

ascil_char = list('"$_&WM#*oahkbdpqwmZO0QLCJUYXzcvunxr\
                    jft/\|()1{}[]?-/+@<>i!:;,\^`.')

像素的RGB颜色值与字符集的对应函数如下:

def get_char(r, b, g, alpha=256):
    if alpha == 0:
        return ' '
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
    unit = 256 / len (ascil_char)
    return ascil_char[int(gray//unit)]

PIL库中Image类的resize(size)函数对图片重新设定大小。size是一个二元元组,分别表示新图像的长度和宽度。resize()函数不是简单第改变图像大小,而是对像素在新尺寸下重新排列。
创建一个控制符串txt,然后利用一个嵌套循环向里面添加字符。im.getpixel()方法可以返回给定推向位置的像素值,如果图像为多通道,则返回一个RGB颜色元组。

经过研究,发现上一个代码会出现那种情况:

  1. 一个是图像的大小设置
  2. 一个是.txt文件字体的设置
  3. 字符集的不同
    当我将图像大小设置为宽300、高80后,运行后图像如下:
    在这里插入图片描述
    宋体、常规、小六
    当将字符集改变为ascil_char = list( '''@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^’. ‘’’)#生成字符画所需的字符集`,运行后的图像如下:
    在这里插入图片描述

当将彩色向灰度的转换为:gray = int(0.299 * r + 0.587 * g + 0.114 * b),运行后图像如下:
在这里插入图片描述

代码如下:

#DrawCharImage.py
from PIL import Image
ascil_char = list( '''@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^`'. ''')#生成字符画所需的字符集
def get_char(r, b, g, alpha=256):
    if alpha == 0:
        return ' '
    #gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
    gray = int(0.299 * r + 0.587 * g + 0.114 * b)
    unit = 256 / len (ascil_char)
    return ascil_char[int(gray//unit)]
def main():
    im = Image.open('astro.jpg')
    WIDTH, HEIGHT = 300, 80
    im = im.resize((WIDTH, HEIGHT))
    txt =' '
    for i in range(HEIGHT):
        for j in range(WIDTH):
            txt += get_char(*im.getpixel((j, i)))
        txt += '\n'
    fo = open('pic_char.txt', 'w')
    fo.write(txt)
    fo.close()
main()

总结:不同的字符给人带来的视觉效果不同,@#¥这类字符有浓密的色彩感,而_!{}/|这类字符空白较多,一般适合表示浅色。在生成字符画后,可以根据字符集和图像的对照适当修改字符排列顺序,例如:将背景色对应的字符修改为_或/,将会突出图像效果,将图像中浓墨重彩色地方使用@*或B&表示层次感更强。

im.getpixel((j,i))返回的是一个元组,这个元组有三个元素,分别对应三个颜色通道(RGB)的值,是一个运算符,对元组使用运算符即为元组拆封操作,元组会返回元组的所有元素。
12/3 10:21

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页