0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MediaPipeでsolutionsが無い?解決法まとめ

0
Posted at

はじめに

Pythonで手の認識をしたかった。

調べると、どうやらMediaPipeというライブラリを使うといいらしい。

そこでAIにコードを書いてもらって試したところ、こんなエラーが出た。

AttributeError: module 'mediapipe' has no attribute 'solutions'

どうやら、solutionsが新しいバージョンでは削除されているらしい

具体的には、バージョン0.10.30 で削除されたようだ。

しかし困ったことに、

  • AIの生成するコード
  • 少し前のQiita記事
  • 古いチュートリアル

このあたりは、だいたい mp.solutions を使っている。

どうすればいいのかの情報があまり無いので、解決法をまとめる。

結論としては、次の2つ↓

解決法その1:MediaPipeのバージョンを下げる

こちらの方が簡単でおすすめです。

メリット

  • AIのコードがそのまま使える
  • 情報が豊富
  • Qiita記事をそのまま試せる

インストール

solutions が使えるバージョンをインストールする。

pip install mediapipe==0.10.21

OpenCVも必要なので忘れずに。

pip install opencv-python

バージョン確認

import mediapipe as mp

print(mp.__version__)

出力:

0.10.21

これでOK。

手の認識を試す

あとはAIに聞けばだいたい教えてくれる。

例えば、以下のコードはChatGPTに書いてもらったもの。

import cv2
import mediapipe as mp

# MediaPipe Hands
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
    static_image_mode=False,
    max_num_hands=2,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5
)

mp_draw = mp.solutions.drawing_utils

# カメラ起動
cap = cv2.VideoCapture(0)

while True:
    success, frame = cap.read()
    if not success:
        break

    # 左右反転
    frame = cv2.flip(frame, 1)

    # BGR -> RGB
    rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

    # 手検出
    results = hands.process(rgb)

    # 検出結果描画
    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            mp_draw.draw_landmarks(
                frame,
                hand_landmarks,
                mp_hands.HAND_CONNECTIONS
            )

    cv2.imshow("Hand Tracking", frame)

    # ESCで終了
    if cv2.waitKey(1) == 27:
        break

cap.release()
cv2.destroyAllWindows()

実行すると、

  • カメラが起動
  • "Hand Tracking"ウィンドウが表示
  • 手を映すとランドマークが描画

されるはず。

個人的には、この方法がいちばん楽だった。

解決法その2:Tasks API に移行する

こちらは、最新版のMediaPipeを使いたい人向け。

最新版ではsolutionsの代わりにTasks APIを使う必要がある。

メリット

  • 新しいAPIが使える
  • ジェスチャー認識ができる
  • 右手・左手を識別できる

※ちゃんと調べていないので、他にもあるかもしれない。

デメリット

  • とにかく情報が少ない
  • AIが平然と存在しないコードを書く

正直、こだわりが無いならバージョンダウンのほうをおすすめします。

しかし、最新版至上主義者のみなさん(私含む)のために、やり方をまとめます。

準備

MediaPipeをインストール

pip install mediapipe

OpenCVも忘れずに。

pip install opencv-python

モデルをダウンロードする

新版では、モデルファイルを自分でダウンロードする必要がある。

旧版では不要だったので、最初かなり困惑した。

# モデルをダウンロード
import urllib.request

url = "https://storage.googleapis.com/mediapipe-models/gesture_recognizer/gesture_recognizer/float16/latest/gesture_recognizer.task"

urllib.request.urlretrieve(url, "gesture_recognizer.task")

print("downloaded")

実行後、gesture_recognizer.task がダウンロードされていればOK。

認識結果を描画する

旧版で使えた mp.solutions.drawing_utils は使えなくなっている。

そこで、Google公式サンプルコードを使う。

少し改変したコードがこちら。

# 少し改変
import mediapipe as mp
import numpy as np
import cv2

mp_hands = mp.tasks.vision.HandLandmarksConnections
mp_drawing = mp.tasks.vision.drawing_utils
mp_drawing_styles = mp.tasks.vision.drawing_styles

