小岳
2026-11-10
点 赞
0
热 度
0
评 论
0

把照片变成字符画,再变成一张 Excel 像素画

  1. 首页
  2. 有趣小玩意
  3. 把照片变成字符画,再变成一张 Excel 像素画

文章摘要

摸鱼小助手

把照片变成字符画,再变成一张 Excel 像素画

这篇不解决任何生产问题,纯粹好玩。 需要:能跑 Python 的电脑 + 一张你喜欢的照片。全程 15 分钟。 读完你能得到:终端里一块"用字符拼成的图",以及一份能发给同事炫耀的 .xlsx。

一、先说原理,一句话

图片是像素的明暗,字符是有疏密的笔画。 把每个像素的亮度映射成一个"看起来差不多黑"的字符,就得到字符画。

最黑 → @  #  %  *  +  =  -  :  .  空格 ← 最亮

处理流程只有四步:

  1. 读图片
  2. 转灰度(彩色变一个 0–255 的亮度值)
  3. 缩放(终端一行装不下 1000 个字符,通常缩到 80–120 列)
  4. 逐像素查表,换成字符

二、装一个依赖

pip install Pillow

验证:

python -c "import PIL; print(PIL.__version__)"

看到版本号(如 11.0.0)就行。

Windows 上如果 pip 找不到,用 python -m pip install Pillow;macOS 用 pip3 install Pillow。

三、第一版:20 行,终端直接出图

新建 ascii.py,整段复制:

from PIL import Image

# 从"最黑"到"最亮"的字符表,可自己换
CHARS = "@%#*+=-:. "

def to_ascii(path, width=100):
    img = Image.open(path).convert("L")          # 转灰度
    w, h = img.size
    # 终端字符是"高比宽大",纵向要压一半,否则图会被拉长
    ratio = 0.5
    height = int((h / w) * width * ratio)
    img = img.resize((width, height))

    lines = []
    for y in range(height):
        row = []
        for x in range(width):
            gray = img.getpixel((x, y))           # 0-255
            idx = int(gray / 256 * len(CHARS))
            row.append(CHARS[idx])
        lines.append("".join(row))
    return "\n".join(lines)

if __name__ == "__main__":
    out = to_ascii("photo.jpg", width=100)
    print(out)
    with open("ascii.txt", "w", encoding="utf-8") as f:
        f.write(out)
    print("已保存到 ascii.txt")

运行:

python ascii.py

你应该看到

终端里刷出一块由 @%#*+=-:. 组成的图,轮廓能认出来。同时目录里多了 ascii.txt。

效果不好? 三个旋钮:

现象 调整
太糊,看不清轮廓 width 调大到 150–200
太黑一片 把 CHARS 倒过来写:" .:-=+*#%@"
太亮,几乎空白 同上,或先做一次对比度增强
图被拉长/压扁 改 ratio,终端字体通常是 1:2,0.5 就对了

四、第二版:自动裁边 + 对比度自适应

真实照片经常是"背景一片白 + 主体一片黑",直接映射会糊成一块。加一步对比度拉伸,把亮度铺满 0–255:

from PIL import Image, ImageOps

def to_ascii_v2(path, width=120):
    img = Image.open(path).convert("L")
    img = ImageOps.autocontrast(img, cutoff=2)   # 自动拉对比度,切掉最亮最暗各 2%
    w, h = img.size
    height = max(1, int((h / w) * width * 0.5))
    img = img.resize((width, height), Image.LANCZOS)  # 用高质量缩放,边缘更干净

    lines = []
    for y in range(height):
        line = "".join(
            CHARS[int(img.getpixel((x, y)) / 256 * len(CHARS))]
            for x in range(width)
        )
        lines.append(line)
    return "\n".join(lines)

ImageOps.autocontrast 是这版的关键:它把"这块图最暗的值"拉到 0、"最亮的值"拉到 255,中间均匀分布。人像、夜景、扫描件提升最明显。

