Up daiarg作 detect.py 作成: 2021-05-12
更新: 2021-05-13


    「RaspberryPi4にYOLOv3-Tinyを実装して‥‥」のプログラムをテストしようとしたが,起動でエラーが返され,叶わず。


    #!/usr/bin/env python import tensorflow as tf import cv2 import sys import numpy as np from core.yolo_tiny import YOLOv3_tiny import picamera import io import RPi.GPIO as GPIO import wiringpi #学習クラス def load_class_names(): #学習クラスのリスト _CLASS_NAMES_FILE = './data/coco.names' #Returns a list of string corresonding to class names and it's length with open(_CLASS_NAMES_FILE, 'r') as f: class_names = f.read().splitlines() return class_names, len(class_names) #サーボモータの設定 def getServoDutyHw(id, val): val_min = 0 val_max = 4095 # デューティ比0%を0、100%を1024として数値を入力 # 50Hz(周期20ms)、デューティ比3.5%: 3.5*1024/100=約36 servo_min = 36 # 50Hz(周期20ms)、デューティ比10%: 10*1024/100=約102 servo_max = 102 if id==1: servo_min = 53 servo_max = 85 duty = int((servo_min - servo_max)*(val - val_min)/(val_max - val_min) + servo_max) if duty > servo_max: duty = servo_max if duty < servo_min: duty = servo_min return duty def main(): #各種初期設定------------------ #カメラの解像度 CAMERA_WIDTH = 512 CAMERA_HEIGHT = 384 #GPIOの設定 GPIO.setmode(GPIO.BCM) GPIO.setup(4, GPIO.OUT) GPIO.output(4, GPIO.LOW) #サーボモータで使用するピンNo. PWM0 = 19 PWM1 = 18 #サーボモータへの入力の初期値 input_x = 2048 input_y = 2048 # wiringPi によるハードウェアPWM # GPIO名で番号を指定する wiringpi.wiringPiSetupGpio() # 左右方向のPWM出力を指定 wiringpi.pinMode(PWM0, wiringpi.GPIO.PWM_OUTPUT) # 上下方向のPWM出力を指定 wiringpi.pinMode(PWM1, wiringpi.GPIO.PWM_OUTPUT) # 周波数を固定するための設定 wiringpi.pwmSetMode(wiringpi.GPIO.PWM_MODE_MS) # 50 Hz。18750/(周波数) の計算値に近い整数 wiringpi.pwmSetClock(375) # PWMのピン番号とデフォルトのパルス幅をデューティ100%を1024として指定。 # ここでは6.75%に対応する69を指定 wiringpi.pwmWrite(PWM0, 69) wiringpi.pwmWrite(PWM1, 69) #---------------------------------- 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) inputs = tf.placeholder(tf.float32, [1, *model.input_size, 3]) detections = model(inputs) saver = tf.train.Saver(tf.global_variables(scope=model.scope)) with tf.Session() as sess: saver.restore(sess, './weights/model-tiny.ckpt') stream = io.BytesIO() #cap = cv2.VideoCapture(0) cap = picamera.PiCamera() #カメラ解像度の設定 ※この値を変えたらutils_busters.pyの値も変更する cap.resolution = (CAMERA_WIDTH, CAMERA_HEIGHT) n = 0 #初期位置に戻すためのカウント #---------------------ここから while ループ--------------------- while True: #カメラ撮影 cap.capture(stream, format='jpeg') #numpy型に変換 data = np.frombuffer(stream.getvalue(), dtype=np.uint8) #opencv型に変換 frame = cv2.imdecode(data, 1) 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]}) #撮影画像の表示 cv2.imshow('frame', frame) boxes_dict = result[0] resize_factor = (frame_size[0] / model.input_size[1], frame_size[1] / model.input_size[0]) n = n + 1 for cls in range(len(class_names)): boxes = boxes_dict[cls] #ターゲットを「バナナ」に if np.size(boxes) != 0 and class_names[cls] == "banana": #初期位置戻しリセット n=0 for box in boxes: xy = box[:4] xy = [int(xy[i] * resize_factor[i % 2]) for i in range(4)] #ターゲットの中心(水平方向) target_x = int((xy[0]+xy[2])/2) #ターゲットの中心(垂直方向) target_y = int((xy[1]+xy[3])/2) #水平方向のカメラ取込画素のの中心値 img_center_x = CAMERA_WIDTH/2 #垂直方向のカメラ取込画素のの中心値img_center_y = CAMERA_HEIGHT/2 #ターゲットとカメラの中心ズレ(水平方向) dx = img_center_x - target_x #ターゲットとカメラの中心ズレ(垂直方向)dy = img_center_y - target_y #モータ入力値の更新。4は想定通り動くか確認して決めた実験値。 input_x = input_x - 4 * dx #モータ入力値の更新。4は想定通り動くか確認して決めた実験値。 input_y = input_y - 4 * dy #モータが回りすぎないようににリミッタ設定 if input_x > 4095: input_x = 4095 if input_x < 0: input_x = 0 if input_y > 2048: input_y = 2048 if input_y < 1500: input_y = 1500 duty0 = getServoDutyHw(0, input_x) duty1 = getServoDutyHw(0, input_y) print("ターゲット発見") print("ターゲット中心:" + str(target_x) + ", " + str(target_y)) print("画像中心:" + str(img_center_x)+ ", " + str(img_center_y)) print("中心ズレ:" + str(dx) + ", " + str(dy)) #dxが大きい時 if abs(dx) > 20: #dxもdyが大きい時は両方のモータ を動かす if abs(dy) > 15: #水平モータ駆動 wiringpi.pwmWrite(PWM0, duty0) #垂直モータ駆動 wiringpi.pwmWrite(PWM1, duty1) #dxが大きい時は水平方向のみのモータ を動かす else: #水平モータ駆動 wiringpi.pwmWrite(PWM0, duty0) #dxが小さい時 else: #dyが大きい時は垂直方向のモータ を動かす if abs(dy) > 15: #垂直モータ駆動 wiringpi.pwmWrite(PWM1, duty1) #ターゲットが鳥でない場合 else: #10回検知しなかったら初期位置に戻す if n == 10: wiringpi.pwmWrite(PWM0, 69) wiringpi.pwmWrite(PWM1, 69) elif n > 10: #nを11でストップ n=11 #カメラのリセット stream.seek(0) #「q」を押すと,while ループをブレイク (画面表示の停止へ) if cv2.waitKey(1) & 0xFF == ord('q'): break #---------------------ここまで while ループ--------------------- #画面表示の停止 #カメラのリセット stream.seek(0) #カメラキャプチャを停止 cap.close() #画面ウインドを消去 cv2.destroyAllWindows() if __name__ == '__main__': main()