在二次元圈子里有这样一句话

有屏幕的地方,就有Bad Apple

比如笔者最近入手了一个物联网开发板HaaS EDU K1,就萌发了在这些小的开发板上实现播放BadApple的想法。

说干就干!!!

本文将给大家展示下如何实现开发板的OLED播放BadApple,比如是基于Python轻应用。Python轻应用是阿里云IoT设备智能平台研发部推出的一个低代码的IoT开发框架,它包含了oled的驱动组件,也包含framebuf这类基础的绘图库。那接下来我就给介绍具体基于Python轻应用实现BasApple的播放。

先上效果

硬件连接

HaaS EDU K1自带一块OLED屏幕,使用HaaS EDU K1的用户无需关心硬件连接,在board.json中添加如下配置即可:

{"version": "1.0.0","io": {"oled_spi": {"type": "SPI","port": 1,"mode": "master","freq": 26000000},"oled_dc": {"type": "GPIO","port": 28,"dir": "output","pull": "pullup"},"oled_res": {"type": "GPIO","port": 30,"dir": "output","pull": "pullup"},},"debugLevel": "ERROR","repl": "disable"
}

软件实现

要实现屏幕显示,肯定需要屏幕驱动模块,本案例中用到的是SH1106 OLED屏幕驱动。液晶屏驱动类提供一个显示器对象,此对象基于FrameBuf帧缓冲区类进行派生,可继承其绘画像素、线、矩形、文本的能力。也提供了绘制XBM图的能力。

其中draw_XBM()就是我们主要用到的方法。

SH1106.draw_XBM(x, y, w, h, bitmap)

在帧缓冲上的给定位置绘制XBM 位图。在使用这个方法之前,我们需要知道 XBM 是个啥。

X-BitMap (XBM)介绍

X-Bitmap(XBM)是一种非常古老但通用的图像文件格式,它与现在的许多Web浏览器都兼容。X-Windows图形界面(UNIX和Linux常用的GUI)的C代码库xlib中有一个组件专门描述了它的规范。XBM图形的实质上是使用16进制数组来表示二进制图像的C源代码文件。

我们举一个例子来说明,XBM如何表达一张图片。

显示图片

  • 原图

当我们想将一张图片显示在屏幕上时,我们需要考虑到图片像素与屏幕分辨率之间的匹配。例如我们尝试将这下图显示在OLED上。它的分辨率是1088*426。很显然,它是远远大于屏幕支持的分辨率的。因此,我们需要通过一些方法将这张图片的分辨率尽可能收缩到我们希望的分辨率,同时尽可能保留其表达的信息。

  • 像素化

这一步就是将图片缩放到目标尺寸,例如右图中的23*9,同时使用像素绘制出该图片。对于一些较为精致的图片,建议手动绘制。像素化完成后,即得到一张BMP (Bitmap 位图) 图片。

对于右图而言,它的分辨率仅仅只有23*9,且每个像素只有黑/白两种颜色,对应OLED上的亮和灭,因此每个像素都可以用0/1表示。

在XBM中,规定了这样一种表达方式:

其规定将BitMap中的像素进行了一个映射,其中一个字节的位为水平映射。每个字节占据8个水平像素,而7位位于屏幕的最左边。 后续字节在连续的水平位置出现,直至到达最右侧的边缘。更多字节在下一行低1个像素显示。


最终生成的文件如下所示:大家可以自己对应图片来数一数

#define haas_width 23#define haas_height 9static unsigned char haas_bits[] = {0xff,0xff,0xfe,0x80,0x00,0x02,0xa4,0xc6,0x7a,0xa5,0x29,0x42,0xbd,0xef,0x7a,0xa5,0x29,0x0a,0xa5,0x29,0x7a,0x80,0x00,0x02,0xff,0xff,0xfe };

我们再在python交互模式中验证一下,输入如下脚本:

from driver import SPI
from driver import GPIOimport sh1106
import utimeoled_spi = SPI()
oled_spi.open("oled_spi")oled_res = GPIO()
oled_res.open("oled_res")oled_dc = GPIO()
oled_dc.open("oled_dc")oled = sh1106.SH1106_SPI(132, 64, oled_spi, oled_dc, oled_res)oled.fill(0)HAAS_XBM_width=23
HAAS_XBM_height=9HAAS_XBM=[0xff,0xff,0xfe,0x80,0x00,0x02,0xa4,0xc6,0x7a,0xa5,0x29,0x42,0xbd,0xef,0x7a,0xa5,0x29,0x0a,0xa5,0x29,0x7a,0x80,0x00,0x02,0xff,0xff,0xfe]oled.draw_XBM(20,20,HAAS_XBM_width,HAAS_XBM_height,HAAS_XBM)oled.show()

