概要は大体理解したので、とりあえず動かしてみる。
プログラムの動作を理解するにはサンプルプログラムを実行しながら処理内容を理解するのが一番早いと信じてます。
サンプルプログラムを読み解く
pythonのサンプルプログラムはいきなりGoogle Colabで実行できるので準備の手間が省けます。
mediapipe_pose.ipynb
resize_and_show
「resize_and_show」関数については、姿勢制御を行う対象の画像ファイルを縮小してGoogle Colab上に表示するための処理です。
実際の姿勢制御には直接関与しないので読み飛ばしても大丈夫です。
覚えておくのは以下の1行分だけです。
この部分でアップロードした画像ファイルを「images」に格納しています。
# Read images with OpenCV.
images = {name: cv2.imread(name) for name in uploaded.keys()}
mp_pose.Pose
まず、関数定義の引数から見ていきます。
「static_image_mode」は入力デーがが「画像」の場合は「True」を設定します。「False」にすると入力データは画像ではなく「動画」になります。
「min_detection_confidence」は姿勢制御結果の信頼度になります。0-1の間で信頼度が決まりますが、指定した値以上の信頼度がある場合に結果を返します。サンプルだと0.5なので50%みたいな感じでしょうか。
「model_complexity」はモデルの複雑さということですが、良く分からないですね。
with mp_pose.Pose(static_image_mode=True, min_detection_confidence=0.5, model_complexity=2) as pose:
最初の処理はBGR->RGB変換を行っています。
cv2.imreadで画像を読み込むとBGRの並びで画像データを格納するようなので、それをRGBの並びに変更しているそうです。
変換した画像データを「pose.process」に渡して姿勢推定を行います。
resultsに姿勢推定結果が格納されます。
# Convert the BGR image to RGB and process it with MediaPipe Pose.
results = pose.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
次の部分では、鼻の位置を例にして結果を抽出する例になります。
「results」の結果から、まずどの部位のデータを抽出するかを指定します。
この場合は鼻の位置を指定するので「mp_pose.PoseLandmark.NOSE」を指定しています。
最後に軸の指定をします。この例では「X軸」「Y軸」の情報を抽出しようとしています。
# Print nose landmark.
image_hight, image_width, _ = image.shape
if not results.pose_landmarks:
continue
print(
f'Nose coordinates: ('
f'{results.pose_landmarks.landmark[mp_pose.PoseLandmark.NOSE].x * image_width}, '
f'{results.pose_landmarks.landmark[mp_pose.PoseLandmark.NOSE].y * image_hight})'
)
実際には1つの部位に対して「X軸」「Y軸」「Z軸」「信頼度」の4つのデータが格納されています。
部位を指定しない状態で表示すると以下のように33のlandmarkが表示されます。このlandmarkが部位に対応しています。
以下を直接指定して取り出す書き方が上記になります。
print(results.pose_landmarks)
-----------------------------------------------------------
landmark {
x: 0.7385817766189575
y: 0.2223731428384781
z: -0.6112484335899353
visibility: 0.999993085861206
}
landmark {
x: 0.7549846172332764
y: 0.2076963186264038
z: -0.6207924485206604
visibility: 0.9999797344207764
}
landmark {
x: 0.7606263756752014
y: 0.20866425335407257
z: -0.6212761998176575
visibility: 0.9999778270721436
}
鼻のデータは最初のlandmarkになるのでこのようにするとデータを直接取り出せます。
print(results.pose_landmarks.landmark[mp_pose.PoseLandmark.NOSE].x)
print(results.pose_landmarks.landmark[mp_pose.PoseLandmark.NOSE].y)
print(results.pose_landmarks.landmark[mp_pose.PoseLandmark.NOSE].z)
print(results.pose_landmarks.landmark[mp_pose.PoseLandmark.NOSE].visibility)
----------------------------------------------------------------------------------
0.7385817766189575
0.2223731428384781
-0.6112484335899353
0.999993085861206
最後の部分では推定した位置情報を画像にプロットして出力する処理です。
私の今回の目的はプロットではなく位置情報を抽出する事なので以下のサンプルコードの説明は省略します。
ただ、ここまで理解できればあとは大体わかるでしょう。