MTCNNで顔検出してみた

顔検出の機械学習ではモデル作成も含め、OpenCVしか使ってなかったのでほかも使ってみることにした。
ということでMTCNN使ってみました。

MTCNNは裏側でtensorflow使ってるようですね。
ディープランニングに片足突っ込んでる感じでいい気分です。

# 準備

```bash
pip3 install cv2
pip3 install matplotlib
pip3 install mtcnn
pip3 install tensorflow
```

# テストで使った画像

検証に丁度いいんですよね。顔いろんなむき出し。顔以外のもの色々写ってるし

![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9094/fcb6124a-9dd3-b73d-0100-d499f0462ba9.png)

# MTCNNで顔検出

## 検証コード

```py
# face detection with mtcnn on a photograph
from matplotlib import pyplot
from matplotlib.patches import Rectangle
from matplotlib.patches import Circle
from mtcnn.mtcnn import MTCNN
import cv2

# draw an image with detected objects
def draw_image_with_boxes(filename, result_list):
	# load the image
	data = pyplot.imread(filename)
	# plot the image
	pyplot.imshow(data)
	# get the context for drawing boxes
	ax = pyplot.gca()
	# plot each box
	for result in result_list:
		# get coordinates
		x, y, width, height = result['box']
		# create the shape
		rect = Rectangle((x, y), width, height, fill=False, color='red')
		# draw the box
		ax.add_patch(rect)
		# draw the dots
		for key, value in result['keypoints'].items():
			# create and draw dot
			dot = Circle(value, radius=2, color='red')
			ax.add_patch(dot)
	# show the plot
	pyplot.show()
 
filename = 'test.png'
# load image from file
pixels = cv2.cvtColor(cv2.imread(filename), cv2.COLOR_BGR2RGB)
# create the detector, using default weights
detector = MTCNN()
# detect faces in the image
faces = detector.detect_faces(pixels)
# display faces on the original image
draw_image_with_boxes(filename, faces)
```

## 結果

すべて正しく検出されていますね。
この画像に関しては誤検出もしていないようです。

![result_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9094/49dd9f55-594c-3b91-01d5-943772c73705.png)

ちなみにOpenCV(haarcascade_frontalface_default)使ったものがこちらになります。
顔は全部検知できてますけど、めっちゃ誤検出しています。
アイスとかほんと顔だわw

![result_cv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9094/5f640b4f-b429-9501-9a46-2d19830c8a27.png)

前にデフォルトのモデルに納得できなくて自分で作ったものが以下です。
誤検出はしなくなったけど、1人検出できてませんね。

参考) とあるgopherが OpenCVをさわってみた話
https://speakerdeck.com/usk81/introduction-about-opencv-for-gophers

![mine.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9094/2552a96b-283b-2b97-fbd3-1be790780b3a.png)

MTCNN... 完敗や... 40時間ぐらいかけたのに
＿|￣|○ il||li

# 切り出しもしてみた

一番大きく切り出せてるやつを1つだけ保存するようにしてみました。

## コード

```py
# face detection with mtcnn on a photograph
from matplotlib import pyplot
from mtcnn.mtcnn import MTCNN
import cv2

# draw each face separately
def save_biggest_face_image(filename, result_list):
	# load the image
	# data = pyplot.imread(filename)
	data = cv2.imread(filename)
	# plot each face as a subplot
	maxlen = -1
	for i in range(len(result_list)):
		# get coordinates
		x1, y1, width, height = result_list[i]['box']
		if width > height:
			length = width 
		else:
			length = height
		x2, y2 = x1 + length, y1 + length
		# # define subplot
		# pyplot.subplot(1, len(result_list), i+1)
		# pyplot.axis('off')
		# # plot face
		# pyplot.imshow(data[y1:y2, x1:x2])
		d = data[y1:y2, x1:x2]
		if length > 100 and length > maxlen:
			maxlen = length
			md = d
		# cv2.imwrite('/Users/komatsu/Desktop/'+str(i)+'.png', d)

	# show the plot
	# pyplot.show()
	if maxlen > 0:
		cv2.imwrite('result.png', md)
 
filename = 'test.png'
# load image from file
pixels = cv2.cvtColor(cv2.imread(filename), cv2.COLOR_BGR2RGB)
# create the detector, using default weights
detector = MTCNN()
# detect faces in the image
faces = detector.detect_faces(pixels)
# save face image
save_biggest_face_image(filename, faces)
```

## 結果

![result_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9094/c69f6ebc-6956-7bde-2a51-cbeb9ca75412.png)


## 備考

画像ファイルの読み込みが、 `pyplot.imread` で読み込めなかったのが謎です。
関数内だと使えるんだけどなぁ...