コンボリューション（畳み込み処理）を実装してみる


[こちらの記事（8.2. コンボリューション行列...）](http://docs.gimp.org/2.8/ja/plug-in-convmatrix.html)を参考に、コンボリューション処理を、HTML5のCanvasで実装してみました。

少し前からOpenCVについて勉強してますが、ちょくちょくこうしたフィルター処理についての言及があるので、せっかくなので作ってみようかなーというのが発端です。

ちなみに今回作成したものは[jsdo.it](http://jsdo.it/edo_m18/ta0R)に上げてあります。
[![コンボリューションサンプル](https://qiita-image-store.s3.amazonaws.com/0/5616/741332c1-5cd7-acf9-0104-fd11ffca34ae.jpeg "ta0R.jpg")]((http://jsdo.it/edo_m18/ta0R))

参考にした記事に書いてあったフィルターを指定できるようにしています。
また画像についてはDrag & Dropで自分の画像を指定できるようにもしてみました。

## コンボリューションとは

「コンボリューションとは」で検索すると色々と記事が出てきますが、ここでは「フィルターとなるコンボリューション行列を各画素に対して処理していく」ものです。

コンボリューション（畳み込み演算）は画像処理に使われ、画像を滑らかにしたり、シャープにしたりといったことができるようになります。また、エッジ検出といったものもあり、様々な画像処理のベースとなっています。

### 画像処理の基本はカーネル

*これは完全に自分の理解とそのメモです。間違いがあるかもしれません。*

画像処理の基本は「 **カーネル** 」です。
（畳み込み処理に関しては、こちらの記事「[たたみ込み演算による画像処理](http://www.clg.niigata-u.ac.jp/~medimg/practice_medical_imaging/imgproc_scion/4filter/index.htm)」がとても分かりやすかったです）

畳み込み処理、という言葉から察せるように、なにかしらを畳み込みます。
それはもちろん画像内のピクセルです。
現在演算中のピクセルにカーネルを置き、その周辺のピクセルをどれくらいの重みで「畳み込む」か、というのがおおまかな演算の流れになります。


#### カーネルの例

| **0** | **-1** | **0** |
|-------|:-------:|-------|
| **-1** | **5** | **-1** |
| **0** | **-1** | **0** |

これはシャープネス処理するカーネルの例です。

[こちらの記事](http://docs.gimp.org/2.8/ja/plug-in-convmatrix.html)から画像を引用させてもらうと、こんな感じになります↓
![シャープネス](http://docs.gimp.org/2.8/ja/images/filters/examples/generic-taj-convmatrix-sharpen.jpg)

これを紹介してくれている記事ではさらにいくつかの例が記載されているので見てみると分かりやすいでしょう。

##### 計算例

カーネルをどう計算に使うのか。
それは、現在計算しているピクセルに、カーネルの中心となる部分（下の画像では★のところ）をあわせ、その周辺のピクセル値に対して配置された数値と掛け合わせ、それを足し込みます。
その結果が、計算対象のピクセルの新しい値として採用されます。

| **0** | **-1** | **0** |
|-------|:-------:|-------|
| **-1** | **★5** | **-1** |
| **0** | **-1** | **0** |

このカーネルを、以下の画素配列を持つ画像に適用すると、

| **92** | **35** | **42** |
|-------|:-------:|-------|
| **12** | **87** | **27** |
| **33** | **40** | **61** |

↓

( 0 * 92) + (-1 * 35) + ( 0 * 42) +
(-1 * 12) + ( 5 * 87) + (-1 * 27) +
( 0 * 33) + (-1 * 40) + ( 0 * 61) = 321

|   |     |   |
|---|:-----:|---|
|   | **321** |   |
|   |        |   |


## 微分フィルタ

OpenCVや画像処理について見ていくと、 **微分フィルタ** というのをよく目にします。
その中でも **Sobel微分** はよく出てくるイメージです。

微分フィルタについては[前述したこちらの記事（たたみ込み演算による画像処理）](http://www.clg.niigata-u.ac.jp/~medimg/practice_medical_imaging/imgproc_scion/4filter/index.htm)が分かりやすいです。

微分フィルタについて解説している文章を引用させてもらうと、

>　微分は，数学的には関数の変化分をとりだす演算である．この微分演算を画像に適用すれば，濃度値が急激に変化している部分を抽出することができる．微分には，１次微分（グラディエント）と２次微分（ラプラシアン）がある．ディジタル画像ではデータが一定間隔にとびとびに並んでいるため，本当の意味での微分演算はできない．このため，隣接画素同士の差をとる演算で微分を近似し，これを”差分”という．つまり，ディジタル画像において”微分”と表現される操作は，実際は差分演算を行うことになる．

>　画像に対する１次微分処理は，注目画素の周辺の勾配（傾き：グラディエント）と求める操作である．この勾配は，大きさと方向をもつベクトル量であり，画像上ではさまざまは方向に勾配が存在していることがわかる．そのため，１次微分では微分の方向によって結果が異なる．

*ちなみに、以前に[物理エンジンを見よう見真似で実装](http://qiita.com/edo_m18/items/f7698c5bd262df4f9cf3)したときに[微分や積分についてのメモ](http://qiita.com/edo_m18/items/ae0c8ea57a0bd98f1cee)があるので、よかったら見てみてください*

上記記事内で、Sobelフィルタを実行している例がありますが、それを見ると「差分」と言っているのが分かります。
つまり、計算対象周辺のピクセルに対して、勾配を正負の数値で表し、それを演算することで勾配を求めている、ということでしょう。


## 参考記事

* [8.2. コンボリューション行列...](http://docs.gimp.org/2.8/ja/plug-in-convmatrix.html)
* [たたみ込み演算による画像処理](http://www.clg.niigata-u.ac.jp/~medimg/practice_medical_imaging/imgproc_scion/4filter/index.htm)
* [コンボリューションを用いた画像の平滑化、鮮鋭化とエッジ検出](http://codezine.jp/article/detail/129)