可以看到出现了一个小小的HaaS图标,证明我们的实现成功了!接下来可以大刀阔斧地显示视频了!

显示视频

由视频生成XBM序列

刚刚说到,XBM是一种图片格式,如果要显示视频,我们需要把视频变成一帧帧图片,再把图片变成XBM数组,最后在我们的OLED上播放。

为了实现以上功能,我们还是请出无所不能的Python,不过这一次,需要在PC上运行全功能的Pythpn。

视频帧采样

import cv2                                    # open-cv库 用于处理视频和图片badapple_frame = []                  # 创建一个空的数组,用来接收每一帧的XBM数据
cap = cv2.VideoCapture('badapple.mp4') # 打开视频文件i = 0
# 由于原视频有30帧,太高的帧率会导致数据量过大,在oled上也看不出太大区别,因此这里做了抽帧
step = 10                            # 每隔10个视频帧抽取一张XBM图片
while(cap.isOpened()):ret, frame = cap.read() # 读出一张图片放在frame里if (ret == True):i = i+1if(i%step):continueif(i > 1000):                # 只取视频前1000帧图像breakxbm_wight, xbm_height, xbm_bit = cv_2_xbm(frame, (128, 64), 150) # 将图像转换为XBMbadapple_frame.append(xbm_bit)        # 存入badapple_frameelse:breakcap.release()

图片转XBM

import cv2# cv2_img open-cv图片对象
# size 目标XBM大小 e.g.(128,64)
# thresh 图片二值化 阈值
def cv_2_xbm(cv2_img, size, thresh):if(len(cv2_img.shape) > 2):                                 # 如果是三通道(彩色)图片cv2_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图片img = cv2.resize(cv2_img, size, interpolation=cv2.INTER_LINEAR)               # 改变修改目标分辨率ret, threshimg = cv2.threshold(img, thresh, 255, cv2.THRESH_BINARY) # 二值化# cv2.imwrite('threshimg.bmp', threshimg) # 写入图片文件xbm_height = size[1]xbm_wight = size[0]//8 + (size[0]%8 != 0)xbm_bit = []mask = 0b10000000byte = 0# 开始映射像素for (pos_y, row) in enumerate(threshimg):for (pos_x, pixel) in enumerate(row):if(mask == 0):mask = 0b10000000xbm_bit.append(byte)byte = 0if pos_x == len(row) - 1:mask = 0if pixel > thresh:byte |= maskmask = mask >> 1xbm_bit.append(byte|mask|(1 if threshimg[-1][-1]>thresh else 0))return size[0],size[1],xbm_bit

于是,我们得到了一个非常宏大的数组:

接下来,我们仔逐帧显示这些XBM图片

播放

import badapple
from driver import SPI
from driver import GPIO
import sh1106
import utimeoled_spi = SPI()
oled_spi.open("oled_spi")oled_res = GPIO()
oled_res.open("oled_res")oled_dc = GPIO()
oled_dc.open("oled_dc")oled = sh1106.SH1106_SPI(132, 64, oled_spi, oled_dc, oled_res)oled.fill(0)
oled.show()f = 0    # 帧索引while(1):if(f == (len(badapple.badapple_frame) - 1)):       # 如果播放到结尾,再从头播放f = 0oled.fill(0)  # 清除帧缓冲区oled.draw_XBM(2, 0,badapple.badapple_frame_width,badapple.badapple_frame_height,badapple.badapple_frame[f]) # 绘制XBMoled.show()            # 绘制到屏幕f = f + 1utime.sleep_ms(30)     # 睡30ms 否则看起来很快

技术交流

Python轻应用继承了Python易学易用的特点,同时提供了基于嵌入式硬件的基础库封装,让开发者可以很方便的通过交互式的环境,实时进行嵌入式开发,让嵌入式开发也变得简单方便。如需更多技术支持,可加入钉钉开发者群,享受一对一的技术支持。

