Raspberry Piのような超小型のコンピューターを使って特定の条件に一致する画像を抽出しようとする場合に、特定の条件をプログラムが判別できるようにまとめたものを「カスケード分類器」といいます。 今回はこのOpenCVのカスケード分類器を自分で作成し、任意の条件に合う画像を抽出するまでの流れをご紹介します。
カスケード分類器とは
画像認識ライブラリーであるOpenCVに含まれる物体検出機能を使用すると、画像の中に含まれる特定の物体を検出することが可能になります。
物体検出を行うためには検出したい物体がどんな特徴を持っているのか、該当する物体を含む画像と含まない画像(=学習用画像)を用意し、検出したい物体の特徴を抽出します。この特徴を「特徴量」と呼びますが、学習用画像すべての「特徴量」をまとめたデータのことを「カスケード分類器」と呼びます。
OpenCVには最初からカスケード分類器が用意されていますが、自分でカスケード分類器を作成することで任意の物体を検出させることができるようになります。
「OpenCV」やOpenCV付属の「カスケード分類器」については、下記の記事もご覧ください。
“Raspberry PiとOpenCVによる画像認識で人の顔を判別する”
https://www.pc-koubou.jp/magazine/19205
OpenCVの準備
Windowsで,OpenCVを使うようにするために公式サイトのファイル配布ページにアクセスします。
“Releases”.2019.OpenCV team
https://opencv.org/releases/
少し下の方にスクロールすると、「OpenCV-3.4.6」と項目が出てくるので赤い枠で囲まれたwindows版をダウンロードします。
ダウンロードが完了したら、次にインストール作業に移ります。
ダウンロードしたファイルを実行して手順を進めます
インストールが完了したら、作業ディレクトリーを作成します。今回はデスクトップに「cv」ディレクトリーを作成しました。
先ほど、ダウンロードして展開したファイルを開いて必要なファイルを作業ディレクトリー「cv」にコピーします。
コピーするディレクトリーは「opencv¥build¥x64¥vc15¥bin」の中に入っています。
- opencv_createsamples.exe
- opencv_traincascade.exe
- opencv_world346.dll
この3つのファイルを「cv」ディレクトリーにコピーします。
カスケード分類器の作成
カスケード分類器作成の手順
カスケード分類器の作成には、正解画像(ポジティブ画像)と不正解画像(ネガティブ画像)の二つの種類の画像必要で、この正解画像と不正解画像をひたすら学習させることでカスケードファイルを作成します。この作成したファイルのことをカスケード分類器と呼ばれています。
正解画像は、「検出させたい物体が写っている画像」のことを示して不正解画像は、「検出させたい物体が写っていない」画像のことを示します。
作業を始める前に「cv」ディレクトリーの環境を構築します。
正解画像を入れる「ok」ディレクトリーと不正解画像を入れる「ng」ディレクトリーをそれぞれ作成してください。
先ほど、カスケード分類器の作成には、正解画像(ポジティブ画像)と不正解画像(ネガティブ画像)の二つの種類の画像が必要だと書きましたが、OpenCV公式ドキュメントによると、実用的な精度を得るために必要なサンプル数は、正解画像「7000枚」、不正解画像「3000枚」必要と言われていて、用意するのは大変です。
OpenCVには1枚の画像から画像のバリエーションを複数用意できる「createsamples」というプログラムがあり、これを使うことで少ない枚数の画像で学習を行うことができます。
今回は正解画像1枚からcreatesamplesにより1000枚の正解画像を生成し、不正解画像40枚とともに学習用サンプル画像として使用します。
不正解画像は検出したい物が写っていなければ何でも構いませんが、正解画像に似ている画像を用いたほうがより少ない枚数で高い精度を得られます
正解画像ファイルの作成
1枚の正解画像から複数のバリエーション画像を用意するには下記のコマンドを実行します。
コマンドを実行する前に準備した1枚の正解画像を作成した「ok」ディレクトリーに入れます。
今回準備した画像の名前は「test.png」にしました。
コマンドプロントを開き、「cv」ディレクトリーまで移動して、下記のコマンドを実行します。
opencv_createsamples.exe -img ./ok/test.png -num 1000 -vec test.vec
このコマンドで「ok」ディレクトリーに入っている「test.png」をもとに変形など様々な加工を繰り返し行い、1000枚の画像を生成します。
実行に成功すると、「cv」ディレクトリーの中に「test.vec」というファイルが作成されたことを確認します。
実は、画像を1000枚別に作成したのではなく「test.vec」に1000枚の画像がまとめられて一つのファイルを生成されたということです。
不正解画像ファイルの作成
不正解画像については、「検出させたい物体が写っていない」画像であればどの画像でもいいので、用意した不正解画像を「ng」ディレクトリーに入れます。
不正解画像ファイルは正解画像ファイルのように画像を量産する必要はないですが、違う点としてリストファイルを作成する必要があります。
下記のようにng.listというファイルを作成して、用意した画像の名前を下記の形式で1行に1ファイルずつ記載します。
.\ng\xxx.jpg
.\ng\yyy.jpg
.\ng\zzz.jpg
これで正解画像と不正解画像の必要なファイルを作成することができました。
カスケードファイルの作成
これまでの手順で用意したファイルを用いて検出したいものの特徴を抽出し(これを「学習」といいます)、カスケード分類器を作成します。
まず、作成するカスケードファイルの保存先となるディレクトリー「cascade」を「cv」ディレクトリーに作成します。
カスケードファイルを作成するために下記のコマンドを実行します。
opencv_traincascade.exe -data ./cascade/ -vec ./test.vec -bg ./ng/nglist.txt -numPos 800 -numNeg 40
このコマンドは各パラメータを指定して実行します。
data部分が作成したカスケードファイルの保存先を指定して,vecの部分で正解画像をまとめた「test.vec」ファイルの指定、bgは不正解画像をまとめたリスト「nglist.txt」の指定、numPosは学習で使う正解画像の枚数を指定して、numNegで学習で使う不正解画像の枚数を指定します。
また、numPosの値を「800」と指定していますが、今回「createsamples」を使って正解画像を1000枚作成したはずなのに、なぜ「1000」と指定しないのかと疑問を持った方もいると思います。
これは、用意した枚数をそのまま指定すると、エラーが出る場合があるためで、用意した画像の8割〜9割の数値を指定することによりエラーを回避して学習を進めることができます。
これで学習を開始することができました。
今回は画像の枚数がそれほど多くないので、実行環境にもよりますが数十分でカスケードファイルを作成することができますが、精度を高くするために画像の枚数を増やすと、数時間、数日かかる場合もあります。
学習に成功すると、「cv」ディレクトリーにある「cascade」ディレクトリーの中に複数ファイルが作成されますが、最終的に検出に使うファイルは「cascade.xml」というファイルのみです。
今回はRaspberry Piで検出を行うため、USBメモリーや他の記録媒体に「cascade.xml」をコピーしてRaspberry Piに移動します。
ここからは、Raspberry Piの作業になるのでRaspberry Piを準備します。
Raspberry Piで画像認識をさせる
Pythonプログラムの作成
先ほど作成した「cascade.xml」を読み込みPythonプログラムを実行し、実際に画像認識を行います。
Vimエディタを開き、「cascade.py」を作成します。
下記のPythonプログラムを書くか、コピーアンドペーストをしてください。
import cv2 as cv img = cv.imread('sample.png') grayimg = cv.cvtColor(img, cv.COLOR_BGR2GRAY) custom_cascade = cv.CascadeClassifier('cascade.xml') custom_rect = custom_cascade.detectMultiScale(grayimg, scaleFactor=1.07, minNeighbors=2, minSize=(1, 1)) print(custom_rect) if len(custom_rect) > 0: for rect in custom_rect: cv.rectangle(img, tuple(rect[0:2]), tuple(rect[0:2]+rect[2:4]), (0, 0, 255), thickness=3) cv.imshow('image', img) cv.waitKey(0) cv.destroyAllWindows()
このプログラムでは同じディレクトリーにある「sample.png」を画像認識させたい画像として、作成したカスケードファイルを読み込んで認識できた部分を赤い枠で囲むというプログラムになっています。
cascade.pyを保存してvimエディタを保存します。
カスケード分類器を用いて画像認識をさせる
先ほどのプログラムを実行するためにディレクトリー内を確認します。
- cascade.xml 学習で作成したカスケードファイル
- cascade.py Pythonプログラム
- sample.png 画像認識させたい画像
この3つのファイルが同一ディレクトリーに存在することを確認して画像認識を実行します。
下記のコマンドを実行してください。
sudo python cascade.py
もともと用意した画像で実行してみると画像認識に成功して「sample.png」に赤い枠がつきました。
違う画像を用意しても同じように画像認識をして見事赤い枠がつきましたが、別の部分も認識して赤い枠が複数になってしまいました。
学習で用意する画像の枚数を多くすればもっと高い精度を実現するのは可能になると思います。
自作のカスケード分類器で好きな物体を検出することができる
カスケード分類器を自分で作成して画像認識を行いましたが、実際に用意した画像の枚数がOpenCV公式ドキュメントに書いてある推奨枚数より少なかったものの、画像認識をさせることに成功しました。
今回認識させた「N」マークがシンプルな形状・色で認識しやすかったため、学習画像の枚数が少なくても認識させることができたと思われます。
実際に今回「猫」の画像でも検出を試みましたが、上記「N」マークよりも多い枚数の画像を容易しても、認識がうまくいきませんでした。
一方、動物のアニメキャラクターの顔では「N」マークよりやや多い枚数で認識が可能となったことから、認識させる対象物によって、必要となる学習画像の数や質が異なるようです。
また、今回カスケード分類器を作成するにあたり最初はRaspberry Piで作業を始めましたが、学習にかなり時間を要したため、途中でWindowsパソコンに切り替えて作業を行いました。今後、学習に適したパソコンのスペックについても検討してみたいと思います。
石郷祐介
大学卒業後、公設研究機関勤務を経て、「情報科学芸術大学院大学[IAMAS]」に入学。
専門学校講師を経て、企業の研究開発をコンセプトから開発まで支援する「合同会社4D Pocket」代表、エンジニアを養成するフリースクール「一般社団法人HOPTER TECH SCHOOL」代表理事、「名古屋文理大学」及び「名古屋造形大学」非常勤講師。