Python实现字符画照片:从灰度转换到终端打印完整指南
本文详解如何利用Python将普通照片转换为字符画。通过PIL库打开并转换图像为灰度模式,结合NumPy进行高效的分辨率调整、反白处理及灰度映射。文章提供了完整的代码示例,展示如何将像素值映射为特定字符并在终端或文件中输出,适用于技术爱好者和开发者探索编程与艺术的结合。
本文深入解析如何利用Python脚本将常规图像转化为字符画,通过详细的代码示例展示实现过程,为相关学习和实际应用提供参考。
前言:字符画的历史与现状
1. 前言
回顾早期计算机时代,如LASER-310机型,显示器仅支持单色文本显示,每行限80字符。当时查看图像需借助针式打印机在穿孔纸上输出,利用不同字符代表不同灰度级,形成独特的古风视觉效果。如今,借助Python仅需十几行代码即可实现类似效果,并可保存为文件。下文将逐步演示具体操作流程。

图像加载与灰度转换
2. 打开图片,转为灰度模式
Python图像处理常用PIL和PyOpenCV模块。本例选用PIL模块加载图像,代码如下:
>>> from PIL import Image
>>> im = Image.open('xufive.jpg')
>>> im.size
(979, 1248)
>>> im.mode
'RGB'
变量im代表打开的图像对象,im.size获取分辨率,im.mode获取颜色模式。计算机图像常见RGB彩色模式,为生成字符画,需将其转换为灰度模式:
>>> im = im.convert('L')
>>> im.mode
'L'
分辨率调整与图像缩放
3. 改变分辨率
字符画需考虑终端每行字符显示数量。假设屏幕水平分辨率为1920,字符宽度占8像素,则每行可显示240字符。综合考量后设定每行显示120字符,需将灰度图宽度设为120像素,高度height计算公式如下:
width = 120
height = int(width*im.size[1]/im.size[0])
根据新分辨率生成图像对象:
>>> im = im.resize((width, height))
>>> im.size
(120, 152)
反白处理与NumPy优化
4. 反白处理
灰度模式下像素值范围0~255,共256级。因屏幕背景色可能为深色或浅色,需提供反白处理功能,即用255减去各像素灰度值。遍历处理速度较慢,本例利用NumPy数组广播技术加速,先将PIL图像转为NumPy数组:
>>> import numpy as np
>>> arr = np.array(im)
>>> arr.shape
(152, 120)
>>> arr.dtype
dtype('uint8')
需注意,PIL对象分辨率120x152表示宽120高152像素;转为NumPy数组后shape为(152, 120),表示152行(高)120列(宽)。两者行列概念虽不一致,但物理意义相同。
利用NumPy广播技术实现反白处理,仅需一行代码且瞬间完成:
arr = 255 - arr
灰度-字符映射与转换
5. 确定灰度-字符映射表
显示器字符由点阵组成,亮点差异表示不同灰度。本例选用8个字符表示不同灰度级:
>>> chs = np.array([' ', '.', '-', '+', '=', '*', '#', '@'])
>>> chs.dtype
dtype('<U1')
8个字符对应8级灰度,需将像素的256级灰度值转换为8级:
>>> arr = arr/32
>>> arr = arr.astype(np.uint8)
>>> arr.min(), arr.max()
(0, 7)
6. 灰度转字符
接下来将0~7范围内的像素值映射为对应字符。虽可用嵌套循环,但利用NumPy数组的矢量化特性更高效。本例展示了NumPy的一种少见应用方式:
>>> arr = chs[arr]
>>> arr.shape
(152, 120)
>>> arr.dtype
dtype('<U1')
终端打印与文件保存
7. 打印
基于上述处理,打印输出自然实现:
>>> for i in range(arr.shape[0]):
for j in range(arr.shape[1]):
print(arr[i,j], end='')
print()
8. 保存为文件
若终端显示不便,可将字符数据保存至文件:
>>> with open('xufive.txt', 'w') as fp:
for line in arr.tolist():
fp.write(''.join(line))
fp.write('\n')
下图展示了输出至文本文件后在编辑器中的显示效果。

完整代码实现与参数调整
9. 完整代码
不同运行环境中图像宽高比可能与原图存在差异。为抵消此差异,代码中引入矫正系数k,通过调整该参数可获得满意的显示效果。
# -*- 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([' ', '.', '-', '+', '=', '*', '#', '@']) #灰度-字符映射表
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('xufive.jpg', width=360, k=0.5, outfile='xufive.txt')
下图为命令行窗口中的显示效果。

以上内容即为本文全部,希望对学习有所帮助,欢迎支持。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













