Skip to content

Instantly share code, notes, and snippets.

@jitomesky
Last active August 29, 2015 14:00
Show Gist options
  • Save jitomesky/c8e7dab2cf2915acf6a9 to your computer and use it in GitHub Desktop.
Save jitomesky/c8e7dab2cf2915acf6a9 to your computer and use it in GitHub Desktop.
RasPi モノクロ動画再生

Raspberry Piに接続したノキアのモノクログラフィック液晶で動画を再生するプログラムです。

大阪旅行に浮かれ、共立電子で買ったSparkfunのLCD-10168を使いました。

動画の読み込み、リサイズ、二値化にはOpenCVを使っています。

基本的な処理の流れは

  1. 動画を読み込む
  2. グレイスケールに変換
  3. リサイズ
  4. ガウス分布を用いたしきい値より二値化
  5. PIL形式に変換
  6. Raspberry Pi用PCD8544ライブラリで表示

という感じです。

ハードウェア接続

ピン接続の図はPCD8544ライブラリのREADMEにのっているので、これを参考にRaspberry Piと接続してください。

ただしここにのっているピン配置と、Sparkfunのモジュールのピン配置が違うので注意してください。

https://github.com/rm-hull/pcd8544/blob/master/README.md

インストール方法

動かすには以下のライブラリのインストールが必要です。

以下のコマンドを実行すると、全部入ります。

cd ~
mkdir src
cd src

sudo aptitude -y install ffmpeg opencv python-opencv

sudo aptitude -y install python-dev libi2c-dev
git clone https://github.com/rm-hull/wiringPi python_wiringPi
cd python_wiringPi
./build clean
./build

cd ~/src
sudo aptitude -y install zlibc libpng3 libfreetype6 libfreetype6-dev python-pip
sudo pip install pillow
git clone https://github.com/rm-hull/pcd8544
python2.7 setup.py clean build
sudo python setup.py install

使い方

sudo python2.7 play_movie_nokia5110.py hogehoge.mp4

動画

https://www.youtube.com/watch?v=w03oP7gNo10&feature=youtu.be

追記: 何故か処理が終わらないので、終わるまでしばらくお待ちください……。

TODO

フレームスキップとか全くやってないので遅い。

1分30秒の動画再生完了まで6分かかる。約4倍。

音声も出力して動画として見られるものにしたい。

参考サイト

http://www.yukun.info/blog/2008/07/python-command-line-arguments.html http://tatabox.hatenablog.com/entry/2013/07/15/164015 https://github.com/rm-hull/pcd8544/tree/master/examples http://tatabox.hatenablog.com/entry/2013/07/21/231751 http://tatabox.hatenablog.com/entry/2013/07/21/031410

# -*- coding: utf-8 -*-
import numpy as np
import cv2
import sys
import pcd8544.lcd as lcd
from PIL import Image
import threading
from Queue import Queue
import time
frameQueue_ = Queue()
def readVideo(filename):
# 動画を開く
cap = cv2.VideoCapture(filename)
while(cap.isOpened()):
try:
# フレーム読み込み
ret, frame = cap.read()
# グレイスケールに変換
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
except:
# 終了
cap.release()
cv2.destroyAllWindows()
quit()
# リサイズする
# 先にリサイズしたほうが、二値化後が綺麗
gray_resized = cv2.resize(gray, (84, 48))
# ガウス分布を用いたしきい値より二値化
resize_first = cv2.adaptiveThreshold(gray_resized,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
# プレビュー表示用
# cv2.imshow("resize first", resize_first)
# PCD9544ライブラリがもとめる画像形式に変換
PIL_data = Image.fromarray(resize_first)
im = Image.new('1',(84,48))
im.paste(PIL_data, (0,0) + PIL_data.size)
frameQueue_.put(im)
argvs = sys.argv
argc = len(argvs)
# 動画の指定は引数から行う
if (argc != 2):
print 'Usage: # python2.7 %s filename' % argvs[0]
quit()
# LCDを初期化
lcd.init()
lcd.backlight(0) # 1:OFF 0:ON
lcd.set_contrast(0xBF) # Sparkfunのモジュール(LCD-10168)はこの値が一番見やすい
# 読み込みを別スレッドで行う
t = threading.Thread(target=readVideo, args=(argvs[1],))
t.setDaemon(True)
t.start()
lcd.text("now loading...")
# 500フレーム先読み
while frameQueue_.qsize() < 500:
time.sleep(1)
# 読み込みが完了し、キューの中身が空になるまで繰り返す
while t.isAlive() or (not frameQueue_.empty()):
# imageメソッド内でポジション移動等全部やるので余計な処理はいらない
lcd.image(frameQueue_.get(),reverse=True)
# -*- coding: utf-8 -*-
import numpy as np
import cv2
import sys
import pcd8544.lcd as lcd
from PIL import Image
import threading
from Queue import Queue
import time
import subprocess
def readVideo(filename):
video_frames = []
# 動画を開く
cap = cv2.VideoCapture(filename)
# if not cap.isOpened():
# raise Exception('File not opend')
while(cap.isOpened()):
# フレーム読み込み
ret, frame = cap.read()
# 終了処理
if frame is None:
cap.release()
cv2.destroyAllWindows()
return video_frames
# グレイスケールに変換
gray = cv2.cvtColor(frame, 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)
# プレビュー表示用
# cv2.imshow("resize first", resize_first)
# PCD9544ライブラリがもとめる画像形式に変換
PIL_data = Image.fromarray(resize_first)
im = Image.new('1',(84,48))
im.paste(PIL_data, (0,0) + PIL_data.size)
# (画像, 表示時間)のタプルを追加
video_frames.append( (im, cap.get(cv2.cv.CV_CAP_PROP_POS_MSEC)) )
# print "msec: " + str(cap.get(cv2.cv.CV_CAP_PROP_POS_MSEC))
def playAudio_with_mplayer(filename):
subprocess.call(['mplayer', '-nogui', '-novideo', filename])
argvs = sys.argv
argc = len(argvs)
# 動画の指定は引数から行う
if (argc != 2):
print 'Usage: # python2.7 %s filename' % argvs[0]
quit()
filename = argvs[1]
# LCDを初期化
lcd.init()
lcd.backlight(1) # 1:OFF 0:ON
lcd.set_contrast(0xBF) # Sparkfunのモジュール(LCD-10168)はこの値が一番見やすい
lcd.text("now loading...")
# 全フレーム読み込みを待つ
frame_list = readVideo(filename)
while True:
lcd.backlight(1) # 1:OFF 0:ON
playtime_ms = 0.0
audio_t = threading.Thread(target=playAudio_with_mplayer, args=(filename,))
audio_t.setDaemon(True)
audio_t.start()
# mplayerが起動するのを少し待つ
time.sleep(0.3)
for frame in frame_list:
# 再生速度を調整する(単位はms)
waittime_ms = frame[1] - playtime_ms - 7
waittime_ms = waittime_ms if waittime_ms > 0 else 0
time.sleep( waittime_ms / 1000.0 )
playtime_ms = frame[1]
# imageメソッド内でポジション移動等全部やるので余計な処理はいらない
lcd.image(frame[0],reverse=True)
audio_t.join()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment