Last active
September 19, 2017 04:03
-
-
Save jitomesky/442e586848d4dfa78843 to your computer and use it in GitHub Desktop.
GIFアニメ画像を2値化してArduino用のヘッダファイルを出力するプログラム
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
# -*- 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") |
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
/* | |
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