炸裂!上手三天,就在开发板上播放BadApple, 还是Python香相关推荐

  1. 第三章 Alter DE2-115 开发板的应用

    重点内容: ①DE2-115开发板的布局及设计特性: ②启动DE2-115开发板预载程序的详细步骤: ③如何利用DE2-115控制面板控制开发板上外围设备: ④简介DE2-115开发板上外围设备的特性 ...

  2. Mastering Embedded Linux Programming 学习 (三)在百问网157开发板上,编译构建linux内核

    Mastering Embedded Linux Programming 学习 (三)在百问网157开发板上,编译构建linux内核 一.下载内核源码 wget http://ftp.sjtu.edu ...

  3. linux usb视频开发板,ARM开发板上USB 摄像头图像采集实现

    开发板上的arm是AT91RM9200,摄像头选用的是网眼的pc350,主控芯片是ov511+.系统内核是2.4,宿主机是fedora core 6,交叉编译器是2.95.3.就是这些家底了,:-). ...

  4. 运行在TQ2440开发板上以及X86平台上的linux内核编译

    一.运行在TQ2440开发板上的linux内核编译 1.获取源码并解压 直接使用天嵌移植好的"linux-2.6.30.4_20100531.tar.bz2"源码包. 解压(天嵌默 ...

  5. 基于Domoticz智能家居系统(十三)Domoticz-3.8153在Tiny6410开发板上的移植

    Domoticz-3.8153在Tiny6410开发板上的移植 本文将在友善之臂Tiny6410开发板上移植Domoticz-3.8153,起因是去年在mini2440上移植的3.5877版本编译出来 ...

  6. 导出RK3288开发板上的根文件系统,并打包img

    整体操作一共三步: 一.将Rk3288的整个根文件系统的文件,通过ssh拷贝到PC系统(Ubuntu): 二.将此拷贝的全部文件,加载到虚拟光盘中,制作成img文件: 三.将img文件,再烧回RK32 ...

  7. Kria K26 SOM 在 KV260 开发板上的使用

    Kria K26 SOM 在 KV260 开发板上的使用 参考 前言 一.Linux开发环境搭建 1. 设置使用local sstate,加速工程编译 (1) 在Xilinx官网下载 aarch64 ...

  8. 将linux内核烧进arm板,ARM开发板上uClinux内核移植

    <ARM开发板上uClinux内核移植>由会员分享,可在线阅读,更多相关<ARM开发板上uClinux内核移植(19页珍藏版)>请在人人文库网上搜索. 1.纷傲掌秀悸篷益哑檀扬 ...

  9. 海思hi3518用eclipse采用交叉编译器编译程序在海思开发板上运行

    题记:在linux下开发C/C++程序时,eclipse是一款不错的IDE软件,在eclipse开发运行在linux系统下的程序时,用到 的编译工具莲是linux gcc,而如果要将eclipse开发 ...

最新文章

  1. JavaScript作用域原理——预编译
  2. 机智云官网用到的库-grid.css我解析
  3. PHP5.6.6上运行 ecshop 2.7.3常见问题处理
  4. 关于UAC执行级别的研究
  5. html表单提交后怎么发送邮箱,Dreamweaver中用表单制作了留言板,如何将内容提交后发到指定邮箱?...
  6. python keyerror_盘点Python 初学者最容易犯的10大错误!你中招了吗?
  7. LeetCode 633 平方数之和
  8. Hadoop教程(二)Hadoop伪集群环境安装
  9. Android获取MAC地址
  10. android java静态库,Android make 中变量记录
  11. android极光推送声音,Android 极光推送JPush---自定义提示音
  12. 最简单方法远程调试Python多进程子程序
  13. 如何注册和获取百度地图的密钥
  14. p4n 今天与朋友沟通支付云服务普及以及跨境电子商务的光辉前景
  15. php获取微信生成签名的时间戳,微信开发中access_token,js_ticket,时间戳,签名工具
  16. 区位码、国标码、机内码的区别和内在机制
  17. mysql front登陆1045错误_解决MySQL-Front连接MySQL出现1045错误
  18. POI 设置某列为文本格式 (亲测可用!!)
  19. 计算机博弈围棋,计算机博弈:“不围棋”入门教程
  20. 基于激光点云数据自动化实现道路标线分类、提取及矢量化

热门文章

  1. 【阅读笔记】TypeScript菜鸟教程
  2. DM9000AEP/CEP 技术文件
  3. 多玩英雄联盟插件盒子v3.8.0
  4. wlan autoconfig 启动错误:1068依赖服务或组无法启动
  5. 金融IC卡 ARQC和ARPC计算方法和实例
  6. 滑动门+下滑加载更多详细图解
  7. PDF防传播防复制一机一码制作教程版权在我手
  8. 阿里云AI训练营-数据分析入门:利用Pandas分析美国总统选举
  9. AD中原理图和PCB的交互
  10. WIFI:1.不使用第三方软件搞定WiFi热点(用代码) 2.win连接的WiFi查看密码3.同路由器限制他人网速(很多路由器软件就行,比如TP-LINK的官方软件功能就很OK,不必使用第三方软件))