OpenCV2で佐々木希の顔パーツのpixel面積を計算してみた


###参考にしたサイト

以下のウェブサイトに掲載されているコードを骨子として、スクリプトファイルを書き起こしてみました。

- [Pythonで図形の輪郭の大きさを調べる（OpenCV編）](https://water2litter.net/rum/post/python_cv2_contourarea/)

作成したスクリプト・ファイルの機能をまとめました。
コードの全文は、この記事の最後に掲載しています。

- 画像ファイルをコマンドライン引数で受け取る 
- 何も出力されないか、かろうじて視認できる点しか書き込まれないものが大量に吐かれるので、**面積が100ピクセル以上のものだけ**、検出した輪郭を青線で元の画像に書き込んで、１輪郭１ファイル出力する
- **左上に領域ID番号と面積（pixel単位）を書き込む**
- **面積が100未満の領域の輪郭を含めて、検出されたすべての領域の輪郭**を*detected_all_the_contours_result.png*にすべてまとめて出力する

###実行結果

```bash:Terminal
% python3 object_area_calc.py --file_name nozomi_1.jpg > nozomi_1_area_calc_result.txt
% wc -l nozomi_1_area_calc_result.txt                                                 
     345 nozomi_1_area_calc_result.txt
%
```


```bash:Terminal
% open detected_all_the_contours_resultnozomi_1.jpg.png 
```

![](https://user-images.githubusercontent.com/87643752/129375576-ddb346d6-b8da-4f72-a3ac-33af9ce16b39.png)

```bash:Terminal
% open resultnozomi_1.jpg133.png
```

![](https://user-images.githubusercontent.com/87643752/129375646-1ec37aa7-deb3-46f1-90d5-bbc47a82ae98.png)

```bash:Terminal
% open resultnozomi_1.jpg93.png
```

![](https://user-images.githubusercontent.com/87643752/129375692-32fb31d4-185b-48c9-b745-0d8faa9207ac.png)

```bash:Terminal
% head -50 nozomi_1_area_calc_result.txt
ID 0 Area 0.0
ID 1 Area 0.0
ID 2 Area 0.0
ID 3 Area 5.5
ID 4 Area 5.5
ID 5 Area 2.0
ID 6 Area 4.0
ID 7 Area 5.5
ID 8 Area 7.5
ID 9 Area 7.5
ID 10 Area 5.5
ID 11 Area 4.0
ID 12 Area 16.5
ID 13 Area 2.0
ID 14 Area 13.5
ID 15 Area 6.0
ID 16 Area 2.0
ID 17 Area 4.0
ID 18 Area 10.0
ID 19 Area 2.0
ID 20 Area 2.0
ID 21 Area 0.0
ID 22 Area 8.5
ID 23 Area 8.5
ID 24 Area 0.0
ID 25 Area 0.0
ID 26 Area 7.0
ID 27 Area 0.0
ID 28 Area 0.0
ID 29 Area 2.0
ID 30 Area 2.0
ID 31 Area 11.0
ID 32 Area 2.0
ID 33 Area 0.0
ID 34 Area 69.5
ID 35 Area 2.0
ID 36 Area 6.0
ID 37 Area 4.0
ID 38 Area 7.0
ID 39 Area 2.0
ID 40 Area 4.0
ID 41 Area 2.0
ID 42 Area 2.0
ID 43 Area 2.5
ID 44 Area 4.0
ID 45 Area 2.0
ID 46 Area 4.0
ID 47 Area 4.0
ID 48 Area 7.5
ID 49 Area 2.0
%
```

#### ID 344が大きな面積を占めている

```bash:Terminal
% tail nozomi_1_area_calc_result.txt
ID 335 Area 2.0
ID 336 Area 2.0
ID 337 Area 2.0
ID 338 Area 4.0
ID 339 Area 2.0
ID 340 Area 6.0
ID 341 Area 4.0
ID 342 Area 2.0
ID 343 Area 0.0
ID 344 Area 76917.5
%
```

```bash:Terminal
% open resultnozomi_1.jpg344.png   
```

![](https://user-images.githubusercontent.com/87643752/129376036-a03e84c3-beeb-486e-807d-47f9e6a59954.png)

###スクリプトファイルに起こしたコード

```Python3:object_area_calc.py
import cv2

from typing import Tuple, Optional
import os
import cv2
import numpy as np
import cv2
import argparse

# 動画ファイル名をコマンドライン引数から受け取る
parser = argparse.ArgumentParser(description='')    #
parser.add_argument('--file_name')
args = parser.parse_args()

img_file = args.file_name

im = cv2.imread(img_file)
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
retval, im_bw = cv2.threshold(im_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 輪郭の検出
contours, hierarchy = cv2.findContours(im_bw, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

# 輪郭を１つずつ書き込んで出力
# 何も出力されないか、かろうじて視認できる点しか書き込まれないものは、画像に出力しない
# 面積が100ピクセル以上のものみ、青色で輪郭を１件ずつ個別のファイルに出力。
# 検出されたすべての面積は、その輪郭のいかんによらず、detected_all_the_contours_resultにすべてまとめて出力する。
for i in range(len(contours)):
	print('ID', i, 'Area', cv2.contourArea(contours[i]))
	if cv2.contourArea(contours[i]) >= 100:
		im_con = im.copy()
		im_con = cv2.drawContours(im_con, contours, i, (255, 191, 0), 10) # dep skyblue RGB(0, 191, 255)
		message =  "ID, {0} :  Area {1}".format(i, cv2.contourArea(contours[i]))
		cv2.putText(im_con, str(message),  (0, 50), cv2.FONT_HERSHEY_TRIPLEX, 1, (0, 0, 255), 1, cv2.LINE_AA)
		cv2.imwrite('result' + img_file + str(i) + '.png', im_con)
	else:
		pass 

# 検出されたすべての輪郭を画像に書き込んでファイル出力
all_counours_engraved_img = cv2.drawContours(im_con, contours, -1, (0, 250, 154), 3)
cv2.imwrite('detected_all_the_contours_result' + img_file + '.png', all_counours_engraved_img)

```

##以下の記事につづく・・・

https://qiita.com/electronics_diy721/items/e1eeacf51027b642bcb7


##（ 追記 ）

ラムダ式を使って面積を降順ソートしたり、一番大きな面積のパーツを探したりすると便利。

####面積が大きい順に並べる（降順ソート）

__（ 参考 ）__

* [2番目に大きい図形を抽出する方法](https://teratail.com/questions/245283)

>```Pythom3:
> import cv2
> import numpy as np
> 
> img = cv2.imread("test.png", cv2.IMREAD_GRAYSCALE)
> 
> #輪郭の抽出
> contours, hierarchy = cv2.findContours(img,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
> 
> #面積の降順にソート
> contours.sort(key=lambda x: cv2.contourArea(x), reverse=True)
> 
> out = np.zeros_like(img)
> cv2.drawContours(out, [contours[0]], -1, color=255, thickness=-1)
> cv2.drawContours(out, [contours[1]], -1, color=128, thickness=-1)
> cv2.drawContours(out, [contours[2]], -1, color=64, thickness=-1)
>```


####面積が一番大きい領域を調べる

__（ 参考 ）__

* [OpenCV – 輪郭の特徴分析について](https://pystyle.info/opencv-structural-analysis-and-shape-descriptors/)

>```Python3:
>max_contour = max(contours, key=lambda x: cv2.contourArea(x))
>```