静止画でオブジェクト検出 【Raspberry Pi & Tensorflow Lite】

Machine Learning

Raspberry Pi にインストールした Tensorflow Lite のライブラリを使って、静止画1枚に対してオブジェクト検出をする Python のスクリプトを作ってみます。

以下の環境で動作を確認しています。
環境:
・ Raspberry Pi (bullseye)
・ Tensorflow Lite インストール済み
・ 学習済み教師データはインストール時のまま使用

背景 Tensorflow Lite のスクリプトを作ってみる

以前に、Tensorflow Lite のオブジェクト検出のスクリプトを Raspberry Pi にインストールする方法についてまとめています。
Raspberry Pi に USB カメラをつなぐと、カメラのライブ画像上で、物体検出のプログラムが動きます。
ところが、このスクリプトは USB カメラのライブ画像で動くサンプルとなっています。写真など静止画を指定してオブジェクト検出をすることはできない(?)ようです。
そこで、静止画1枚に対しても物体検出のプログラムが動くよう Python のスクリプトを作り、まとめておくことにします。
ライブ動画ではオブジェクト検出は実際に機能しているので、何とでもなるはずです。

手順

① あらかじめ事前に、Raspberry Pi に Tensorflow Lite のオブジェクト検出のプログラムをインストールしておきます。インストールの手順は、関連リンクを参照してください。
例: /home/pi/tensorflow_lite1/
※ インストールするフォルダを上記とします。インストールしたフォルダが上記と異なる場合は、以後、フォルダの位置を読み替え、必要によりプログラムを修正してください。
※ 正常に Tensorflow Lite のインストールが終わると、上記のフォルダに、以下のファイル等が入っていると思います。
・ detect.py (USB カメラをつなぐとライブ画像上で物体検出する Python のスクリプト)
・ utils.py (検出結果を描画するユーティリティ用のスクリプト )
・ efficientdet_lite0.tflite (Tensorflow Lite 用の学習済みファイル)
・ README.md
② ①のフォルダ内に、あらたに、detect_image1.py という名前で新たにテキストファイルを作成し、末尾のスクリプトをコピー&ペーストして保存してください。
例: /home/pi/tensorflow_lite1/detect_image1.py
③ オブジェクト検出をさせる画像を入れたフォルダを作成し、画像を入れてください。
例: /home/pi/image01/screen_shot1/240120_120000.png
④ ターミナルを起動し、以下を参考に、Python のスクリプトを実行してください。
コマンドの形式: “python [detect_image1.pyのパス] [画像のパス]
コマンドの例: python /home/pi/tensorflow_lite1/detect_image1.py /home/pi/image01/screen_shot1/240120_120000.png

→ オブジェクト検出の実行結果が表示されたら成功です!
表示画面上で任意のキーを押すと、プログラムが終了します。

※ オブジェクト検出は、画像によってはうまくいかないことがあります。画像をいくつか変えて試してみてください。
※ なお、上記のコマンドの例は、「ウェブサイトのスクリーンショットを自動化する 【Raspberry Pi 版】」で取得したネット上のライブカメラの画像に対して、オブジェクト検出をする事例としています。

スクリプトの説明

・ スクリプトの冒頭で os, sys など、必要なモジュールをインポートしています。画像の変換に OpenCV (cv2) を使います。
・ from tflite_… となっているところで、Tensorflow Lite をインポートしています。
・ utils (utils.py) は、物体検出の結果を矩形や文字で元の画像上に描くためのユーティリティです。Tensorflow Lite をインストールした際についてくると思います。

