はじめに
顔を追跡するカメラを目標にしてましたがおまけで物体追跡も試してみました。
おまけなので試すだけで投稿しないつもりでしたが、全然うまくいかず苦戦したので記録に残そうと思い投稿しました。
まあ原因はカメラモジュールが重すぎたせいだったりするんですが・・・
カメラモジュールからUSBカメラに変えたらうまくいきました。
参考サイト
PonDad様のこちらのサイトのものを使わせていただきました。
コード内のコメントはこちらのumentu様のコードを参考にさせていただきました。
構成図、回路図
過去のサーボと同じです。こちらを参照してください。
pythonコード
pythonのバージョンは3.5.3、OpenCVのバージョンは3.1.0で動作させました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
#!/usr/bin/python # -*- coding: utf-8 -*- import numpy as np import cv2 import time import pigpio pi = pigpio.pi() #x_move:range720-2370 #y_move:range1000-2315 def move(x_move, y_move): pi.set_servo_pulsewidth(4, x_move) pi.set_servo_pulsewidth(17, y_move) #X,Yのサーボで稼働させる範囲。適当によさげな範囲を指定。 X_MIN = 720 X_HOME = 1545 X_MAX = 2370 Y_MIN = 1000 Y_HOME = 1650 Y_MAX = 2300 #カメラの位置初期化 move(X_HOME, Y_HOME) #カメラ準備 cap = cv2.VideoCapture(0) # デフォルト画面サイズ横幅 W = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # デフォルト画面サイズ縦、高さ H = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # デフォルトfps fps = cap.get(cv2.CAP_PROP_FPS) #デフォルトの画面サイズとfpsを確認 #print('W,H,fps: ', W , H , fps) #メモ W,H,fps: 640.0 480.0 30.0 #画面サイズ横幅 cap.set(3, 320) #画面サイズ縦、高さ cap.set(4, 320) #fps cap.set(5, 15) #白色 color = (255, 255, 255) time.sleep(1) # 追跡する枠の座標とサイズ、320*320の真ん中なら110,110から100ずつ x, y, w, h = 110, 110, 100, 100 #はじめに指定した枠 track_window = (x, y, w, h) # フレームの取得 ret,frame = cap.read() # 追跡する枠を決定 roi = frame[y:y+h, x:x+w] #①test1画面箇所。初期取得全体画面 cv2.imshow('test2', frame) #②test2画面箇所。追跡する枠 cv2.imshow('test1', roi) #追跡する枠の内部を切り抜いてBGR→HSV変換 HSVだと操作しやすい hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) #③test3画面箇所。追跡する枠のHSV変換後 cv2.imshow('test3', hsv_roi) #マスク画像の作成。暗い光源化での追跡失敗を防ぐため、暗い画素値を無視する処理 img_mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.))) #④test4画面箇所。追跡する枠のマスク後 cv2.imshow('test4', img_mask) #確認のための待ち。 cv2.waitKey(0) # 正規化するためのヒストグラムの生成 roi_hist = cv2.calcHist([hsv_roi], [0], img_mask, [180], [0,180]) #試したい奴2 #roi_hist = cv2.calcHist([roi], [0], img_mask, [180], [0,180]) # ノルム正規化 cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX) # Setup the termination criteria, either 10 iteration or move by atleast 1 pt term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 ) #初期位置 now_degree_x, now_degree_y, move_degree_x, move_degree_y = X_HOME, Y_HOME, 0, 0 while(True): #画面取得 ret, frame = cap.read() if ret == True: #フレームをHSV変換する。BGR→HSV変換 HSVだと操作しやすい hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) #上で計算したヒストグラムを特徴量として、画像の類似度を求める dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180], 1) #物体検出する ret, track_window = cv2.meanShift(dst, track_window, term_crit) #物体検出で取得した座標を元のフレームで囲う x,y,w,h = track_window #物体検出した枠を長方形で囲む?色は白色 img_dst = cv2.rectangle(frame, (x,y), (x+w, y+h), (255,255,255), 3) #ここら辺までは画面サイズに従ってそう。 img_x = int(x+w/2) img_y = int(y+h/2) #ここから動かすところ。320/2で160。0.1箇所を大きくするとカメラが大きく 動く move_degree_x = now_degree_x - (img_x-160)*0.1 move_degree_y = now_degree_y + (img_y-160)*0.1 #実際にカメラを動かすところ move(move_degree_x, move_degree_y) now_degree_x = move_degree_x now_degree_y = move_degree_y #物体検出した中心点を丸で表す?色は緑色 cv2.circle(img_dst, (img_x, img_y), 10, (0,180,0), -1) #画面への描写 cv2.imshow('SHOW MEANSHIFT IMAGE', img_dst) k = cv2.waitKey(1) if k == ord('q'): break else: break cap.release() cv2.destroyAllWindows() |
以下箇所は私が動作確認したいがために追加したものです。物体追跡するためだけならコメントアウトしたほうがスムーズです。これがある4つの画面を閉じないと物体追跡してくれないので。。
cv2.imshow(‘test1’, frame)
cv2.imshow(‘test2’, roi)
cv2.imshow(‘test3’, hsv_roi)
cv2.imshow(‘test4’, img_mask)
cv2.waitKey(0)
動作について
流れとしては初めに画面中央に移った物体を追跡するものです。
物体追跡するものの見本です。
緑色のカラーボールを追跡してもらいました。
各 cv2.imshow 箇所で画像を取得してみました。
①test1箇所で取得した画像です。全体図ですね。
②test2箇所で取得した画像です。全体図から切り出したこの画像部分を追跡してくれます。
③test3で取得した画像です。test2のHSV変換後です。
④test4で取得した画像です。test2のマスク後です。
こちらは物体追跡しているときの画面です。
動画はこちらです。
最後に
カメラモジュールでやると重いからかうまく物体追跡してくれませんでした。。
ラズパイで物体追跡、顔認証するならUSBカメラのほうが安定すると思います。
コメント