概要
ラズパイ4で GIF(Graphics Interchange Format)ファイルを作成しました。作成したファイルは次の通りです。複数の連続画像からコマ送り動画を作成します。
リンク
構成・接続
次の写真の通り、フィギュアをステップモーターで一定角度回転させて、写真手前のWEBカメラで撮影し、連続画像を作成します。カメラはUSB接続なので、空いているポートに挿入します。
過去投稿と同じですが、モーターは次の様に接続しています。
連続画像作成プログラム
次の様な連続画像を作成します。
今回は9度づつ回転し、40(枚/回転)の撮影を行っています。ファイル名は撮影時の回転角度を示します。
連続画像生成プログラムは次の通りです
import wiringpi as wp
import RPi.GPIO as GPIO
import struct
import time
import sys
import cv2
import os
import glob
SPI_CH = 0 # SPI チャンネル
SPI_HZ = 1000000 # SPI 通信速度
GPIO_Nbr = 25 # GPIO-NO
GPIO.setmode(GPIO.BCM) # GPIO-NO 指定
GPIO.setup(GPIO_Nbr,GPIO.IN) # GPIO INPUT 指定
# L6470初期設定
def INIT_L6470():
spi_send([0x00,0x00,0x00,0xc0]) # Reset Device
spi_send([0x05,0x00,0x0e]) # Acceleration (12)
spi_send([0x06,0x00,0x0e]) # Deceleration (12)
spi_send([0x07,0x00,0x0e]) # Maximum speed (10)
spi_send([0x08,0x00,0x01]) # Minimum speed (13)
spi_send([0x15,0x03,0xFF]) # Full-step speed (10)
spi_send([0x16,0x03]) # Micro Step (8)
spi_send([0x09,0x50]) # Holding Kval (8)
spi_send([0x0A,0x50]) # Constant Speed Kval (8)
spi_send([0x0B,0x50]) # Acceleration starting Kval (8)
spi_send([0x0C,0x50]) # Deceleration starting Kbal (8)
# SPI データ送信
def spi_send(spi_dat_ary):
for itm in spi_dat_ary:
tmp=struct.pack("B",itm)
wp.wiringPiSPIDataRW(SPI_CH, tmp)
# JOG (SPEED指定 : 0---30000)
def L6470_run(run_spd):
# 方向検出
if (run_spd > 0):
dir = 0x50
spd = run_spd
else:
dir = 0x51
spd = -1 * run_spd
L6470_SEND_MOVE_CMD( dir , spd )
# 移動量指定移動
def L6470_POSITIONING(MV_DIST):
# 方向検出
if (MV_DIST > 0):
dir = 0x40
else:
dir = 0x41
MV_DIST = -1 * MV_DIST
L6470_SEND_MOVE_CMD( dir , MV_DIST )
# 絶対位置指定移動
def L6470_MOVE_ABS(MV_DIST):
dir = 0x60
if (MV_DIST < 0):
MV_DIST = -1 * MV_DIST
L6470_SEND_MOVE_CMD( dir , MV_DIST )
# データ加工・送信(共通)
def L6470_SEND_MOVE_CMD( cmd , DAT ):
tmp=[]
tmp.append(cmd)
tmp.append((0x0F0000 & DAT) >> 16)
tmp.append((0x00FF00 & DAT) >> 8)
tmp.append((0x00FF & DAT))
spi_send(tmp)
# 停止指令
def L6470_STOP():
spi_send([0xB0]) # SOFT STOP
time.sleep(0.2)
spi_send([0xA8]) # Hard HiZ
time.sleep(0.2)
# 原点設定
def L6470_SET_ORIGIN():
spi_send([0xD8]) # Reset Position
time.sleep(0.5)
# 原点移動
def L6470_MOVE_ORIGIN():
spi_send([0x70]) # Go Home
time.sleep(0.5)
# ドライバーBUSY解除待ち
def wait_until_not_busy():
while True:
time.sleep(0.2)
mtr_sts = GPIO.input(GPIO_Nbr)
#print(mtr_sts)
if GPIO.input(GPIO_Nbr) == GPIO.HIGH :
#print("L6470 NOT BUSY")
break
time.sleep(0.2)
##################################
# メインプログラム
##################################
if __name__ == "__main__":
print("PROGRAM START")
file_list = glob.glob("./pic/*") # 保存先ファイル削除
for file in file_list:
os.remove(file)
wp.wiringPiSPISetup(SPI_CH,SPI_HZ) # SPI 接続
INIT_L6470() # L6470初期設定
L6470_SET_ORIGIN() # 原点位置設定(0)
capture = cv2.VideoCapture(0)
if capture.isOpened() is False:
raise IOError
rot_f = 0
loop_cnt = 0
while(True):
ret,frame=capture.read()
if ret is False:
raise IPError
frm_crp = frame[95:285,210:390]
cv2.imshow('frm_crp',frm_crp)
k = cv2.waitKey(1)
if k==27: # ESC
break
if k==49: # 1
print("MOVE START")
L6470_MOVE_ABS(0)
rot_f = 1
if rot_f > 0 and rot_f < 41 :
if GPIO.input(GPIO_Nbr) == GPIO.HIGH :
loop_cnt = loop_cnt + 1
if loop_cnt > 45 :
rot_step = 40 * rot_f
file_name = ("000"+str(int(360*(40*(rot_f-1))/1600)))[-3:]
cv2.imwrite("./pic/"+file_name + ".jpg" , frm_crp)
#print(str(int(360*rot_step/1600))+"deg ("+str(rot_step)+"step)")
print( file_name + "deg , " +str(rot_step) + "step")
L6470_MOVE_ABS(rot_step)
rot_f = rot_f + 1
loop_cnt = 0
GPIO.cleanup()
capture.release()
cv2.destroyAllWindows()
print("PROGRAM END")
sys.exit()
GIFファイル生成プログラム
連続画像から GIF ファイルを作成するプログラムです。
プログラムのあるディレクトリ下の “pic” というディレクトリ内にある全 jpeg ファイルを “Pillow” というライブラリで、GIFファイルに変換しています。
from PIL import Image
import glob
images = []
file_list = sorted(glob.glob("./pic/*.jpg"))
for filename in file_list:
im = Image.open(filename)
images.append(im)
images[0].save('out1.gif', save_all=True, append_images=images[1:], loop=0, duration=200)
プログラム12行目が、GIFファイルへの変換処理です。
images[0].save('out1.gif', save_all=True, append_images=images[1:], loop=0, duration=200)
変換保存時の指定パラメータは、下表の様になります。
変数 | 内容 |
images[0] | 1フレーム目になるImageオブジェクト |
‘out1.gif’ | 保存ファイル名(拡張子:gif) |
save_all=True | True : リスト画像全登録 , False : 静止画 |
append_images= images[1:] | 2フレーム目以降のImageオブジェクトリスト |
loop=0 | 0 : 無限ループ , 1 : ループしない |
duration=200 | フレーム表示間隔(単位:ミリ秒) 個別設定→duration=[1000, 50, 50, 300,・・・] |
まとめ
コマ送り動画なので、容量が小さくできる利点があるのだと思っています。途中で停止したり、反転は出来ないかな(?)という疑問を持ちました。