用树莓派和墨水屏做一个 mnist-clock

1. 墨水屏

  • 型号:微雪 2.9inch e-Paper Module, 带驱动板,8PIN

  • 工作电压:3.3V/5V

  • 通信接口:SPI

  • 分辨率:296 x 128

  • 显示颜色:黑、白

  • 局部刷新:0.3s

  • 全局刷新 :2s

  • 接线表:

墨水屏 8PIN 树莓派 40PIN 物理序号 备注
VCC 1 3.3V
GND 6 GND
DIN 19
CLK 23
CS 24
DC 22
RST 11
BUSY 18

2. 树莓派基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
├───Arduino
├───RaspberryPi&JetsonNano
│ ├───c
│ │ └─── ...
│ └───python
│ │ readme_rpi_CN.txt
│ │ setup.py
│ │ ...
│ │
│ ├───examples
│ │ epd_2in9bc_test.py # 测试程序
│ │ ...
│ │
│ ├───lib
│ │ └───waveshare_epd
│ │ epd2in9.py # 主逻辑
│ │ epdconfig.py # 配置文件
│ │ __init__.py
│ │ ...
│ │
│ └───pic
│ 2in9.bmp # 图片
│ Font.ttc # 字体文件,文泉驿,含中文字体
│ ...
└─── ...

  • 2.打开 SPI

    1
    2
    sudo raspi-config
    # 选择Interfacing Options -> SPI -> Yes 开启SPI接口
  • 3.安装依赖(python3)

1
2
3
4
5
6
7
8
# sudo apt-get update
# sudo apt-get install python3-pip

sudo apt-get install python3-numpy
sudo apt-get install python3-pil

sudo pip3 install RPi.GPIO
sudo pip3 install spidev
  • 4.运行测试程序
1
2
3
4
cd e-Paper/'RaspberryPi&JetsonNano'/
cd python/examples

sudo python3 epd_2in9bc_test.py

3. 处理 mnist 数据集,提取 index

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import numpy as np
import json


img_rows, img_cols = 28, 28

# the data, split between train and test sets
path = 'mnist.npz'
with np.load(path) as f:
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']

print('x_train.shape: {}, y_train.shape: {}'.format(x_train.shape, y_train.shape))
print('x_test.shape: {}, y_test.shape: {}'.format(x_test.shape, y_test.shape))

print(x_train[0], y_train[0])
print(x_test[0], y_test[0])


# 创建一个字典,keys 是0-9,values为空的list,后面将序号存进去
idx_dict = {}
for i in range(10):
idx_dict[i] = []
print(idx_dict)

# 将序号存进去
for idx in range(60000):
num = y_train[idx]
idx_dict[num].append(idx)

# if idx == 60: break

# print(idx_dict)

# 转为 json 格式, 保存
idx_json = json.dumps(idx_dict)
# print(idx_json)

with open('mnist_index.json', 'w') as f:
json.dump(idx_dict, f)

# 读取 json 文件
# with open('mnist_index.json', 'r') as f:
# data = json.load(f)
# print(data)

4. 先测试下用 opencv 显示时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import numpy as np
import json
import random
import cv2
import time

# load mnist dataset
path = 'mnist.npz'
with np.load(path) as f:
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']

with open('mnist_index.json', 'r') as f:
idx_dict = json.load(f)

for i in range(10):
print(i, len(idx_dict[str(i)]))


def get_mnist_num(num):
idxs = idx_dict[str(num)]
idx = random.choice(idxs)
return x_train[idx]


gap = np.zeros((28, 10))
for i in [8, 9, 18, 19]:
for j in [4,5,6,]:
gap[i][j] = 255

last_time = [-1, -1, -1, -1, -1, -1]
last_imgs = np.zeros((6, 28, 28))

while True:
now = time.localtime(time.time())
sec, mnt, hour = now.tm_sec, now.tm_min, now.tm_hour
s1, s2 = sec//10, sec%10
m1, m2 = mnt//10, mnt%10
h1, h2 = hour//10, hour%10
now_time = [h1, h2, m1, m2, s1, s2]
print(last_time, now_time)

for i in range(6):
if last_time[i] != now_time[i]:
last_imgs[i] = get_mnist_num(now_time[i])
last_time[i] = now_time[i]

