【Raspberry Pi】ディープラーニングで検出したオブジェクトの位置情報を取得する

  • URLをコピーしました!

※本ページはアフィリエイト広告を利用しています

今回はロボットに搭載するディープラーニングを使った画像処理アプリケーションが完成したので記事にしたいと思います。

以前書いたTensorFlow Liteによる物体検出を行うプログラムをさらに改良して、検出したオブジェクトの位置情報を取得できるようにしてみました。

また、OpenCVの活用事例についても以下の記事で解説していますので、あわせてご覧ください。

目次

Raspberry Pi(ラズベリーパイ)とは

Raspberry Pi(ラズベリーパイ)はイギリスのラズベリーパイ財団が教育用に開発したボードコンピュータです。

最新のRaspberry Pi 4では、ARMアーキテクチャを採用したBroadcom製の高性能SoC BCM2711を搭載しており、1.5GHzで動作するARM Cortex-A72が4コアとマイコンボードの中では非常に高速な処理能力を持っています。また、ユーザーがアクセス可能な40ピンのGPIOも搭載しており、外部ハードウェアを制御することが可能です。

詳細なスペック等は以下の記事で解説していますので、あわせてご覧ください。

やりたいこと

例えば、人間や犬を発見すると近寄ってくる、あとをついて歩いてくるような動作をロボットにさせたいと思っています。
そんな時、ロボットが「追跡する目標を発見する」というのは、ディープラーニングを使えば可能です。そして目標に近づくためには、「ロボットをどちらの方向に向ければ良いか」を判断する必要があります。その方向を判断をするための処理実装してみました。

以下の図のように、ロボットを追従させてい犬がいるとします。

ロボットとオブジェクトの位置関係

その場合、まず検出した「犬」というオブジェクトがカメラの中心から右側にいるのか、左側にいるのかによって、ロボットが回転するべき方向を判断します。

そして、次に中心からオブジェクトまでの距離によって、どれくらいの角度を回転させれば良いのかを判断するという流れになります。

使用するロボット

使用するロボットはRaspberry Piベースのスパイダーロボット、PiCrawlerです。
詳細は以下のページをご覧ください。

環境

ハードウェア:Raspberry Pi 3 ModelB
OS:Raspbian 10.11
OpenCV:4.1.0.25
カメラ:OV5647
TensorflowLite-bin:2.5.0

ディープラーニングによる物体検出

Googleが公開している機械学習のソフトウェアライブラリ、TensorFlow Liteを使って物体検出をするプログラムを実装したことを以前記事にしました。

今回はこのPINTO氏がチューニングされた高速推論処理エンジン、TensorflowLite-binのソースコードをベースに、改良したものを実装してみました。
PINTO氏のGithubリポジトリは以下となります。

著:Sebastian Raschka, 著:Vahid Mirjalili, 著:株式会社クイープ, 著:福島 真太朗
¥3,960 (2024/09/19 15:03時点 | Amazon調べ)

作成したソースコード

今回は先ほど紹介したPINTO氏の公開しているリポジトリにある「mobilenetv2ssd-sync-usbcam.py」のソースコードを一部改変する形で実装しましたので、その部分だけ紹介します。

このソースファイルの「overlay_on_image」というメソッドに、検出したオブジェクト部分に枠線とラベルを描画する処理が実装されています。

以下のように改変することで、画面上の座標情報を計算できるようにしました。