MARGIN = 10
FONT_SIZE = 1
FONT_THICKNESS = 1
HANDEDNESS_TEXT_COLOR = (88, 205, 54)

def draw_landmarks_on_image(rgb_image, detection_result):
    hand_landmarks_list = detection_result.hand_landmarks
    handedness_list = detection_result.handedness
    annotated_image = np.copy(rgb_image)

    for idx in range(len(hand_landmarks_list)):
        hand_landmarks = hand_landmarks_list[idx]

        # ランドマーク描画
        mp_drawing.draw_landmarks(
            annotated_image,
            hand_landmarks,
            mp_hands.HAND_CONNECTIONS,
            mp_drawing_styles.get_default_hand_landmarks_style(),
            mp_drawing_styles.get_default_hand_connections_style()
        )

        # テキスト表示位置
        height, width, _ = annotated_image.shape
        x_coordinates = [landmark.x for landmark in hand_landmarks]
        y_coordinates = [landmark.y for landmark in hand_landmarks]

        text_x = int(min(x_coordinates) * width)
        text_y = int(min(y_coordinates) * height) - MARGIN

        # 元の認識結果
        handedness = handedness_list[idx][0].category_name

        # 左右反転しているので入れ替え
        if handedness == "Left":
            handedness_text = "Right"
        else:
            handedness_text = "Left"

        cv2.putText(
            annotated_image,
            handedness_text,
            (text_x, text_y),
            cv2.FONT_HERSHEY_DUPLEX,
            FONT_SIZE,
            HANDEDNESS_TEXT_COLOR,
            FONT_THICKNESS,
            cv2.LINE_AA
        )

    return annotated_image

後で出てくるコードで、カメラ映像を左右反転している。
そのままだと右手と左手が逆になるので、表示を入れ替えている。

カメラ映像を取得して認識する

やっていること↓

カメラ映像取得
↓
手を認識
↓
結果を描画
↓
画面表示
↓
ループ

コードはこちら。

import cv2
import mediapipe as mp

def camera_loop(cap, recognizer):
    while True:
        success, frame = cap.read()

        if not success:
            break

        # 左右反転
        frame = cv2.flip(frame, 1)

        # BGR -> RGB
        rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        # mediapipe.Image に変換
        mp_image = mp.Image(
            image_format=mp.ImageFormat.SRGB,
            data=rgb
        )

        # 手検出
        results = recognizer.recognize(mp_image)

        # 検出結果描画
        if results.hand_landmarks:
            annotated_rgb = draw_landmarks_on_image(rgb, results)

            # RGB -> BGR
            frame = cv2.cvtColor(
                annotated_rgb,
                cv2.COLOR_RGB2BGR
            )

        cv2.imshow("Hand Tracking", frame)

        # ESCで終了
        if cv2.waitKey(1) == 27:
            break

最後に実行するコード

以下を実行すれば動くはず。

import mediapipe as mp

BaseOptions = mp.tasks.BaseOptions
GestureRecognizer = mp.tasks.vision.GestureRecognizer
GestureRecognizerOptions = mp.tasks.vision.GestureRecognizerOptions
VisionRunningMode = mp.tasks.vision.RunningMode

model_path = "gesture_recognizer.task"

options = GestureRecognizerOptions(
    base_options=BaseOptions(
        model_asset_path=model_path
    ),
    running_mode=VisionRunningMode.IMAGE
)

with GestureRecognizer.create_from_options(options) as recognizer:

    # カメラ起動
    cap = cv2.VideoCapture(0)

    try:
        camera_loop(cap, recognizer)

    finally:
        # エラー時でもちゃんと閉じる
        cap.release()
        cv2.destroyAllWindows()

実行すると、

  • カメラ起動
  • 手を認識
  • ランドマーク描画
  • "Hand Tracking" ウィンドウに表示

されるはず。

おわりに

MediaPipeを試そうとしたところ、コードが動かなくて困惑した。
調べたら、仕様変更があったことは分かった。
しかし、新バージョンでどうすれば動かせるのか情報が少なくて困った。
そのために解決法をまとめた。

同じところでハマった人の助けになればうれしいです。

全体コードはこちら

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?