Created
October 2, 2016 23:31
-
-
Save stestagg/f9238eb9d859b5563f1216d09b56c39e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import smbus2 | |
import time | |
import numpy as np | |
import cv2 | |
from collections import deque | |
class Display: | |
COMMAND_REG = 128 | |
DATA_REG = 0x40 | |
ON = 175 | |
OFF = 174 | |
CHARGE_PUMP_SET = 141 | |
SET_ROW = 176 | |
TOP_TO_BOTTOM = 200 | |
LEFT_TO_RIGHT = 161 | |
SET_ADDR_MODE = 32 | |
SET_COL_ADDR = 0x21 | |
SET_PAGE_COL_START_LO = 0x00 | |
SET_PAGE_COL_START_HI = 0x10 | |
SET_PAGE_ROW = 0xB0 | |
ADDR_MODE_HORIZ = 0b00 | |
ADDR_MODE_VERT = 0b01 | |
ADDR_MODE_PAGE = 0b10 | |
CHARGE_PUMP_ON = 20 | |
def __init__(self, display_addr=60, i2c_addr=1): | |
self.i2c = smbus2.SMBus(i2c_addr) | |
self._addr = display_addr | |
self._buffer = self._make_buffer() | |
self._next_buffer = self._make_buffer() | |
def _make_buffer(self): | |
return np.zeros((8,128), dtype=np.uint8) | |
def _command(self, *cmds): | |
for cmd in cmds: | |
self.i2c.write_byte_data(self._addr, self.COMMAND_REG, cmd) | |
@property | |
def raw_buffer(self): | |
return self._next_buffer | |
def setup(self): | |
self._command(self.OFF) | |
time.sleep(0.1) | |
self._command(self.ON) | |
self._command(self.TOP_TO_BOTTOM, self.LEFT_TO_RIGHT) | |
self._command(self.SET_ADDR_MODE, self.ADDR_MODE_PAGE) | |
self.repaint_all() | |
self._command(self.CHARGE_PUMP_SET, self.CHARGE_PUMP_ON) | |
def set_pixel(self, col, row, val): | |
bit_index = row % 8 | |
mask = 1 << bit_index | |
if val: | |
self._next_buffer[row//8,col] |= mask | |
else: | |
self._next_buffer[row//8,col] &= ~mask | |
def set_update_pos(self, row, col): | |
col_lo = col & 0b00001111 | |
col_hi = (col & 0b11110000) >> 4 | |
self._command( | |
self.SET_PAGE_COL_START_LO | col_lo, | |
self.SET_PAGE_COL_START_HI | col_hi, | |
self.SET_PAGE_ROW | row | |
) | |
def clear(self): | |
self._next_buffer = [0x0] * 1024 | |
self.repaint_dirty() | |
def _send_display_data(self, data): | |
MAX_CHUNK = 32 | |
for start in range(0, len(data), MAX_CHUNK): | |
chunk = data[start:start+MAX_CHUNK] | |
self.i2c.write_i2c_block_data(self._addr, self.DATA_REG, chunk) | |
def repaint_all(self): | |
for row in range(8): | |
self.set_update_pos(row,0) | |
self._send_display_data(self._next_buffer[row]) | |
np.copyto(self._buffer, self._next_buffer) | |
def repaint_dirty(self): | |
for row, (old_row, new_row) in enumerate(zip(self._buffer, self._next_buffer)): | |
if np.array_equal(old_row, new_row): | |
continue | |
compare = old_row != new_row | |
start_index = np.argmax(compare) | |
end_index = len(compare) - np.argmax(compare[::-1]) - 1 | |
self.set_update_pos(row, start_index) | |
self._send_display_data(new_row[start_index:end_index+1]) | |
np.copyto(self._buffer, self._next_buffer) | |
def __setitem__(self, index, value): | |
if isinstance(index, (list, tuple)): | |
assert len(index) == 2 | |
col, row = index | |
self.set_pixel(col, row, value) | |
def draw_pb(percent, display): | |
bar_wid = 105 | |
bar_offset = 12 | |
pixels = int(percent * bar_wid / 100) | |
display.raw_buffer[4, bar_offset:bar_offset+pixels] = 255 | |
display.raw_buffer[4, bar_offset+pixels:bar_wid] = 0 | |
display.repaint_dirty() | |
SKIP_SECONDS = 6370 | |
def play(display): | |
for i in range(10, 117): | |
display[i, 30] = True | |
display[i, 41] = True | |
for i in range(30, 42): | |
display[10, i] = True | |
display[117, i] = True | |
display.repaint_dirty() | |
draw_pb(5, display) | |
vid = cv2.VideoCapture("mx.mp4") | |
draw_pb(25, display) | |
fps = vid.get(cv2.CAP_PROP_FPS) | |
print("FPS: %s" % (fps, )) | |
draw_pb(30, display) | |
vid.set(cv2.CAP_PROP_POS_MSEC, SKIP_SECONDS * 1000) | |
draw_pb(75, display) | |
last_frames = deque([], 4) | |
THRESH = 128 | |
while vid.isOpened(): | |
_, frame = vid.read() | |
gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) | |
scaled = cv2.resize(gray, (128, 64), cv2.INTER_CUBIC) | |
bw = cv2.adaptiveThreshold(scaled,1,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,15,-1) | |
last_frames.append(bw) | |
combined = np.copy(bw) | |
for frame in last_frames: | |
combined += frame | |
_, combined_bw = cv2.threshold(combined, len(last_frames)-1, 1, cv2.THRESH_BINARY) | |
by_byte = combined_bw.transpose().reshape((128, 8, 8))[:,:,::-1] | |
bits = np.squeeze(np.packbits(by_byte, -1)).transpose() | |
np.copyto(display.raw_buffer, bits) | |
display.repaint_dirty() | |
if __name__ == '__main__': | |
display = Display() | |
display.setup() | |
play(display) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment