LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 1 year has passed since last update.

OpenCVでAIって何ができるの?

Last updated at Posted at 2022-04-11

OpenCVって?

OpenCVは画像処理で有名なオープンソースのライブラリです。20年以上前から開発されているライブラリなので本当に色々なことができます。

例えば画像の回転やリサイズといった基本的な処理はもちろんですがエッジやコーナの検出といった古典的な特徴点計算や主成分分析などの統計的手法を用いた画像処理も扱うことができます。

combine_images.jpg

さらに近年注目を集めている機械学習やAIモデル(ディープラーニング)も扱うことができ、日を追うごとに進化し続けています。そこで今回はAIモデルに着目して最新のOpenCVではどんなことができるのか調査してみました。

※ 調査対象は2021年12月リリースのバージョン4.5.5時点でPython実装されているものに限定しています。

OpenCVでAIモデルを使う

OpenCVで「データセットを使ってモデル学習!」といったことは残念ながらできないのですが、既に作成されたAIモデルを使って推論することは可能です。現時点でサポートされているフレームワークはTorchやTensorFlow, Darknet, ONNXなどを含めた合計6つで、これらのフレームワークで作成されたモデルファイルを読み込みことで推論することができます。

さっそく物体検出モデルYOLOv4をOpenCV上で動かしてみました。

combine_images (1).jpg

犬と猫が四角い枠で囲まれています。物体検出ではこのように検出された物体を四角い枠で囲います。この四角い枠をバウンディングボックス(BBox)と呼びBBoxの上に書かれている数字が信頼度を表す数値(スコア)です。このスコアが1に近いほど推論結果の信頼度が高いことになります。

サンプルコード

事前準備として物体検出したい画像(今回はdog_and_cat.jpg)とモデルの設定ファイルyolov4.cfg, yolov4.weightsが必要です。なお、設定ファイルはこちらからダウンロードさせていただきました。

※ 用意する設定ファイルはフレームワーク毎に異なります。詳しくはリファレンスを参照ください。
※ 検出結果を画像に反映させる部分は省略しています。

yolov4_on_OpenCV.py
import cv2

# 物体検出したい画像の読み込み
img = cv2.imread('./dog_and_cat.jpg')

# モデルの読み込み(Darknet)
net = cv2.dnn.readNet('./yolov4.cfg', './yolov4.weights')
# net = cv2.dnn.readNetFromDarknet('./yolov4.cfg', 'yolov4.weights')
model = cv2.dnn_DetectionModel(net)
model.setInputParams(scale=1 / 255, size=(416, 416), swapRB=True)

