前回、MeidaPipeライブラリを使って手を検出するプログラムを紹介しました。今日はCVZoneというライブラリを使って、Webカメラに映った手を検出して、指の数をかぞえるプログラムを作成してみました。CVZoneはOpenCVとMediaPipeを利用したコンピュータビジョンのライブラリです。MediaPipeを使いやすくしたラッパーのようなものでしょうか。詳しくは以下のサイトを見てください。
https://github.com/cvzone/cvzone
また今日紹介するプログラムはこちらのビデオを参考にしています。
それでは早速、内容に入りましょう。
【準備】ライブラリのインストールと使用する画像
まず準備として、以下のコマンドでcvzoneとmediapipeをインストールします(OpenCVも必要です)。
|
1 2 |
pip install mediapipe pip install cvzone |
今回使うイメージファイルとプログラムのソースコードはこちらからダウンロードできます。
Pythonのスクリプトと「images」という名前のフォルダに「0.png」「1.png」「2.png」「3.png」「4.png」「5.png」という6つの画像が入っています。それぞれの画像には以下のように指の絵が描かれています。

今回のプログラムでは、検出された指の数に対応する上のイラストが画面に表示されるようになっています。
プログラムの内容(全体)
ソースコードの全体はこちら。
|
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 |
import cv2 import os from cvzone.HandTrackingModule import HandDetector cap = cv2.VideoCapture(1) cap.set(3, 640) # width cap.set(4, 480) # height # 手の画像が含まれているフォルダを指定して、ファイル名を取得する folderpath = "images" img_list = os.listdir(folderpath) # 手の画像を読み込む finger_imgs = [] for file in img_list: image = cv2.imread(f'{folderpath}/{file}') finger_imgs.append(image) detector = HandDetector(detectionCon=0.75) while True: success, img = cap.read() hands, img = detector.findHands(img) if hands: fingers = detector.fingersUp(hands[0]) finger_num = fingers.count(1) # 伸びている指の数を数える h, w, _ = finger_imgs[finger_num].shape img[0:h, 0:w] = finger_imgs[finger_num] # 指の数を表示する cv2.rectangle(img, (20, 250), (170, 450), (0, 255, 0), cv2.FILLED) cv2.putText(img, text=str(finger_num), org=(40, 410), fontFace=cv2.FONT_HERSHEY_COMPLEX, fontScale=6, color=(255, 0, 0), thickness=3) cv2.imshow("Image", img) key = cv2.waitKey(1) & 0xFF if key == ord('q'): break cap.release() cv2.destroyAllWindows() |
実行した様子はこちら。
プログラムの説明
内容について簡単に説明していきます。
|
1 2 3 4 5 6 7 |
import cv2 import os from cvzone.HandTrackingModule import HandDetector cap = cv2.VideoCapture(1) cap.set(3, 640) # width cap.set(4, 480) # height |
3行目で CVZone の手を検出するモジュールをインポートしています。
Webカメラのオブジェクトを作成します(5行目)。環境に合わせて引数の数字を変更してください。
またカメラの画像サイズは幅640 px、高さ480 pxにしています(6,7行目)。
|
9 10 11 12 13 14 15 16 17 18 19 20 |
# 手の画像が含まれているフォルダを指定して、ファイル名を取得する folderpath = "images" img_list = os.listdir(folderpath) # 手の画像を読み込む finger_imgs = [] for file in img_list: image = cv2.imread(f'{folderpath}/{file}') finger_imgs.append(image) detector = HandDetector(detectionCon=0.75) |
「images」フォルダにある手のイラスト画像を読みだす処理です。os.listdir 関数を使ってフォルダ内の全てのファイルをリストにして、それぞれを読み込んでいます。読み込んだイラスト画像は配列 finger_imgs に格納しています。
手を検出するモデルを作成します(19行目)。detectionCon パラメータは0~1.0の値を取り、高い値にすると検出の精度が高くなります(デフォルト値は0.5)。
|
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
while True: success, img = cap.read() hands, img = detector.findHands(img) if hands: fingers = detector.fingersUp(hands[0]) finger_num = fingers.count(1) # 伸びている指の数を数える h, w, _ = finger_imgs[finger_num].shape img[0:h, 0:w] = finger_imgs[finger_num] # 指の数を表示する cv2.rectangle(img, (20, 250), (170, 450), (0, 255, 0), cv2.FILLED) cv2.putText(img, text=str(finger_num), org=(40, 410), fontFace=cv2.FONT_HERSHEY_COMPLEX, fontScale=6, color=(255, 0, 0), thickness=3) cv2.imshow("Image", img) key = cv2.waitKey(1) & 0xFF if key == ord('q'): break |
Webカメラから画像を読み込み、モデルで手の検出をしています(22,23行目)。
もし手が見つかった場合、fingersUp 関数でどの指が伸びているかを調べます(26行目)。fingersUp 関数の戻り値(変数 fingers)は5つの要素をもつリストで、1もしくは0の値が入っています。1だと指が上がっていて、0だと下がっています。たとえば以下のようにすると、どの指が上がっているかを判定できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
if detector.fingersUp(hands[0]) == [0, 0, 0, 0, 0]: # どの指も上がっていないときの処理 elif detector.fingersUp(hands[0]) == [1, 0, 0, 0, 0]: # 親指だけが上がっているときの処理 elif detector.fingersUp(hands[0]) == [0, 1, 0, 0, 0]: # 人差し指だけが上がっているときの処理 elif detector.fingersUp(hands[0]) == [0, 0, 1, 0, 0]: # 中指だけが上がっているときの処理 elif detector.fingersUp(hands[0]) == [0, 0, 0, 1, 0]: # 薬指だけが上がっているときの処理 elif detector.fingersUp(hands[0]) == [0, 0, 0, 0, 1]: # 小指だけが上がっているときの処理 elif detector.fingersUp(hands[0]) == [1, 1, 1, 1, 1]: # 全ての指が上がっているときの処理 |
今回はどの指が上がっているかの判定はせず、fingers.count(1) で上がっている指の数をかぞえて(27行目)、その数に対応するイラスト画像を表示するようにしています(28~31行目)。また指の数を数値としても表示しています(32行目)。
キーボードの Q ボタンを押すとプログラムを終了するようにしています(35~37行目)。
さいごに
実行した様子のビデオでも分かる通り、かなり高い精度で指を検出できているのではないでしょうか。このプログラムをちょっと変えてやれば、じゃんけんゲームなんかが作れそうですね。
今日の内容が誰かのお役に立てば幸いです。
- 投稿タグ
- プログラミング