Image.LANCZOS 是缩放算法,比默认的 NEAREST 平滑得多,字符边界不会锯齿。

五、第三版:写进 Excel,做成"像素画"

字符画只能看,Excel 版可以发出去。思路一样,只是把"选一个字符"换成"给单元格填一个颜色"。

pip install openpyxl
from PIL import Image
from openpyxl import Workbook
from openpyxl.styles import PatternFill
from openpyxl.utils import get_column_letter

def to_excel(path, out="pixel_art.xlsx", size=48):
    """size = 最终图的长边像素数(也是单元格数)"""
    img = Image.open(path).convert("RGB")
    img.thumbnail((size, size), Image.LANCZOS)   # 等比缩到 size 以内
    w, h = img.size

    wb = Workbook()
    ws = wb.active
    ws.title = "PixelArt"

    # 让单元格变成正方形:列宽约等于行高的 1/7
    for x in range(1, w + 1):
        ws.column_dimensions[get_column_letter(x)].width = 2.0
    for y in range(1, h + 1):
        ws.row_dimensions[y].height = 15

    for y in range(h):
        for x in range(w):
            r, g, b = img.getpixel((x, y))
            hex_color = f"{r:02X}{g:02X}{b:02X}"
            cell = ws.cell(row=y + 1, column=x + 1)
            cell.fill = PatternFill(start_color=hex_color, end_color=hex_color, fill_type="solid")

    ws.sheet_view.showGridLines = False
    wb.save(out)
    print(f"已保存 {out}({w} x {h} 个单元格)")

if __name__ == "__main__":
    to_excel("photo.jpg", size=48)

你应该看到

已保存 pixel_art.xlsx(48 x 36 个单元格)

打开 Excel:一片没有网格线的彩色方块,凑远了看就是那张照片。

三个实用参数:

  • size=32:适合当头像,文件小
  • size=64:细节多,打开稍慢(4096 个单元格)
  • size=128:16384 个单元格,Excel 已经开始卡了,别超过 150

六、常见报错

报错 原因 处理
ModuleNotFoundError: No module named 'PIL' 装到了别的 Python 用 python -m pip install Pillow 保证装进当前解释器
UnidentifiedImageError 文件不是图片,或 HEIC 格式 iPhone 的 HEIC 先用系统导出成 JPG
输出全是一个字符 图片是纯色 / 对比度太低 用第二版的 autocontrast
图被拉得很长 忘了 ratio = 0.5 终端字符高约为宽的 2 倍
Excel 打开后颜色错乱 用了 size 太大 降到 64 以下
PermissionError 文件正被 Excel 打开 关掉 Excel 再跑
中文路径报错(老版本 Python) 编码问题 升级 Python,或把图片放英文路径

七、还能怎么玩

  1. 批量:把目录下所有图都转一遍,os.listdir 循环即可
  2. 视频:用 opencv-python 逐帧读,每帧转字符画后 \033[H\033[J 清屏重绘,就是终端里的"字符电影"
  3. GIF 动图:Image.open(gif) 后 seek 每一帧
  4. 反过来:把字符画渲染成图片(Pillow ImageDraw.text),得到一张能发朋友圈的图
  5. 做成网页:把字符画塞进 <pre>,配个等宽字体,就是一张极简 ASCII 艺术页

八、出处与参考

代码在 Python 3.10 + Pillow 11 + openpyxl 3.1 上实测。字符表可以随便改,中文全角字符(如 █▓▒░)也能用,效果更"实心"。


本站站长,主角光环,怎么滴,你还想攻击你的站长吗,真是好big的狗胆

小岳

intp 逻辑家

站长

不具版权性
不具时效性

文章内容不具时效性。若文章内容有错误之处,请您批评指正。

目录

欢迎来到摸鱼干货栈,这里为您提供开源与摸鱼源码

23 文章数
7 分类数
0 评论数
37标签数
最近评论