0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CustomVisionのモデルをOpenCVで推論(ラズパイ4+Windows10)

Last updated at Posted at 2020-11-17

はじめに

ラズパイやJetsonでCustomVision推論するときに、時間かかるわエラーが出るわでなぜかonnxruntimeが入らないのでOpenCVでやってみようと思いました。その予行演習としてまずはWindowsノートPCで動かしてラズパイ+Windowsで動かそうと思います。ちなみに、ノートPCで推論するなら普通にonnxruntime入れるほうが手っ取り早いです。

ノートPCで推論

環境

  • Python3.6(Anaconda)
  • OpenCV>=4.0.0

必要なライブラリは、OpenCVとpillowとnumpyです。

pip install pillow numpy opencv-python

OpenCVはバージョン4以降じゃないとだめかもです。
CustomVisionのモデルは、ONNXでエクスポートしてダウンロードしておいてください。Compactドメインで学習して、パフォーマンスタブからエクスポートできます(参考)。
展開したら以下のような構成になっていると思います。C#とPythonのサンプルコードがついてます。

$ tree /f
E:.
│  cvexport.manifest
│  labels.txt
│  LICENSE
│  model.onnx
│
├─CSharp
│      ObjectDetection.cs
│
└─python
    │  cntk_predict.py
    │  object_detection.py
    │  onnxruntime_predict.py
    │
    └─__pycache__
            object_detection.cpython-36.pyc

pythonというフォルダに移動して以下のコードを保存します。

inference.py
import cv2
import numpy as np
from object_detection import ObjectDetection
from PIL import Image, ImageDraw

filename = 'test1.png'        # 推論したい画像のパス
modelname = '../model.onnx'   # 推論に使うモデルのパス
labelpath = '../labels.txt'   # エクスポートした中にあったlabels.txtへのパス

class ODbyCV2(ObjectDetection):
    def __init__(self, model_filename, labels):
        super(ODbyCV2, self).__init__(labels)
        self.model = cv2.dnn.readNetFromONNX(modelname)
    def predict(self, img):
        img = self.pil2cv(img)
        h,w,c = img.shape
        self.model.setInput(cv2.dnn.blobFromImage(img,size=(w,h),swapRB=True,crop=False))
        results = self.model.forward()
        return np.squeeze(results).transpose((1,2,0)).astype(np.float32)
    def pil2cv(self, image):
        new_image = np.array(image, dtype=np.uint8)
        if new_image.ndim == 2:
            pass
        elif new_image.shape[2] == 3:
            new_image = cv2.cvtColor(new_image, cv2.COLOR_RGB2BGR)
        elif new_image.shape[2] == 4:
            new_image = cv2.cvtColor(new_image, cv2.COLOR_RGBA2BGRA)
        return new_image

# ラベル読み込み
with open(labelpath, 'r') as f:
    labels = [l.strip() for l in f.readlines()]

model = ODbyCV2(modelname,labels)
img = Image.open(filename)

# 推論
results = model.predict_image(img)
print(results)

# 以下推論結果の表示
img = cv2.imread(filename)
height,width,channel = img.shape

font_face = cv2.FONT_HERSHEY_DUPLEX
font_scale = 0.6
font_thickness = 1
for result in [results[0]]:
    # if result['probability'] >= 0.3:
    text_str = str(int(result['tagName']))
    text_w, text_h = cv2.getTextSize(text_str, font_face, font_scale, font_thickness)[0]
    score_w, score_h = cv2.getTextSize(str(round(result['probability'],2)), font_face, font_scale, font_thickness)[0]
    x1 = int(width*result['boundingBox']['left'])
    y1 = int(height*result['boundingBox']['top'])
    x2 = int(width*result['boundingBox']['width']+width*result['boundingBox']['left'])
    y2 = int(height*result['boundingBox']['height']+height*result['boundingBox']['top'])
    text_pt = (x1, y1 - 3)
    text_color = [255,255,255]
    rgb = [255,0,0]
    cv2.rectangle(img, (x1, y1),(x2,y2),rgb,2)
    cv2.rectangle(img, (x1, y1),(x1+text_w,y1-text_h-4),rgb,-1)
    cv2.rectangle(img, (x1, y1),(x1+score_w,y1+score_h+4),rgb,-1)
    cv2.putText(img, text_str, text_pt, font_face, font_scale, text_color, font_thickness, cv2.LINE_AA)
    cv2.putText(img, str(round(result['probability'],2)), (x1, y1 +score_h), font_face, font_scale, text_color, font_thickness, cv2.LINE_AA)
        
cv2.imshow('test',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

エクスポートしてきたときについているサンプルコードを参考にしました。object_detection.pyのObjectDetectionクラスを継承してpredict関数をオーバーライドしています。このコードを実行すると以下のような結果が得られます。8がtagName、0.72がprobabilityです。

result.png

ラズパイ(Windows10)で推論

環境

  • Raspberry Pi4 Model B 4GB RAM
  • Windows10

ラズパイでWindows10を動かす方法は、こちらを参考にしてください。

結論からいうと上記と全く同じ流れでできます。しかし、NumpyがWindows+Armに対応してないのか、import時に以下のようなwarningが出て、推論時にもたくさんwarningが出てきます。

C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:172: RuntimeWarning: divide by zero encountered in exp2
  eps=exp2(ld(-112)),
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:51: RuntimeWarning: divide by zero encountered in log10
  self.precision = int(-log10(self.eps))
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:52: RuntimeWarning: divide by zero encountered in power
  self.resolution = float_to_float(float_conv(10) ** (-self.precision))
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:184: RuntimeWarning: divide by zero encountered in exp2
  epsneg_f80 = exp2(ld(-64))
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:185: RuntimeWarning: divide by zero encountered in exp2
  tiny_f80 = exp2(ld(-16382))
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:199: RuntimeWarning: divide by zero encountered in exp2
  eps=exp2(ld(-63)),
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:212: RuntimeWarning: divide by zero encountered in nextafter
  if hasattr(umath, 'nextafter')  # Missing on some platforms?
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:224: RuntimeWarning: divide by zero encountered in exp2
  eps=exp2(ld(-105)),
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:225: RuntimeWarning: divide by zero encountered in exp2
  epsneg= exp2(ld(-106)),
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\core\getlimits.py:227: RuntimeWarning: divide by zero encountered in exp2
  tiny=exp2(ld(-1022)))
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\__init__.py:316: RuntimeWarning: divide by zero encountered in subtract
  if not abs(x.dot(x) - 2.0) < 1e-5:
C:\Users\pi\anaconda3\envs\test\lib\site-packages\numpy\__init__.py:316: RuntimeWarning: divide by zero encountered in absolute
  if not abs(x.dot(x) - 2.0) < 1e-5:

ここに同じwarningが出るという報告がありますが解決策はわからず...。import時はともかく推論実行時に出るのでうまく推論できているのかもわからないです(同じような結果が得られるのでただしそうではありますが...)。解決策があれば教えてください。

おわりに

お疲れさまでした。opencvでCustomVisionのモデルの推論をしました。cv2.dnn.forward()の出力が何を表しているかもわかっていないので知っている方は教えていただければ幸いです。

間違い等ありましたらご指摘よろしくお願いします。

参考

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?