ねぎとろ放浪記

ねぎとろ放浪記

個人的備忘録です。勉強したことをまとめていきます。

自動追尾カメラを作ろう その1

Arduino Advent Calendar 2020の10日目の記事です。

物体を認識して追尾するカメラを作りたい!

今回はその第一歩として、ARマーカーを追って動くカメラを作ろうと思います。


電子工作初心者で至らぬ点も多いと思いますがご了承ください。

できたもの

ARマーカーを追ってカメラが回転します。

部品

コード

Arduinoのコードです。

Pythonから値を受け取って、モーターを動かします。

#include <Servo.h>
 
Servo myservo;

byte r;

void setup() {
  Serial.begin(9600);
  myservo.attach(9);
  myservo.write(0);
}
 
void loop() {
  if (Serial.available()) {
      r = Serial.read(); //値を受け取る
      myservo.write(r); //モーターを動かす
  }
}


Pythonのコードです。

OpenCVでARマーカーを認識し、その方向へモーターを動かします。

import cv2 
import sys
import time
import serial
 
aruco = cv2.aruco #arucoライブラリ
dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)

FOV_H = 80 #カメラの水平画角
MAX_H = 180 #カメラを動かす範囲
 
def move_servo(): 
    cap = cv2.VideoCapture(0) #ビデオキャプチャの開始
    angle_h = MAX_H//2
 
    while True:
 
        ret, frame = cap.read() #ビデオキャプチャから画像を取得
 
        height, width = frame.shape[:2]
 
        #sizeを半分にする
        half_height = height // 2
        half_width = width // 2
        half_img = cv2.resize(frame, (half_width, half_height))
 
        corners, ids, rejectedImgPoints = aruco.detectMarkers(half_img, dictionary) #マーカを検出

        #マーカーがあれば中心のx座標を求める
        if len(corners) > 0:
            sum_x = 0
            for i in range(4) : sum_x += corners[0][0][i][0]
            ave_x = sum_x//4

            theta_h = int(ave_x * FOV_H // half_width)#画像左端を0とした角度

            #サーボモーターの制御
            if ave_x < half_width//4: #左側ならカメラを正の方向へ
                angle_h += (FOV_H//2 - theta_h)
                angle_h = min(MAX_H, angle_h)
            elif half_width//4 < ave_x < 3*(half_width//4): #中心に近いなら動かさない
                pass
            else: #画像の右側ならカメラを負の方向へ
                angle_h -= (theta_h - FOV_H//2)
                angle_h = max(0, angle_h)

            ser.write(bytes([angle_h])) #Arduinoに送る
 
        aruco.drawDetectedMarkers(half_img, corners, ids, (0,255,0)) #描画
 
        cv2.imshow('drawDetectedMarkers', half_img) #画像を表示
 
        cv2.waitKey(1)

        if cv2.waitKey(30) & 0xFF == ord('q'):
            break
 
    cap.release()
    cv2.destroyAllWindows()

    ser.close()
 

if __name__ == '__main__':
    ser = serial.Serial('/dev/cu.usbmodem144101', 9600, timeout = 0.1) #シリアル通信の開始
    time.sleep(3) #openしてからラグがあるので待機
    ser.write(bytes([MAX_H//2])) #最初に中心を向く

    move_servo()


以上、自動追尾カメラを作ろうその1でした。

次は上下方向にも動くようにする予定です。

最終的には物体検出と組み合わせて、任意のものを自動追尾できるようにしたいです。