img = np.hstack((last_imgs[0], last_imgs[1], gap,
last_imgs[2], last_imgs[3], gap,
last_imgs[4], last_imgs[5]))

cv2.imshow('num', img)
# cv2.imwrite('mnist-clock.png', img)
cv2.waitKey(100)

5. 在墨水屏显示时间

详见 epd29_mnist_clock.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# epd29_mnist_clock.py 

import sys
import os

import logging
import json
import numpy as np
import random
import time
import traceback

from PIL import Image, ImageDraw, ImageFont

from lib import epd2in9


logging.basicConfig(level=logging.DEBUG)
font = ImageFont.truetype('lib/Font.ttc', 18)

# load mnist dataset
with np.load('mnist.npz') as f:
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']

with open('mnist_index.json', 'r') as f:
idx_dict = json.load(f)

gap = np.ones((28, 10)) * 255
for i in [8, 9, 18, 19]:
for j in [4,5,6,]:
gap[i][j] = 0

def get_mnist_num(num):
idxs = idx_dict[str(num)]
idx = random.choice(idxs)
return 255 - x_train[idx]


# === 0. init
logging.info('epd2in9 Demo')

epd = epd2in9.EPD()
logging.info('init and Clear')
epd.init(epd.lut_full_update)
epd.Clear(0xFF)

# === 1. show date & time
logging.info('show date & time')

def YMD(draw, x1=10, y1=5, x2=160, y2=30):
draw.rectangle((x1, y1, x2, y2), fill=255)
draw.text((x1, y1), time.strftime('%Y-%m-%d %a'), font = font, fill=0)

def HMS(draw, x1=180, y1=5, x2=280, y2=30):
draw.rectangle((x1, y1, x2, y2), fill = 255)
draw.text((x1, y1), time.strftime('%H:%M'), font = font, fill=0)

def MNIST(img, draw, mnist_img, x1=8, y1=30, x2=280, y2=120):
draw.rectangle((x1, y1, x2, y2), fill = 255)
mnist_img = Image.fromarray(mnist_img)
mnist_img = mnist_img.resize((38*2*3, 28*3))
img.paste(mnist_img, (x1, y1))

# partial update

time_image = Image.new('1', (epd.height, epd.width), 255)
time_draw = ImageDraw.Draw(time_image)

last_time = [-1, -1, -1, -1]
last_imgs = np.ones((4, 28, 28)) * 255

while (True):
now = time.localtime(time.time())
sec, mnt, hour = now.tm_sec, now.tm_min, now.tm_hour
m1, m2 = mnt//10, mnt%10
h1, h2 = hour//10, hour%10
now_time = [h1, h2, m1, m2]
print(f'{hour}:{mnt}:{sec}', last_time, now_time)

if -1 in last_time or (mnt == 0 and sec < 5) :
logging.info('partial update')
epd.init(epd.lut_full_update)
epd.Clear(0xFF)
time.sleep(1)

logging.info('partial update')
epd.init(epd.lut_partial_update)
epd.Clear(0xFF)
YMD(time_draw)
time.sleep(1)

for i in range(4):
if last_time[i] != now_time[i]:
last_imgs[i] = get_mnist_num(now_time[i])
last_time[i] = now_time[i]
mnist_image = np.hstack((last_imgs[0], last_imgs[1], gap,
last_imgs[2], last_imgs[3]))
HMS(time_draw)
MNIST(time_image, time_draw, mnist_image)

epd.display(epd.getbuffer(time_image))
time.sleep(1)

time.sleep(3)

# Clear
logging.info('Clear...')
epd.init(epd.lut_full_update)
epd.Clear(0xFF)

# Sleep
logging.info('Goto Sleep...')
epd.sleep()
epd.Dev_exit()


所有的文件

把有用的几个文件拉出来放在一个文件夹里。

1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── cv2_mnist_clock.py # 测试用 opencv 显示时间
├── epd29_mnist_clock.py # 在墨水屏显示时间
├── epd_2in9_test.py
├── lib
│ ├── epd2in9.py
│ ├── epdconfig.py
│ ├── Font.ttc
│ └── __init__.py
├── mnist_index_gen.py # 提取序号(index)
├── mnist_index.json # 保存序号(index),以 json 格式
└── mnist.npz # mnist 原始数据集

完整代码:

https://github.com/shenbo/mnist-clock

效果


灵感: https://github.com/dheera/mnist-clock