・ def detection1() としたところは、物体検出する関数です。
学習済み教師モデル model1 と、物体検出を行う画像 image1 を渡したら、画像を Tensorflow 用に色変換をし、さらに、”テンソルイメージ” tsr_image1 に変換します。
物体検出を行う際のオプションの設定を option1, 2, 3 で作り、detector1 = … とした行でデテクターを作ります。
このデテクターにテンソルイメージ tsr_image1 を流すことで、物体検出の結果 result1 を取得し、関数の戻り値として返します。
・ def object_counter1() は、物体検出の結果 result1 を調べて、どういう物体をいくつ見つけたかをカウントする関数です。自作しています。
・ detect_image1.py を実行すると、path1 = … とした行以降、順次、スクリプトを実行しています。
・ model1 は、学習済み教師モデルで、スクリプト内で指定しています。
・ file1 は、物体検出を行う画像で、OpenCV を使って画像 image1 を読み込んだ後、上記の detection1() 関数に渡すことで物体検出を行います。
その後、見つかった物体と数を表示させたあと、image2 = … の行で、画像上に検出した領域の描画をしています。
物体検出の結果を表示した後、任意のキーを待ち、キー入力があればスクリプトを終了します。
※ detection1() 関数内部の max_results=10、score_threshold=0.3 としたところで、検出する物体の最大数、検出する際の閾値(感度)を設定しています。うまく動いたら、数値を変えてみて、使いたい環境に応じて調整してみてください。
※ num_threads=4 とした行では、Raspberry Pi で使えるコア数などを指定しています。
※ object_counter1() 関数で、検出結果 result1 を print させているところをコメントアウトしています。
検出結果から、見つかった物体の座標を出力したいなど、カスタマイズしたいときは、このコメントアウト部分を出力させてみて、検出結果の出力フォーマットを確認してみてください。
たとえば、Raspberry Pi でサーボモーターと組み合わせることで、見つけた物体をトレースするよう動くロボットなども製作できると思います。

まとめ

TensorFlow Lite のライブラリを参照し Python のスクリプトを作成することで、任意の静止画に対しても物体検出のプログラムが動くようになりました。
この程度のプログラムに慣れてくると、あとはどのようにでもカスタマイズできそうな気がしてきます。

内部リンク
・ TensorFlow Lite を Raspberry Pi にインストール
・ ウェブサイトのスクリーンショットを自動化する 【Raspberry Pi 版】
・ ネット上のライブカメラの動画を自作のHTMLに埋め込む
・ サーボモーターを動かす 【Raspberry Pi】

サンプルスクリプト

オブジェクト検出のスクリプト detect_image1.py

import os 
import sys
from operator import itemgetter 

import cv2
from tflite_support.task import core
from tflite_support.task import processor
from tflite_support.task import vision
import utils

def detection1( model1, image1 ): 
  rgb_image1 = cv2.cvtColor( image1, cv2.COLOR_BGR2RGB )                            # rgb image 
  tsr_image1 = vision.TensorImage.create_from_array( rgb_image1 )                   # tensor image 
  options1 = core.BaseOptions( file_name=model1, use_coral=False, num_threads=4 )   # GPU:False CPU_threads:4 
  options2 = processor.DetectionOptions( max_results=10, score_threshold=0.3 )
  options3 = vision.ObjectDetectorOptions( base_options=options1, detection_options=options2 )
  detector1 = vision.ObjectDetector.create_from_options( options3 )
  result1 = detector1.detect( tsr_image1 )
  return result1 

def object_counter1( result1 ): 
  # print( result1 ) 
  n0 = len( result1.detections ) 
  a1 = [] 
  for i1 in range(n0): 
    str1 = result1.detections[i1].categories[0].category_name 
    a1.append( str1 ) 
    a1.sort()
  a2 = [] 
  if n0 > 0: 
    str1 = a1[0] 
    n1 = 1 
    for i1 in range(len(a1)-1): 
      str2 = a1[i1+1] 
      if str1 == str2: 
        n1 = n1 + 1 
      else: 
        a2.append( [str1, n1] ) 
        str1 = str2 
        n1 = 1 
    a2.append( [str1, n1] ) 
    a2.sort( key=itemgetter(0) ) 
    a2.reverse() 
    a2.sort( key=itemgetter(1) ) 
    a2.reverse() 
  return a2 

path1 = os.path.dirname( __file__ ) + "/" 
model1 = path1 + "efficientdet_lite0.tflite" 
file1 = sys.argv[1]                           # image file (*.png etc.) 
image1 = cv2.imread( file1 )                  # bgr image 

result1 = detection1( model1, image1 )        # object detection 

a1 = object_counter1( result1 ) 
print( a1 ) 

image2 = utils.visualize( image1, result1 )   # bgr image 

cv2.imshow( 'object_detector', image2 )

cv2.waitKey(0)   # any key 

タイトルとURLをコピーしました