使用python实现图片字符化

什么样的代码才能写进你的心里?沉浸代码,迷失自我,试图忘却现实.

好久没有搞代码了,今天更新一篇关于图片转换的文章,原理是利用灰度翻转,字符匹配实现从色彩图到字符的转换。这里我使用了python的PIL组件。废话不多说,下面我们直接上代码。

工欲善其事,必先利其器。我们首先安装PIL,这里演示的是window10的安装方法。

pip install Pillow    //直接打开cmd输入这个代码进行安装。(事实上python3以上本已经自带了PIL)
import PIL            //查看一下属实安装成功
调用一下PIL发现成功

我们首先创建一个函数:
以120个字符宽度打印打开我们转换好的的字符这里我设置了一个k值为了矫正不同分辨率下的误差来提高代码的实用性。

def print_photo(photo_file, width=120, k=1.0, reverse=False, outfile=None):
"""打印照片,默认120个字符宽度,直接声明函数"""

接下来我们就要把我么需要打印的原图给导入到程序中来,并且以灰度格式打开文件,也就是rgb格式,为我们之后的选取灰度字符做准备。

im = Image.open(photo_file).convert('L') // 打开图片文件,转为灰度格式

下面我们声明一个变量用来表示打印图像的高度,这里用到了我们的K值,用于我们像素比的调整。

 height = int(k*width*im.size[1]/im.size[0]) // 设置打印图像的高度,这里的k用于适应像素比可以进行修改

灰度模式下,每个像素的值域范围是0~255,共有256级灰度。考虑到屏幕背景色可能是深色的,也可能是浅色的,我们需要提供图像反白处理的手段。所谓反白处理,就是用灰度最大值255减去每一个像素的灰度值作为该像素新的灰度值。遍历每一个像素,固然可以实现反白,但速度会很慢。本案使用NumPy数组的广播技术,可以显著提升处理速度。我们先把PIL图像对象转成NumPy数组

arr = np.array(im.resize((width, height )))  //把获得的数据转换成Numpy数组

这里值得一提的是,PIL对象的分辨率为120*152转换成数组后的shape是[152,120]这里对应高度(行)120则对应120(列)。
这里我们利用数组广播技术进行反色处理

  arr = 255 - arr

现在准备工作已经完成,接下来就是对灰度进行映射,这里我引用维基百科上的一段话“在显示器上,字符是由点阵组成的。每个字符的亮点(或暗点)不同,可以用来表示不同的灰度。本案使用了下面8个字符表示不同的灰度:”

chs = np.array(['&','$','[',']','{','}','|','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','X','Y','Z']) // 灰度-字符映射表(这里仅作为参考可以自行添加)
  arr= chs[(arr/32).astype(np.uint8)] // 灰度转为对应字符

转义什么的准备工作全部完成了,接下来就是输出像素了。这是水到渠成的事情了

for i in range(arr.shape[0]): // 逐像素打印
      for j in range(arr.shape[1]):
        print(arr[i,j], end=' ')
      print()

最后我们来把i/o写了(引入并输出文件)

 print_photo('2.jpg', width=160, k=0.5, outfile='a.txt')

大功告成,我们来看一个成品视频

这个是我们的效果视频

最后我把完整的代码给大家发出来,欢迎各路大神分析指正!

# -*- coding: utf-8 -*-
 
from PIL import Image
import numpy as np
 
def print_photo(photo_file, width=120, k=1.0, reverse=False, outfile=None):
  """打印照片,默认120个字符宽度"""
   
  im = Image.open(photo_file).convert('L') # 打开图片文件,转为灰度格式
  height = int(k*width*im.size[1]/im.size[0]) # 打印图像高度,k为矫正系数,用于矫正不同终端环境像素宽高比
  arr = np.array(im.resize((width, height ))) # 转为NumPy数组
  if reverse: # 反色处理
    arr = 255 - arr
   
  chs = np.array(['&','$','[',']','{','}','|','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','X','Y','Z']) #灰度-字符映射表
  arr= chs[(arr/32).astype(np.uint8)] # 灰度转为对应字符
   
  if outfile:
    with open(outfile, 'w') as fp:
      for row in arr.tolist():
        fp.write(''.join(row))
        fp.write('\n')
  else:
    for i in range(arr.shape[0]): # 逐像素打印
      for j in range(arr.shape[1]):
        print(arr[i,j], end=' ')
      print()
 
if __name__ == '__main__':
  print_photo('2.jpg', width=160, k=0.5, outfile='a.txt')

留下评论