def overlay_on_image(frames, object_infos, camera_width, camera_height):

    color_image = frames
    
    if isinstance(object_infos, type(None)):
        return color_image
        
    img_cp = color_image.copy()
    
    #座標情報を取得
    img_bottom = img_cp.shape[0] #画像の高さを取得
    img_right = img_cp.shape[1] #画像の横幅を取得
    
    #通信の座標を取得
    img_bottom_center = int(img_bottom / 2) #中心点 高さ
    img_right_center = int(img_right / 2) #中心点 横幅
    for obj in object_infos:
    
        #オブジェクトの座標を取得
        box_left = int(obj[0][0])
        box_top = int(obj[0][1])
        box_right = int(obj[1][0])
        box_bottom = int(obj[1][1])
        
        #オブジェクトの中心点を取得
        box_right_center = int(box_left + ((box_right - box_left) / 2))
        box_bottom_center = int(box_top + ((box_bottom - box_top) / 2))
        
        #座標情報を出力
        print("box_right_center", box_right_center)
        print("box_bottom_center", box_bottom_center)
        
        #画面の中心からオブジェクトの中心まで直線を引く
        cv2.line(img_cp, (box_right_center, box_bottom_center), (img_right_center, img_bottom_center), (0, 0, 255), 3) #第2引数:始点 第3引数:終点
        
        #オブジェクトのX軸方向の中心点までの距離
        cv2.putText(img_cp, str(img_right_center - box_right_center), (box_right_center + 3, box_bottom_center + 3), cv2.FONT_HERSHEY_SIMPLEX, 0.5, label_text_color, 1)
        
        #長方形を描画
        cv2.rectangle(img_cp, (box_left, box_top), (box_right, box_bottom), box_color, box_thickness)
        percentage = int(obj[2] * 100)
        label_text = obj[3] + " (" + str(percentage) + "%)"
        print("Label = ", label_text)
        
        label_size = cv2.getTextSize(label_text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)[0]
        label_left = box_left
        label_top = box_top - label_size[1]
        
        if (label_top < 1):
            label_top = 1
        label_right = label_left + label_size[0]
        label_bottom = label_top + label_size[1]
        
        cv2.rectangle(img_cp, (label_left - 1, label_top - 1), (label_right + 1, label_bottom + 1), label_background_color, -1)
        cv2.putText(img_cp, label_text, (label_left, label_bottom), cv2.FONT_HERSHEY_SIMPLEX, 0.5, label_text_color, 1)
        
    cv2.putText(img_cp, fps,       (camera_width-170,15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (38,0,255), 1, cv2.LINE_AA)
    cv2.putText(img_cp, detectfps, (camera_width-170,30), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (38,0,255), 1, cv2.LINE_AA)
    
    return img_cp

14、15行目:
画面の中心点の座標を計算します。

25、26行目:
各オブジェクトの中心点の座標を計算します。

33行目:
画面の中心から各オブジェクトの中心まで直線を描画します。

36行目:
画面の中心から各オブジェクトの中心までのX軸方向の距離を計算し、表示します。

実行結果

以下の画像のように画面の中心から各オブジェクトの中心までの距離を計算、表示することができました。

オブジェクトが画面中央より左側にある時はプラス、中央より右側にある場合はマイナスで距離が表示されます。つまり距離の符号を見て、プラスならロボットを左回転、マイナスならロボットを右回転させれば良いということになります。

また画面中央からの距離が大きければ旋回する角度を大きく、距離が小さければ旋回する角度を小さくすることで、常にロボットを目標の方向へ向けることができます。

実際に距離を計測している様子を動画で撮影してみました。

リアルタイムにオブジェクトまでの距離を計算して表示できていることが見て頂けるかと思います。

\ Pythonを自宅で好きな時に学べる! /

まとめ

今回のオブジェクトの位置計算処理を実装したことにより、カメラからロボットの行動を制御するのに必要な情報を取得することができるようになりました。
このオブジェクトの位置情報を使ってロボットを人間に追従させる機能の実装について、以下の記事で解説しています。


機械学習を学びたい方向けに、以下の記事を公開しています。

また、以下の記事で効率的にPythonのプログラミングスキルを学べるプログラミングスクールの選び方について解説しています。最近ではほとんどのスクールがオンラインで授業を受けられるようになり、仕事をしながらでも自宅で自分のペースで学習できるようになりました。

スキルアップや副業にぜひ活用してみてください。

スクールではなく、自分でPythonを習得したい方には、いつでもどこでも学べる動画学習プラットフォームのUdemyがおすすめです。

講座単位で購入できるため、スクールに比べ非常に安価(セール時1200円程度~)に学ぶことができます。私も受講しているおすすめの講座を以下の記事でまとめていますので、ぜひ参考にしてみてください。

それでは、また次の記事でお会いしましょう。

著:山内 直, 著:大久保 竣介, 著:森本 梨聖, 監修:太田 昌文
¥2,618 (2024/09/19 16:36時点 | Amazon調べ)

\ Raspberry Piを使ったアプリ開発を学びたい人には自宅で学べるUdemyがおすすめ! /

講座単位で購入できます!

おすすめ記事

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次