如何高效使用Micropython看你喜欢看的视频?【上】(驱动OLED屏幕显示图像教程)
前言
前几天突然突发奇想:能不能用Micropython驱动OLED屏幕看视频呢?
不过我对Micropython驱动OLED屏幕的认识,还只停留在显示字符的阶段,没有深入研究过如何显示图像。刚好,看到网上有人实现了差不多的效果,我就借这个机会进行了深入研究,终于让我找出了最方便的,显示动画和图像的方法,在这里开源给各位学习。
首先,要感谢Micropython中文社区的版主邵子扬老师对本项目的帮助!老师牛逼!
话不多说,先上图,还有GitHub地址:用Micropython看Bad Apple!
以及演示视频连接:
【工程开源】看BadApple?100行代码教你如何用Micropython驱动OLED屏幕看视频!
0x00 播放视频需要几步?
无论什么屏幕,播放视频都是利用人眼的暂留效应,即通过快速切换每一帧图像,制造图像运动的错觉。所以,要完成动画的播放,至少需要解决三个大方向的问题:
①如何获取读取图像内容?
②如何在屏幕上显示图像
③把视频切分成图像?
整个显示视频的流程大概就是:(准备工作:分割图片)=> 读取图片 => 显示内容,接下来,我们来逐一进行解决。
0x01 如何在屏幕上显示图像?
Micropython用于驱动OLED屏幕的库为ssd1306.py
,而我之前一直只用过这个库中的oled.text()
函数,并没有研究过里面的东西,直到这几天,我打开ssd1306,发现里面导入了一个没见过的库:framebuf
。
import framebuf
帧缓冲区类提供一个像素缓冲区,此缓冲区可使用像素、线、矩形、文本甚至其他帧缓冲区来绘制。此缓冲区可在生成显示器输出时发挥作用。
所以这个库可以产生一个变量,用来保存在屏幕上要显示的内容。然后问题来了,内容从哪里来呢?我们要显示的图像是黑白图像(二值化,不是灰度),那是否可以直接读取一张黑白图像来获取图像数据呢?
答案是:可以!隆重介绍.pbm
格式:
PBM格式由Jef Poskanzer在20世纪80年代发明,为了便于通过电子邮件,用ASCII码表示单色位图。每个文件的开头两个字节(ASCII码)作为文件描述子,指出具体格式和编码形式。
PBM还有两个兄弟:PPM和PGM,三者被统称为PNM格式。在PNM格式中,每个像素的颜色都用一个字符进行保存,PPM和PGM因为保存的是彩色图和灰度图,因此用ASCII码进行保存,而PBM是专门用来保存二值化之后的位图,每个像素“非黑即白”,所以每个字符都是1或0,这里是一个简单的PBM图片读取后的内容:
P1
# This is an example bitmap of the letter "J"
6 10
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
1 0 0 0 1 0
0 1 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
第一行的P1
表示的其实是文件的类型,P1指ASCII保存的位图。除此还有P2~P6,具体含义大家可以自行查阅,此处不加赘述;第二行是注释,不用管;第三行表示的是这个位图的宽和高分别是6和10,接下来的全部数据就是每个像素的黑白值了。不难发现,这个图显示出来,应该是一个字母J。
所以不难发现,只要我们把每一帧图像都保存成PBM格式,再把内容读取到framebuf中保存,不就可以显示了吗?对的,所以第一阶段的任务我们已经基本完成,我们来尝试写一下代码:
with open(dirt,'rb') as f :
f.readline()#读取文件头
f.readline()#读取尺寸
data = bytearray(f.read())#把剩下全部的数据读取出来
fbuf = framebuf.FrameBuffer(data,88,64,framebuf.MONO_HLSB)#把读取的数据保存到framebuf中,88和64是图片的宽和高
接下来就是第二个问题了——如何显示?
0x02 如何在屏幕上显示图像?
我发现,掌控板自带的屏幕可以显示图形,这个图形包括自定义图形,而我手头上刚好有一个掌控板,于是把显示图像的代码拉出来看,发现它是使用了一个叫做oled.blit()
的函数实现的,这个函数的用法类似于oled.text()
,传入帧缓冲区、显示的xy坐标,就可以显示了,非常简单,因此我们完善一下刚刚的代码:
#注意:此处的的运行平台为ESP32,测试过ESP32-WROVER-B和掌控板均可使用,pyboard有待测试
from ssd1306 import SSD1306_I2C
from machine import I2C,Pin
import framebuf,time,os, machine
SD_SW = Pin(5, Pin.IN)#我使用的ESP32的5号脚是用于读取SD卡的
os.mount(machine.SDCard(), '/sd')#挂载SD卡,SD卡里放要播放的图片
i2c = I2C(sda = Pin(23),scl = Pin(22))#定义软件I2C接口
display = SSD1306_I2C(128,64,i2c)#创建屏幕对象
for i in range(1,41):#我这里只用了41张图片测试,因此“读取-显示”的过程要循环41次,亲测整个5帧版本BAD_APPLE也是可以播放的
dirt = 'sd/BAD_APPLE/' + str(i) + '.pbm' #文件地址
print(i)
with open(dirt,'rb') as f :#注意,这里的'rb'参数很重要,没有的话会读取错误
f.readline()
f.readline()
data = bytearray(f.read())
fbuf = framebuf.FrameBuffer(data,88,64,framebuf.MONO_HLSB)
display.fill(0)
display.blit(fbuf,19,0)#如果不居中,可以修改中间的参数
display.show()#记得show
del fbuf#清理内存
time.sleep(0.2)#这个延时的长度取决于各自的帧率,使用我提供的BAD_APPLE5帧版本则0.2秒切换一次,I2C的刷新极限应该就是0.2了,再快就会花屏了。
到这里,我们基本上可以做到看bad apple啦!不过,我们还有两个问题没有解决:
①我想要显示自己的喜欢的图片和视频,怎么自己去制作BPM图片呢?
②我的Micropython开发板没有TF卡槽/我没有TF卡,怎么播放视频呢?
这些问题,我们留到下一篇继续为大家解答,同时我也会提供一个非常简单的脚本给大家处理自己的视频和图片!感谢大家阅读到这里!