Skip to content

Instantly share code, notes, and snippets.

@stestagg
Created October 2, 2016 23:31
Show Gist options
  • Save stestagg/f9238eb9d859b5563f1216d09b56c39e to your computer and use it in GitHub Desktop.
Save stestagg/f9238eb9d859b5563f1216d09b56c39e to your computer and use it in GitHub Desktop.
#!/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