cv2.Canny(): Canny法によるエッジ検出の自動化

#背景
　デスク上に置いてあるカードを認識するアプリケーションを作ることを想定します。
　実装の過程で、様々な知見が得られたので、その内容を纏めます。　

プログラムコードはこちらに掲載します。
https://github.com/kotai2003/CannyEdgeDetection
　
![tree.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/22de2206-fb01-2e01-6b4e-17c49147bc56.jpeg)
![tree-canny-automatic.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/c2863d9d-acba-0603-b280-c0a8cf239a5c.jpeg)



#実装の手順
　このようなアプリケーションを作るときの一般的な実装の手順を整理します。
　
1. 画像の取り込み
2. カラー画像をグレースケール画像に変換
3. Gaussian Blurをかける。
4. Edgeを検出する。
5. Contoursを探す
6. Contoursの情報から、必要なContourだけを抽出する。
7. 後処理する。

　この手順で、最も重要なのは 「4.Edgeを検出する」ことだと思います。物体のEdgeが上手く検出されれば、次のContours（輪郭）の処理プロセスは比較的に簡単に実装できます。

＊ちなみに、４.Edgeを検出するプロセスが終わった後の理想的な画像の状態はこちらです。
（物体：白 (255,255,255), 背景：黒(0,0,0))
![Image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/4cacc562-d05d-54cb-1dfb-dfea65eeb072.png)


#cv2.Canny()とは
エッジ検出にはCanny法が良く使われます。より詳しい説明を知りたい方は下記のページを参考にしてください。

公式OpenCV文書
https://docs.opencv.org/master/da/d22/tutorial_py_canny.html
翻訳
http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_canny/py_canny.html

#cv2.Cannyの二つの調整パラメータ
Canny（）には二つの閾値があります。この閾値を利用して、正しいエッジとそうではないものを区別します。

```Python:
cv2.Canny(img_gray, threshold1=minVal, threshold2=maxVal)
```

画素値の微分値を計算し、その値がmaxVal以上であれば、正しいエッジと判断します。maxValはthreshold2に指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/1bb4b2bf-2df8-0ac5-61a0-9a0dee211093.png)

そして、画素値の微分値がminVal以下であれば、エッジではないと判断します。minValはthreshold1に指定します。従って, maxVal >= minValの関係から threshold2 >= threshold1の関係が成立する必要があります。（そうでなくてもCanny()は動作しますが、動作が不安定になるため、注意してください。）

この二つのパラメータを調整する方法については、下記のページを参考にしてください。
https://qiita.com/Takarasawa_/items/1556bf8e0513dca34a19


#Cannyの自動化

この二つの閾値を自動的に決める方法があります。
ある程度の背景と物体が分かれているものに関しては、うまく動作します。

img_blurからCanny方法を適用するコートです。


```Python:

import numpy as np

med_val = np.median(img_blur)
sigma = 0.33  # 0.33
min_val = int(max(0, (1.0 - sigma) * med_val))
max_val = int(max(255, (1.0 + sigma) * med_val))

img_edge1 = cv2.Canny(img_blur, threshold1 = min_val, threshold2 = max_val)

```

1.　img_blurから中央値を算出
2.  min_val : 0と(1.0 - sigma) * 中央値)の間の最大値
3.  max_val : 255と(1.0 + sigma) * 中央値)の間の最大値
* sigmaは0.33とする。

#実行結果
##1.目を閉じている男性
 ![kuchikomi.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/db8bde5f-d9c7-ee6d-97f6-a5c64889180e.jpeg)
![kuchikomi-canny-automatic.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/0798a8e1-c2cf-b3c3-e6ec-9d1b4cf43b9d.jpeg)

##2.バスケットボール
![basketball.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/94e3f491-8e8a-1fda-a408-60f2a5642ffa.jpeg)
![basketball-canny-automatic.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/a2233364-e2f7-dcec-0886-7764a30c5cf7.jpeg)


##3.チェス駒
![chess.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/e5dc5de2-9e6f-7ba3-52c6-0954e0d1088e.jpeg)
![chess-canny-automatic.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/83bc3d90-50c2-ed85-17e2-d7e1f0b526ec.jpeg)

##4. 白黒イメージ
![Image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/dea41ebe-e530-fcd2-9012-186cac54f978.png)
![image-canny-automatic.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/097993c7-16a9-331c-988b-29bb90da7620.jpeg)


#まとめ
1. 輪郭検出の前段階として、エッジ検出が使われる。
2. エッジ検出にはCanny法が一般的。
3. Canny法には二つのパラメーターがあり、その値を自動的に決める方法を紹介した。

#参考文献
1.   https://qiita.com/Takarasawa_/items/1556bf8e0513dca34a19
2.   https://docs.opencv.org/3.4/da/d22/tutorial_py_canny.html
3.   http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_canny/py_canny.html