Ubuntu + OpenCvでカスケード分類器を作成してみる part 1


今回利用した環境は、AzureのVMでOSはUbuntu 18.04にしました。
Ubuntu系であればAWSでもDockerでも、Jetson系でも大体手順は一緒だと思います。

まず、 [OpenCVの本当に動くインストール手順](https://qiita.com/usk81/items/98e54e2463e9d8a11415) のUbuntuのところを参考にOpenCVをソースからインストールします。


```
$ sudo su -

$ apt-get update
$ apt-get upgrade

# libjasper-devを入れるためにリポジトリを追加
$ add-apt-repository "deb http://security.ubuntu.com/ubuntu bionic-security main"

# 依存パッケージをインストールする
$ apt-get -y install build-essential checkinstall cmake unzip pkg-config yasm
$ apt-get -y install git gfortran python3-dev
$ apt-get -y install libjpeg8-dev libjasper-dev libpng12-dev libavcodec-dev libavformat-dev libswscale-dev libdc1394-22-dev libxine2-dev libv4l-dev
$ apt-get -y install libjpeg-dev libpng-dev libtiff-dev libtbb-dev
$ apt-get -y install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libatlas-base-dev libxvidcore-dev libx264-dev libgtk-3-dev

$ cd /usr/local/src
$ git clone https://github.com/opencv/opencv.git
$ git clone https://github.com/opencv/opencv_contrib.git
$ cd opencv_contrib
$ git checkout -b 3.4.3 refs/tags/3.4.3
$ cd ../opencv/
$ git checkout -b 3.4.3 refs/tags/3.4.3

# ビルドしてインストールする
$ mkdir build
$ cd build
$ cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
$ cmake -D CMAKE_BUILD_TYPE=Release \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D WITH_TBB=ON \
-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules ..
$ make -j7
$ make install
$ echo /usr/local/lib > /etc/ld.so.conf.d/opencv.conf
$ ldconfig -v

# きちんとインストールされていることを確認する
$ opencv_version
3.2.0
```

これで `opencv_traincascade` コマンドが使えるようになります。

```
# opencv_traincascade
Usage: opencv_traincascade
  -data <cascade_dir_name>
  -vec <vec_file_name>
  -bg <background_file_name>.......
```

今回は学習のpositive用にりんご画像を1枚と、negative用にgoogle_images_downloadを利用して取得した100枚の猫のjpg画像を利用しました。

google-images-downloadを利用して猫画像を100枚ダウンロードします。

```
$ sudo apt install python3.7
$ git clone https://github.com/Joeclinton1/google-images-download.git
$ python3 ./google-images-download/build/lib/google_images_download/google_images_download.py --keywords 'cat' -f jpg -s medium
$ mkdir ~/neg
$ mv downloads/cat/* ~/neg/
```

Positive画像は適当なリンゴの画像をopencv_createsamplesを利用して水増しします。
リンゴ画像はフリーサイトやgoogle_images_downloadからなどで取ってきてください。

```
$ mkdir ~/pos
$ mv apple.jpg ~/pos/
$ opencv_createsamples -img ./pos/apple.jpg -vec ./vec/patch.vec -num 100 -bgcolor 255
```

ネガティブ画像のリストテキストと、cascadeファイルが作成されるディレクトリを作成してやっと `opencv_traincascade` です。

```
$ ls neg | xargs -I {} echo neg/{} > nglist.txt
$ mkdir ./cascade/
$ opencv_traincascade -data ./cascade/ -vec ./vec/patch.vec -bg nglist.txt -numPos 100 -numNeg 100
---------------------------------------------------------------------------------
Training parameters are pre-loaded from the parameter file in data folder!
Please empty this folder if you want to use a NEW set of training parameters.
---------------------------------------------------------------------------------
PARAMETERS:
cascadeDirName: ./cascade/trained_data/
vecFileName: ./vec/patch.vec
bgFileName: nglist.txt
numPos: 100
numNeg: 100
numStages: 20
precalcValBufSize[Mb] : 1024
precalcIdxBufSize[Mb] : 1024
acceptanceRatioBreakValue : -1
.
.
.
.

===== TRAINING 5-stage =====
<BEGIN
POS count : consumed   100 : 100
NEG current samples: 43
NEG count : acceptanceRatio    100 : 1.95563e-06
Precalculation time: 1
+----+---------+---------+
|  N |    HR   |    FA   |
+----+---------+---------+
|   1|        1|        1|
+----+---------+---------+
|   2|        1|     0.39|
+----+---------+---------+
END>
Training until now has taken 0 days 0 hours 4 minutes 40 seconds.

===== TRAINING 6-stage =====
<BEGIN
POS count : consumed   100 : 100
NEG count : acceptanceRatio    1 : 4.76837e-07
Required leaf false alarm rate achieved. Branch training terminated.
```

~/cascade/ に cascade.xmlができています。
その後、下記の様なスクリプトを組んで検出を試してみたのですがうまく見つけられませんでした。

学習データをもう少し考えたほうが良さそうですが、一旦動くだけ動いたということでまた次回チャレンジしようと思います。

```python
import cv2

cascade_path = 'cascade/cascade.xml'
cascade = cv2.CascadeClassifier(cascade_path)

src = cv2.imread('pos/apple.jpg')
src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

apple = cascade.detectMultiScale(src_gray)
print(apple)

for x, y, w, h in apple:
    cv2.rectangle(src, (x, y), (x + w, y + h), (255, 0, 0), 2)
    face = src[y: y + h, x: x + w]
    face_gray = src_gray[y: y + h, x: x + w]
    eyes = eye_cascade.detectMultiScale(face_gray)
    for (ex, ey, ew, eh) in eyes:
        cv2.rectangle(face, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)

cv2.imwrite('detect_rectangle.jpg', src)
```