Python实战1- 图片转字符画
Python实战系列用于记录实战项目中的思路,代码实现,出现的问题与解决方案
本文为第1篇–图片转字符画
参考教程:https://www.cnblogs.com/MartinLwx/p/9143844.html
一、步骤
分析:字符画原理是将图片的灰度值与个人设定的字符集之间建立映射关系,不同区间的灰度值对应不同的字符,之后将图片每一个像素对应的字符打印出来,即可获得字符画
-
将原图片转化为灰度图片
方案一:利用灰度公式将像素的 RGB 值映射到灰度值
gray = 0.2126 * r + 0.7152 * g + 0.0722 * b
方案二:利用PIL库所带的convert(“L”)函数转化图片 -
将图片的灰度值与个人设定的字符集之间建立映射关系
可以自己设定,也可以找网上教程里给出的,下面将给出两种参考方案
方案一:ascii_char = list("[email protected]%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
方案二:
ascii_char = list("qwertyuiop[]asdfghjkl;'zxcvbnm,./`[email protected]#$%^&<()*+{}:"?> |")
经测试,方案二生成的图片真实度更高
-
将字符串保存到txt文件
二、代码实现
注:IDE为Spyder,Python版本为3.6,推荐使用Anaconda,自带Pillow库。否则要提前安装好pillow。
pillow库安装教程:
- 用管理员身份打开命令提示符
- 输入pip install pillow
代码实现如下:
# -*- coding: utf-8 -*-
"""
Created on Fri Sep 28 23:23:44 2018
@author: PastoralDog
"""
from PIL import Image
class ASCIIart(object):
def __init__(self,file):
self.file=file
self.codelist = """qwertyuiop[]asdfghjkl;'zxcvbnm,./`[email protected]#$%^&<()*+{}:"?> |"""
self.img=Image.open(file)
self.count=len(self.codelist)
def to_ASCII(self):
img = self.img.convert("L")
asciilist = ''
for h in range(0,img.size[1]):
for w in range(0,img.size[0]):
gray = img.getpixel((w,h))
pos = gray/256
#asciilist = asciilist + self.codelist[int((self.count-1)*pos)]
asciilist = asciilist + self.codelist[int((self.count-1)*pos)]+" "+self.codelist[int((self.count-1)*pos)]
asciilist = asciilist+"\n"
return asciilist
def to_txt(self):
outfile = open('ASCIIart.txt', 'w')
outfile.write(self.to_ASCII())
outfile.close()
def _resize(self,rate):
width = self.img.size[0]
height = self.img.size[1]
scale = width / height
self.img = self.img.resize((int(width*rate), int(width*rate/scale) ))
if __name__ == '__main__':
file="test.jpg"
img=ASCIIart(file)
img.to_txt()
三、出现的问题及解决方案
-
图像失真严重
采用方案一的编码生成的字符画效果不是很好,改用方案二后得到解决 -
图像左右过于窄
我们以下图为例
第二张核心代码:asciilist = asciilist + self.codelist[int((self.count-1)*pos)]
第三张核心代码:
asciilist = asciilist + self.codelist[int((self.count-1)*pos)]+" "+self.codelist[int((self.count-1)*pos)]
由于第二张过窄,我们就加点东西(" "+self.codelist[int((self.count-1)*pos))使它丰满起来
本人水平有限,欢迎大家提出问题与建议。若代码有看不懂的地方,也欢迎提出!