Skip to content

Instantly share code, notes, and snippets.

@jitomesky
Last active September 19, 2017 04:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jitomesky/442e586848d4dfa78843 to your computer and use it in GitHub Desktop.
Save jitomesky/442e586848d4dfa78843 to your computer and use it in GitHub Desktop.
GIFアニメ画像を2値化してArduino用のヘッダファイルを出力するプログラム
# -*- coding: utf-8 -*-
import numpy as np
import cv2
from PIL import Image, ImageSequence, ImageDraw
import time
import unittest
import sys
# original code : http://playground.arduino.cc/Code/PCD8544
WIDTH = 84
HEIGHT = 48
def cvImageToBinaryString(cvImage):
row = 0;
col = 0;
bit = 0;
# バイナリの格納先を指定
ba = np.zeros((HEIGHT/8, WIDTH), dtype=np.uint8)
# 要素数が正しいかチェック
assert len(ba) == HEIGHT / 8, "ba height missmuch"
assert len(ba[0]) == WIDTH, "ba width missmuch"
# TODO: 全部0か調べる
PIL_data = Image.fromarray(cvImage).convert('1')
# PIL_data.show()
# 0 or 1 の1行バイナリ列に変換
b = list([0 if x else 1 for x in PIL_data.getdata()])
binaryString = ""
for i in range(WIDTH * HEIGHT):
val = b[i]
ba[row, col] |= val << bit
# next col
col += 1
# next bit
if col >= WIDTH:
col = 0
bit += 1
# next data row
if bit >= 8:
bit = 0
for x in range(WIDTH):
s = "%x" % ba[row, x]
assert "0x" + s == hex(ba[row, x]), "hex convert failture"
# Do some formatting
if len(s) > 2:
s = s[-2:]
while len(s) < 2:
s = "0" + s
binaryString += "0x" + s + ","
binaryString += "\n"
row += 1
# 最後のコロンを削除
binaryString = binaryString[:-2]
return binaryString
def gif89a_alpha_merge(now_frame, pre_frame):
nowf_rgba = now_frame.convert('RGBA')
pref_rgba = pre_frame.convert('RGBA')
img = Image.alpha_composite(pref_rgba, nowf_rgba)
return img
if __name__ == '__main__':
name = sys.argv[1]
im = Image.open(name)
binStr_List = []
bframe = im.convert('RGB')
for fn,f in enumerate(ImageSequence.Iterator(im)): #using the class from the PIL handbook
# gif89aなら透過色の処理を入れる
if im.info['version'] == "GIF89a" and fn > 0:
f = gif89a_alpha_merge(f, bframe)
PIL_data = f.convert('RGB')
bframe = PIL_data
# PILからOpenCVに変換
OpenCV_RGB = np.asarray(PIL_data)
# 色をRGB から BGRに変換
OpenCV_BGR = cv2.cvtColor(OpenCV_RGB, cv2.COLOR_RGB2BGR)
# グレイスケール化
gray = cv2.cvtColor(OpenCV_BGR, cv2.COLOR_BGR2GRAY)
# リサイズする
# 先にリサイズしたほうが、二値化後が綺麗
gray_resized = cv2.resize(gray, (84, 48))
# ガウス分布を用いたしきい値より二値化
resize_first = cv2.adaptiveThreshold(gray_resized,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
binStr_List.append( cvImageToBinaryString(resize_first) )
# 表示
cv2.imshow('frame', OpenCV_BGR )
cv2.imshow('binary_mini', resize_first )
time.sleep(0.1)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
# ファイル書き込み
f = open("gifHeader.h", 'w')
f.write('#include "Arduino.h"' + "\n")
f.write('#include <avr/pgmspace.h>' + "\n\n")
f.write("#define PICTURE_ENTRY " + str(len(binStr_List)) + "\n")
f.write("#define PICTURE_SIZE " + str(len(binStr_List[0].split(','))) + "\n\n")
for i,binStr in enumerate(binStr_List):
f.write("PROGMEM prog_uchar gifAnime_" + str(i) + "[] = { \n")
# f.write(" { \n ")
f.write(binStr)
# f.write("\n }")
f.write(",\n" if i != (len(binStr_List) - 1) else "\n")
f.write("};\n\n")
f.write("PROGMEM prog_uchar *gifAnimePointer[] = { \n")
for i in range(len(binStr_List)):
f.write(" gifAnime_" + str(i) + ",\n")
f.write("};\n")
/*
7-17-2011
Spark Fun Electronics 2011
Nathan Seidle
This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
This code writes a series of images and text to the Nokia 5110 84x48 graphic LCD:
http://www.sparkfun.com/products/10168
Do not drive the backlight with 5V. It will smoke. However, the backlight on the LCD seems to be
happy with direct drive from the 3.3V regulator.
Although the PCD8544 controller datasheet recommends 3.3V, the graphic Nokia 5110 LCD can run at 3.3V or 5V.
No resistors needed on the signal lines.
You will need 5 signal lines to connect to the LCD, 3.3 or 5V for power, 3.3V for LED backlight, and 1 for ground.
*/
#include "gifHeader.h"
#define PIN_SCE 10
#define PIN_RESET 9
#define PIN_DC 6
#define PIN_SDIN 2
#define PIN_SCLK 3
#define PIN_LED 12
//The DC pin tells the LCD if we are sending a command or data
#define LCD_COMMAND 0
#define LCD_DATA 1
//You may find a different size screen, but this one is 84 by 48 pixels
#define LCD_X 84
#define LCD_Y 48
void setup(void) {
LCDInit(); //Init the LCD
Serial.begin(9600);
}
void loop(void) {
char buffer[PICTURE_SIZE];
char *gifPointer;
for(int i=0;i<PICTURE_ENTRY;i++){
//LCDClear();
gifPointer = (char *)pgm_read_word_near(gifAnimePointer + i);
for(int j=0; j < PICTURE_SIZE; j++){
buffer[j] = (char)pgm_read_byte_near(gifPointer + j);
}
//memcpy(buffer, (char *)pgm_read_word())
LCDBitmap(buffer);
// delay(500);
}
// delay(1000);
}
void gotoXY(int x, int y) {
LCDWrite(0, 0x80 | x); // Column.
LCDWrite(0, 0x40 | y); // Row. ?
}
//This takes a large array of bits and sends them to the LCD
void LCDBitmap(char my_array[]){
for (int index = 0 ; index < (LCD_X * LCD_Y / 8) ; index++)
LCDWrite(LCD_DATA, my_array[index]);
}
//Clears the LCD by writing zeros to the entire screen
void LCDClear(void) {
for (int index = 0 ; index < (LCD_X * LCD_Y / 8) ; index++)
LCDWrite(LCD_DATA, 0x00);
gotoXY(0, 0); //After we clear the display, return to the home position
}
//This sends the magical commands to the PCD8544
void LCDInit(void) {
//Configure control pins
pinMode(PIN_SCE, OUTPUT);
pinMode(PIN_RESET, OUTPUT);
pinMode(PIN_DC, OUTPUT);
pinMode(PIN_SDIN, OUTPUT);
pinMode(PIN_SCLK, OUTPUT);
pinMode(PIN_LED, OUTPUT);
//Reset the LCD to a known state
digitalWrite(PIN_RESET, LOW);
digitalWrite(PIN_RESET, HIGH);
// LED ON
digitalWrite(PIN_LED, HIGH);
LCDWrite(LCD_COMMAND, 0x21); //Tell LCD that extended commands follow
LCDWrite(LCD_COMMAND, 0xBF); //Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark
LCDWrite(LCD_COMMAND, 0x04); //Set Temp coefficent
LCDWrite(LCD_COMMAND, 0x14); //LCD bias mode 1:48: Try 0x13 or 0x14
LCDWrite(LCD_COMMAND, 0x20); //We must send 0x20 before modifying the display control mode
LCDWrite(LCD_COMMAND, 0x0C); //Set display control, normal mode. 0x0D for inverse
}
//There are two memory banks in the LCD, data/RAM and commands. This
//function sets the DC pin high or low depending, and then sends
//the data byte
void LCDWrite(byte data_or_command, byte data) {
digitalWrite(PIN_DC, data_or_command); //Tell the LCD that we are writing either to data or a command
//Send the data
digitalWrite(PIN_SCE, LOW);
shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
digitalWrite(PIN_SCE, HIGH);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment