#!/usr/bin/env python
##### モデル tiny YOLO の設定 #################
from core.utils import load_class_names, load_image, draw_boxes, draw_boxes_frame
from core.yolo_tiny import YOLOv3_tiny
from core.yolo import YOLOv3
# object のクラス
class_names, n_classes = load_class_names()
iou_threshold = 0.1
confidence_threshold = 0.25
model = YOLOv3_tiny(n_classes=n_classes, iou_threshold=iou_threshold, confidence_threshold=confidence_threshold)
import tensorflow as tf
inputs = tf.placeholder(tf.float32, [1, *model.input_size, 3])
detections = model(inputs)
saver = tf.train.Saver(tf.global_variables(scope=model.scope))
##### servo の設定 ##########################
import RPi.GPIO as GPIO
# GPIOの設定
GPIO.setmode(GPIO.BOARD)
pan_servo_pin = 16
tilt_servo_pin = 18
GPIO.setup(pan_servo_pin, GPIO.OUT)
GPIO.setup(tilt_servo_pin, GPIO.OUT)
# PWM (Pulse Width Modulation) の設定
# SG90 の周波数は50Hz (周期20ms)
pan_servo_pwm = GPIO.PWM(pan_servo_pin, 50)
tilt_servo_pwm = GPIO.PWM(tilt_servo_pin, 50)
##### servo の動作 (関数) ##########################
from time import sleep
# 指定角度 (単位 : 度) にサーボを定位
def servo_angle(servo, degree):
duty = 9.5 * degree / 180 + 7.25
if servo == 'pan' :
pan_servo_pwm.ChangeDutyCycle(duty)
else:
tilt_servo_pwm.ChangeDutyCycle(duty)
sleep(2)
##### カメラ取込画像 ##########################
# ヨコ, タテ
CAMERA_WIDTH = 640
CAMERA_HEIGHT = 480
# 中心
img_center_x = CAMERA_WIDTH/2
img_center_y = CAMERA_HEIGHT/2
##### カメラ映像画面の dx, dy に対するサーボの dpan, dtilt の比例定数 (実験値)
pixel2deg = -0.1
##### トラッキング対象 #################
target_class = 'sports ball'
# 配列 class_names における target object の番号 target_n を求める
for n in range(len(class_names)):
if class_names[n] == target_class:
target_n = n
break
##### exit プロセス #################
import cv2
import sys
def destroy():
#サーボモータをストップ
servo_angle('pan', 0)
pan_servo_pwm.stop()
servo_angle('tilt', 0)
tilt_servo_pwm.stop()
#GPIOをクリーンアップ
GPIO.cleanup()
#カメラキャプチャを停止
cap.release()
#ストリーミングウインドを閉じる
cv2.destroyAllWindows()
#プログラムを終了
sys.exit()
##### START ##########################
# pan, tilt を 0° (Duty比 7.25) からスタート
pan_deg = 0
pan_servo_pwm.start(7.25)
sleep(2)
tilt_deg = 0
tilt_servo_pwm.start(7.25)
sleep(2)
with tf.Session() as sess:
# モデル tiny YOLO の読み込み
saver.restore(sess, './weights/model-tiny.ckpt')
# カメラ映像の読み込み
# カメラの番号:0
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
# ヨコ,タテ
frame_size = (frame.shape[1], frame.shape[0])
resized_frame = cv2.resize(frame, dsize=tuple((x) for x in model.input_size[::-1]), interpolation=cv2.INTER_NEAREST)
result = sess.run(detections, feed_dict={inputs: [resized_frame]})
#カメラ映像の表示
draw_boxes_frame(frame, frame_size, result, class_names, model.input_size)
cv2.imshow('frame', frame)
#### target_class の検出 ####
boxes_dict = result[0]
resize_factor = (frame_size[0] / model.input_size[1], frame_size[1] / model.input_size[0])
boxes = boxes_dict[target_n]
if( len(boxes) != 0):
print("\nターゲット発見")
for box in boxes:
coordinates = box[:4]
coordinates = [int(coordinates[i] * resize_factor[i % 2]) for i in range(4)]
# object の中心
object_center_x = int((coordinates[0]+coordinates[2])/2)
object_center_y = int((coordinates[1]+coordinates[3])/2)
# 画像中心からの object 中心のズレ
dx = object_center_x - img_center_x
dy = object_center_y - img_center_y
print("中心ズレ:" + str(dx) + ", " + str(dy))
# カメラ方向からの角度ズレ
dpd = round( pixel2deg * dx )
dtd = round( pixel2deg * dy )
print("角度ズレ:" + str(dpd) + ", " + str(dtd))
# dxが大きいとき,pan 駆動
if abs(dx) > 20:
servo_angle('pan', pan_deg)
# モータ入力値の更新
# +, - は,ズレを解消するサーボの回転方向に依存)
pan_deg = pan_deg + dpd
# dyが大きいとき,tilt 駆動
if abs(dy) > 15:
servo_angle('tilt', tilt_deg)
# モータ入力値の更新
# +, - は,ズレを解消するサーボの回転方向に依存)
tilt_deg = tilt_deg - dtd
# 残りの box は取り上げない
break
# <for box in boxes> ここまで
# <if( len(boxes) != 0)> ここまで
# 画像ウィンドウをアクティブにして 'q' キーを押すと, break
if cv2.waitKey(10) & 0xFF == ord('q'):
destroy()
|