Python如何使用字符打印照片


Posted in Python onJanuary 03, 2020

这篇文章主要介绍了Python如何使用字符打印照片,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

1. 前言

第一次在学校机房里见到计算机,还是上古时期。计算机型号大概是LASER-310吧,有点记不清了。那会儿,显示器还是单色的,只能显示文本,每行最多显示80个字符。想看图片,印象中只能用针式打印机打印在两侧穿孔的宽行打印纸上,每个像素用一个字符表示,不同的字符代表不同的灰度,就像下图这个样子。有没有感觉到浓郁古风呢?其实,随便一张照片,十几行Python代码,你也可以打印出这样的效果,还可以保存成文件。下面,我就一步一步地演示一下。

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是最常见的彩色图像模式。打印字符图片的话,需要将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)

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列(对应宽度)。虽然PIL对象和NumPy数组关于行列的概念不一致,但表达的物理意义是相同的。

利用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')

下图是输出到文本文件,在编辑器中显示的效果。

Python如何使用字符打印照片

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如何使用字符打印照片

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中for循环详解
Jan 17 Python
将图片文件嵌入到wxpython代码中的实现方法
Aug 11 Python
分享一个常用的Python模拟登陆类
Mar 29 Python
JavaScript中的模拟事件和自定义事件实例分析
Jul 27 Python
python读取文本中的坐标方法
Oct 14 Python
详解django的serializer序列化model几种方法
Oct 16 Python
Python常用爬虫代码总结方便查询
Feb 25 Python
Python手绘可视化工具cutecharts使用实例
Dec 05 Python
python GUI库图形界面开发之PyQt5切换按钮控件QPushButton详细使用方法与实例
Feb 28 Python
Python文件读写w+和r+区别解析
Mar 26 Python
Python如何对XML 解析
Jun 28 Python
Python多线程 Queue 模块常见用法
Jul 04 Python
Pytorch.nn.conv2d 过程验证方式(单,多通道卷积过程)
Jan 03 #Python
如何基于python实现画不同品种的樱花树
Jan 03 #Python
Python基础之变量基本用法与进阶详解
Jan 03 #Python
PyTorch里面的torch.nn.Parameter()详解
Jan 03 #Python
Python实现银行账户资金交易管理系统
Jan 03 #Python
Pytorch提取模型特征向量保存至csv的例子
Jan 03 #Python
pytorch查看torch.Tensor和model是否在CUDA上的实例
Jan 03 #Python
You might like
PHP实现MVC开发得最简单的方法――模型
2007/04/10 PHP
Gregarius中文日期格式问题解决办法
2008/04/22 PHP
解析mysql left( right ) join使用on与where筛选的差异
2013/06/18 PHP
PHP中的函数-- foreach()的用法详解
2013/06/24 PHP
php批量更改数据库表前缀实现方法
2013/10/26 PHP
PHP实现微信小程序人脸识别刷脸登录功能
2018/05/24 PHP
JSON 学习之完全手册 图文
2007/05/29 Javascript
根据一段代码浅谈Javascript闭包
2010/12/14 Javascript
JS继承--原型链继承和类式继承
2013/04/08 Javascript
Jquery 动态循环输出表格具体方法
2013/11/23 Javascript
jQuery实现的超简单点赞效果实例分析
2015/12/31 Javascript
学习Angular中作用域需要注意的坑
2016/08/17 Javascript
Node.js实现注册邮箱激活功能的方法示例
2018/03/23 Javascript
Vue.js实现双向数据绑定方法(表单自动赋值、表单自动取值)
2018/08/27 Javascript
怎样使你的 JavaScript 代码简单易读(推荐)
2019/04/16 Javascript
详解ES6新增字符串扩张方法includes()、startsWith()、endsWith()
2020/05/12 Javascript
浅谈JavaScript中等号、双等号、 三等号的区别
2020/08/06 Javascript
详解微信小程序轨迹回放实现及遇到的坑
2021/02/02 Javascript
[51:30]OG vs LGD 2018国际邀请赛淘汰赛BO3 第二场 8.26
2018/08/30 DOTA
python在ubuntu中的几种安装方法(小结)
2017/12/08 Python
几种实用的pythonic语法实例代码
2018/02/24 Python
python实现快速排序的示例(二分法思想)
2018/03/12 Python
Python生成器generator用法示例
2018/08/10 Python
Django发送邮件功能实例详解
2019/09/02 Python
详解如何使用CSS3中的结构伪类选择器和伪元素选择器
2020/01/06 HTML / CSS
Supersmart英国:欧洲市场首批食品补充剂供应商之一
2018/05/05 全球购物
数字漫画:comiXology
2020/06/13 全球购物
医院辞职信范文
2014/01/17 职场文书
廉洁自律承诺书
2014/03/27 职场文书
韩语专业职业生涯规划范文:成功之路就在我们脚下
2014/09/11 职场文书
骨干教师申报材料
2014/12/17 职场文书
2015年保安个人工作总结
2015/04/02 职场文书
2016七夕情人节广告语
2016/01/28 职场文书
2016年119消防宣传日活动总结
2016/04/05 职场文书
十大最强火系宝可梦,喷火龙上榜,第一名有双火属性
2022/03/18 日漫
Python中Schedule模块使用详解 周期任务神器
2022/04/19 Python