Python实现字符画照片:从灰度转换到终端打印完整指南

顾言
顾言
发布时间:2026-10-13| 5人浏览过
原创

本文详解如何利用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')

下图为命令行窗口中的显示效果。

以上内容即为本文全部,希望对学习有所帮助,欢迎支持。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。