二次元絵の顔を検出する

　概要です。

<blockquote class="twitter-tweet" lang="en"><p>ScalaでOpenCVを使って画像処理&#10;<a href="http://t.co/dn1jvLDstM">http://t.co/dn1jvLDstM</a>&#10;これを参考にClojureからOpenCVを、誰かがやってくれると思う</p>&mdash; 島風/天江衣分類器作成マン (@AntiBayesian) <a href="https://twitter.com/AntiBayesian/statuses/453403367117574144">April 8, 2014</a></blockquote>

上の記事の流れを全く無視して、二次元絵の顔の検出をします。

　試した環境です。

* Mac OSX 10.11.6
* OpenCV 3.2.0
* Clojure 1.8.0
* Java 1.8.0_121

## 準備

　インストールの様子です。

```sh
# Homebrew
$ ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
$ brew update

# Leiningen
$ brew install leiningen

# OpenCV
$ brew install homebrew/science/opencv3 --with-java

$ ls /usr/local/Cellar/opencv3/3.2.0/share/OpenCV/java/
libopencv_java320.dylib opencv-320.jar
```

　プロジェクト作成の様子です。

```sh
# プロジェクトをつくる
$ lein new karen
$ cd karen

# 先に生成したファイルをプロジェクトにコピーしてくる
$ mkdir lib
$ cp /usr/local/Cellar/opencv3/3.2.0/share/OpenCV/java/libopencv_java320.dylib lib/
$ cp /usr/local/Cellar/opencv3/3.2.0/share/OpenCV/java/opencv-320.jar lib/
```

`project.clj` を編集します。

```clj
(defproject karen "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]]

  ;; 以下を追記、適宜変更すること
  :jvm-opts ["-Djava.library.path=lib/"]
  :resource-paths ["./lib/opencv-320.jar"]
  :injections [(clojure.lang.RT/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME)]
  :main karen.core)
```

`:jvm-opts` と `:resource-paths` でパスの設定、`:injections` でプロジェクト実行の度に dylib を読むように設定、という感じです。

## グレースケール変換

　画像のグレースケール変換やります。適当な画像を用意してください。

```sh
$ lein repl
```

```clj
karen.core=> (org.opencv.core.Core/VERSION)
"3.2.0"
karen.core=> (import [org.opencv.imgcodecs Imgcodecs])
org.opencv.imgcodecs.Imgcodecs
karen.core=> (import [org.opencv.imgproc Imgproc])
org.opencv.imgproc.Imgproc
karen.core=> (def image (Imgcodecs/imread "karen.jpg"))
#'karen.core/image
karen.core=> (Imgproc/cvtColor image image Imgproc/COLOR_RGB2GRAY)
nil
karen.core=> (Imgcodecs/imwrite "karen_gray.jpg" image)
true
```

![D進どうですか](https://qiita-image-store.s3.amazonaws.com/0/4250/8044278b-036c-7325-1cc5-39b9fe5a134c.png)

楽しい！ ✌(’ω’✌ )三✌(’ω’)✌三( ✌’ω’)✌

`ClassNotFoundException` が出るときは jar のパス、`UnsatisfiedLinkError` が出るときは dylib のパスに不備がある、と思われます。

## 顔の検出

　二次元絵の顔の検出やります。OpenCV 用のアニメ顔分類器（lbpcascade_animeface.xml）をダウンロードして適当な場所に置いてください。

- [OpenCV によるアニメ顔検出なら lbpcascade_animeface.xml - デー](http://ultraist.hatenablog.com/entry/20110718/1310965532)

`src/karen/core.clj` を編集します。

```clj
(ns karen.core
  (:import [org.opencv.core Mat MatOfRect Point Scalar])
  (:import [org.opencv.imgcodecs Imgcodecs])
  (:import [org.opencv.imgproc Imgproc])
  (:import [org.opencv.objdetect CascadeClassifier]))

(defn -main [& args]
  (let [filename (first args)
        image (Imgcodecs/imread filename)
        gray (Mat.)
        faces (MatOfRect.)]

    ;; 画像をグレースケール変換したあと、ヒストグラムを均一化する
    (Imgproc/cvtColor image gray Imgproc/COLOR_RGB2GRAY)
    (Imgproc/equalizeHist gray gray)

    ;; アニメ顔分類器を使って顔を検出する
    (doto (CascadeClassifier.)
          (.load "lbpcascade_animeface.xml")
          (.detectMultiScale gray faces))

    ;; 検出した顔の位置に四角形を描画する
    (doseq [face (.toList faces)]
      (let [src (Point. (.x face) (.y face))
            dst (Point. (+ (.x face) (.width face)) (+ (.y face) (.height face)))]
        (Imgproc/rectangle image src dst (Scalar. 144 48 255) 2)))

    ;; 結果をファイルに出力する
    (let [[_ base extension] (re-find #"(.*)\.([A-Za-z]*)$" filename)]
      (Imgcodecs/imwrite (str base "_result." extension) image))))
```

```sh
$ lein run karen.jpg
```

![See You Next Time](https://qiita-image-store.s3.amazonaws.com/0/4250/8691af6a-be51-e50b-e6ee-3d709aadda6b.png)

楽しい！ ✌(’ω’✌ )三✌(’ω’)✌三( ✌’ω’)✌

## 終わりに

　参考情報です。

- [Scala で OpenCV を使って画像処理 - rest term](http://rest-term.com/archives/3018/)

- [Introduction to OpenCV Development with Clojure - OpenCV](http://docs.opencv.org/3.2.0/d7/d1e/tutorial_clojure_dev_intro.html)

- [OpenCV によるアニメ顔検出なら lbpcascade_animeface.xml - デー](http://ultraist.hatenablog.com/entry/20110718/1310965532)

- [顔を検出する - OpenCV-CookBook](http://opencv.jp/cookbook/opencv_img.html#id40)