# 物体検出
detect_result = model.detect(img, confThreshold=0.7, nmsThreshold=0.4)
print(detect_result)
> [(array([15, 16], dtype=int32), array([0.76033837, 0.87054247], dtype=float32), array([[  0, 219, 291, 260],[259, 156, 374, 259]], dtype=int32))

サンプルコードの解説

# 物体検出したい画像の読み込み
img = cv2.imread('./dog_and_cat.jpg')

# モデルの読み込み(Darknet)
net = cv2.dnn.readNetFromDarknet('./yolov4.cfg', 'yolov4.weights')
# net = cv2.dnn.readNet('./yolov4.cfg', './yolov4.weights')
model = cv2.dnn_DetectionModel(net)
model.setInputParams(scale=1 / 255, size=(416, 416), swapRB=True)

まず最初に今回物体検出したい画像と使用するモデルを読み込みます。今回Darknetを使用しているのでモデルの読み込みをreadNetFromDarknet()としていますがコメントアウトしているreadNet()でも同じように動作します。

次に読み込んだモデルの入力画像に必要な処理をセットしています。これを記述することで画像のスケール調整やリサイズ、色空間の反転処理といった入力画像に必要な前処理をOpenCV側でやってくれます。YOLOシリーズの他にもSSD, Faster R-CNNといった物体検出モデルにも対応しているようです。

# 物体検出
detect_result = model.detect(img, confThreshold=0.7, nmsThreshold=0.4)

物体検出はmodel.detect()で行われます。各種パラメータについて確認します。

confThresholdではスコアの閾値を設定します。この値を大きくすることでより信頼性の高いものだけ物体検出することになります。一方nmsThresholdではIoUと呼ばれる値の閾値を設定しています。この値を大きくすることでBBoxの重なりを許容することになり、物体どうしが近くても正しく検出できるようになるのですが、あまりに大きくしすぎると同じ検出結果が排除されずダブりが生じます。例えばnmsThreshold=0.99と設定した場合、次のようにBBoxが重複した結果になります。

result.jpg

print(detect_result)
> [(array([15, 16], dtype=int32), array([0.76033837, 0.87054247], dtype=float32), array([[  0, 219, 291, 260],[259, 156, 374, 259]], dtype=int32))

最後に検出結果ですが左から検出した物体のリスト番号、スコア、BBoxの座標情報となっています。リスト番号というのは検出された物体がcoco.namesに記載されているリストの何番目のものなのかを表しています。Pythonの仕様上番号が1つ後ろにずれることに注意してください。例えば検出した結果の番号が15であればcoco.namesリストの16番目catを、16であればリストの17番目dogを指しています。

エッジデバイスなどフレームワーク環境が整っていない、あるいはリソースに制限があるような状況であってもAIモデルで推論することができそうです。

OpenCVの推論時間

OpenCV上でAIモデルを推論するときスコアや推論時間はどうなるのか気になったので調べてみました。今回はTensorFlowとONNXの2つのフレームワークで計測します。調査はGoogle ColaboratoryのCPU環境Intel(R) Xeon(R) CPU @ 2.20GHzで実施しました。

OpenCV vs. TensorFlow

ImageNetで学習済みのDenseNet121モデルを使用して300回の推論時間の平均を計算しました。推論には次の画像を使用しました。

mac_pc.jpg

フレームワーク 推論結果 スコア 平均推論時間(sec)
OpenCV 681(notebook / notebook computer) 0.564565 0.188474
TensorFlow 681(notebook / notebook computer) 0.564565 0.219263

tfvscv_mac.png

スコアは同じですが推論時間はOpenCVの方がはやいですね!!今回は計測から外しましたが、序盤の推論時間についてはTensorFlowの方が時間がかかる傾向にありました。一方でOpenCVは推論時間が不安定になる傾向がありました。

フレームワーク 1回目の推論時間(sec)
OpenCV 0.429673
TensorFlow 5.207420

tensorflow_densenet.png

opencv_densenet.png

OpenCV vs. ONNX

次にONNXの計測ですがこちらは独自に作成した物体検出モデルを使用します。このモデルはPytorchで上で学習したYOLOXモデルをONNXに変換したものです。YOLOXモデルの作成についてはこちらのブログで紹介していますので興味がある方は併せてご覧ください。こちらもGoogle ColaboratoryのCPU環境Intel(R) Xeon(R) CPU @ 2.20GHzで実施しました。また、推論に使用した画像と推論結果はこちらです。

combine_images (2).jpg

フレームワーク 平均推論時間(sec)
OpenCV 0.080006
ONNX 0.021513

onnxvccv2.png

こちらはONNX Runtimeの圧勝ですね。OpenCVでONNXを使うと推論時間がやや遅くなる傾向があるのかもしれません。

まとめ

今回はOpenCV上で学習済みモデルやYOLOXで作成した独自モデルを動かしてみました。また、CPU環境下での検証ではOpenCVの方が推論時間が短くなるケースがあるということがわかりました。エッジデバイスのようなリソースに制限があるような状況であってもOpenCVを使えば手軽にAIモデルを導入することができるようです。

(下記は記事掲載外)

エラーメモ

[ERROR:0@0.604] global /Users/xperience/actions-runner/_work/opencv-python/opencv-python/opencv/modules/dnn/src/onnx/onnx_importer.cpp (909) handleNode DNN/ONNX: ERROR during processing node with 2 inputs and 1 outputs: [Gather]:(StatefulPartitionedCall/model/tf_op_layer_Shape_2/Shape_2:0) from domain='ai.onnx'
Traceback (most recent call last):
  File "index.py", line 3, in <module>
    net = cv.dnn.readNet('./yolov4.onnx')
cv2.error: OpenCV(4.5.5) /Users/xperience/actions-runner/_work/opencv-python/opencv-python/opencv/modules/dnn/src/onnx/onnx_importer.cpp:928: error: (-2:Unspecified error) in function 'handleNode'
> Node [Gather@ai.onnx]:(StatefulPartitionedCall/model/tf_op_layer_Shape_2/Shape_2:0) parse error: OpenCV(4.5.5) /Users/xperience/actions-runner/_work/opencv-python/opencv-python/opencv/modules/dnn/src/onnx/onnx_importer.cpp:2580: error: (-215:Assertion failed) indexMat.total() == 1 in function 'parseGather'

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