7.4 输入输出:练习——ASCII 图¶
内容梗概¶
本课是一节练习课:把一个 BMP 彩色图片转换成由字符组成的 ASCII 图(txt 文本)。老师强调这个练习**不布置为作业**(因为包含少量未学的超前知识),但下一节课的作业可能与之相关。课程讲解了转换的整体原理(彩色图 → 灰度图 → 字符映射)、正式引入 with open(...) as ... 语法、手工解析 BMP 二进制文件格式的思路,以及把 0~255 灰度值映射到 70 级字符的换算方法,最后留下"图像为何倒过来、如何翻转"的思考题。
知识点详解¶
练习任务与演示效果(约 00:00)¶
- 任务:读取一张 BMP 图片(老师用的是机器猫/小叮当图),通过一系列操作转成 ASCII 字符画,写入 txt 文本文件。
- 演示:代码用**相对路径**(py 文件当前目录)读取 BMP,运行后目录下多出
test.txt;初看是一堆字符,把字号不断缩小(记事本或 VSCode 中 Ctrl+-)后能看出是一个(倒过来的)机器猫。 - 练习目的:训练文件读写能力;因为含一点超前知识,所以只当练习、不当作业。
转换原理(约 03:27)¶
分三步:
- 彩色图 → 灰度图:彩色图的每个像素由 R、G、B(红、绿、蓝)三个分量组成;灰度图的每个像素只有一个 0~255 的**灰度值**(共 256 级),0 表示黑色,255 表示白色,中间是不同程度的灰色。
- 灰度值 → 字符:定义一个名为
GRAY_SCALE的字符串变量,包含 70 个 ASCII 可打印字符,排列顺序有讲究(约 07:38): - 越靠左(索引越接近 0)的字符越"复杂",打印出来后单位面积内黑色占比越大(如
$); - 越靠右的字符越"浅",最后一个(索引 69)是空格(全白)。
- 于是索引越小越黑、越大越白,正好对应灰度值 0=黑、255=白。
- 范围换算(约 10:13):把 0~255 的灰度值映射到 0~69 的索引——用
256 / 70得到一个缩小比例,每个灰度值除以这个比例再取整,即得字符下标。心算验证:灰度 0 → 索引 0($,黑色);灰度 255 → 索引 69(空格,白色)。
with open(...) as ... 语法(约 10:55)¶
- 正式引入
with语法: - 对比传统写法:传统方式要
open→ 判断打开是否成功(异常处理)→ 读写 →close,框架繁琐。 with的好处:- 类似条件判断:打开**成功**才执行缩进块内的代码,失败则什么也不做、直接执行后面的内容;
- 跳出
with块时**自动close()文件**,不会忘记关闭、不会一直占用文件。 - 开源项目和示例代码中普遍都是这种写法。
手工解析 BMP 文件格式(约 13:47)¶
- 代码中用**二进制方式**(
rb)打开 BMP 文件并手工解析其格式——这一段属于超前内容,老师只讲思路,细节下节课展开。 - BMP 是固定格式的二进制文件:开头约 14 字节文件头 + 约 40 字节信息头,共约 54 字节,头部记录了图片的宽、高、大小等信息;之后才是真正的像素数据。
- 像素数据的存储顺序是 BGR(先 blue,再 green,再 red),不是 RGB;把每三个字节以
[::-1](步长 -1)反序即可还原为 RGB(约 16:12)。 - 每读三个字节(一个像素的 BGR)→ 反序成 RGB → 用图像处理学科的一个**线性转换公式**把 RGB 换算成 0~255 的灰度值 → 再按上面的比例换算成 0~69 的字符索引 → 把对应字符写入输出文件;处理完一行像素后写一个换行符,再写下一行(约 17:28 ~ 19:52)。
- 图片的宽和高来自读取 BMP 文件头(具体读法下节课讲)。
- 老师联系实际:信息安全方向的同学离不开二进制格式解析,之前"计算机安全与维护"课手工做数据恢复(解析文件记录、偏移、文件头)是同类工作,以后学 PE 文件(exe)也会遇到。
遗留问题:图为什么是倒过来的(约 20:30)¶
- BMP 存储像素时**从最底下一行开始、从左到右**逐行存放,按顺序读出来图像就垂直翻转了,所以打出来是倒着的。
- 思考题(不强制):可以
- 用
f.seek()调整读取位置来翻转; - 或改变写入顺序——先写最后一行、再写倒数第二行……
- 方法不限,大家自己想办法。
注意事项(约 22:06)¶
- 这段代码**只能处理 BMP 格式**,JPG/JPEG、PNG 都处理不了。
- 可以用 Windows 画图把图片"另存为 BMP"来做格式转换。
- 今天没有作业,把之前的作业交上来;下节课讲完二进制和编码后会布置相关作业。
示例与演示¶
- 整体效果演示(约 01:27):运行现成代码,读取同目录下的机器猫 BMP,生成
test.txt;缩小字号后可见(倒置的)机器猫字符画;在 Windows 记事本中也可用 Ctrl+- 缩小查看。 - 代码逐段讲解:
GRAY_SCALE字符串:70 个字符从"黑"到"白"排列(约 07:38);with open("test.txt", "w") as output:打开输出文件,成功后再以rb打开 BMP(约 13:38);- 读 14 字节 + 40 字节文件头获取宽高等信息(超前内容,略讲);
- 循环中每次读 3 字节(BGR)→ 反序为 RGB → 线性公式转灰度 → 除以
256/70的比例取整得索引 → 取字符写入文件;每行结束写换行。 - 课堂思考题:利用
f.seek或调整写入顺序把倒置的字符画翻转过来。
重点与难点¶
- 理解 ASCII 图的核心映射思想:字符的"视觉黑度"对应灰度值,索引 0 最黑、69(空格)最白。
- 范围换算:灰度值 ÷ (256/70) 取整 → 0~69 的字符下标;要意识到这是把 0~255 的区间压缩到 70 级。
with open as的语义:成功才执行、自动 close,是文件操作的推荐写法。- 难点(超前内容):BMP 二进制格式——54 字节头部、像素按 BGR 存储、从下往上逐行存储导致图像倒置。
- 实用限制:代码仅支持 BMP,其他格式需先转换。
关联内容¶
- 本练习综合运用本章前几节:7.3 的文件读写(
open、read、write、模式w/rb、seek)、相对路径概念;with语法老师表示之前也提过,这里正式引入。 - 用到了之前讲过的切片技巧(
[::-1]反序 BGR→RGB)和 base64 串的观感类比(约 01:16)。 - 为下一节课做铺垫:二进制文件处理、字符编码、BMP 文件头的详细解析都在下一节展开,且**下节课的作业与本练习相关**。
- 跨课程关联:与"计算机安全与维护"课的手工数据恢复(文件头、偏移解析)、将来信息安全方向的 PE 文件解析一脉相承。