# 理論
この部分の内容は、この論文からまとめて翻訳されています。
## 色空間
色空間は、色情報を3つまたは4つの異なる色成分として表す数学モデルです。皮膚の検出には、さまざまな色空間を利用できます。 それらは、RGBベースの色空間(RGB、正規化されたRGB)、色相ベースの色空間(HSI、HSV、およびHSL)、輝度ベースの色空間(YCBCr、YIQ、およびYUV)です。
RGB(Red-Green-Blue:赤ー緑ー青)
RGB色空間は広く使用されており、通常、デジタル画像を保存および表現するためのデフォルトの色空間です。 原色である赤、緑、青の3つのコンポーネントで構成されています。 3つの基本色を混合することにより、任意の色を得ることができます。
これは、赤、緑、青の値の線形結合によって色が取得される付加的な色空間です。
3つのチャネルは、表面に当たる光の量によって相関しています。
HSV(Hue Saturation Value:色相ー彩度ー明度)
色相(H)が0から1.0まで変化すると、対応する色は赤から黄色、緑、シアン、青、マゼンタを経て赤に戻ります。 彩度(S)が0から1.0まで変化すると、対応する色(色相)は不飽和(灰色の陰影)から完全に飽和(白成分なし)まで変化します。 値(V)または明るさが0から1.0まで変化すると、対応する色がますます明るくなります。
YCbCr(Luminance, Chrominance)
YCbCrは、エンコードされた非線形RGB信号です。 色は、RGB値の加重和として構築された輝度(非線形RGBから計算された輝度)で表されます。
このフォーマットでは、輝度情報は単一の成分(Y)として保存され、クロミナンス情報は2つの色差成分(CbとCr)として保存されます。この表現により、冗長な色情報を簡単に取り除くことができるため、JPEG、MPEG1、MPEG2、MPEG4などの画像およびビデオ圧縮規格で使用されます。
人間の肌色
著者が提案した皮膚検出アルゴリズム
以上のアルゴリズムについていくつかまだわからなくて、実装も難しそうなので、このもっと簡単な方法を使ってみます
https://github.com/CHEREF-Mehdi/SkinDetection
HSV: 0<=H<=17 and 15<=S<=170 and 0<=V<=255
and
YCrCb: 0<=Y<=255 and 135<=Cr<=180 and 85<=Cb<=135
# 実装
目的
環境
Windows 10
OpenCV 3.4.2
Python 3.7.9
コード
HSVフィルター
img=cv2.imread("a.jpg")
img_YCrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
HSV_mask = cv2.inRange(img_HSV, (0, 15, 0), (17,170,255))
HSV_mask = cv2.morphologyEx(HSV_mask, cv2.MORPH_OPEN, np.ones((3,3), np.uint8))
cv2.imshow("HSV.jpg", HSV_mask)
YCrCbフィルター
img=cv2.imread("a.jpg")
img_YCrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
YCrCb_mask = cv2.inRange(img_YCrCb, (0, 135, 85), (255,180,135))
YCrCb_mask = cv2.morphologyEx(YCrCb_mask, cv2.MORPH_OPEN, np.ones((3,3), np.uint8))
cv2.imshow("YCbCr.jpg",YCrCb_mask)
見えるようにYCrCbフィルターの方はよく肌の色をにんしきできます。
OpenCVの輪郭(リンク)
def apply_contours(contour_img):
ret, thresh = cv2.threshold(contour_img, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:]
# 一番大きい輪郭を選ぶ
cnt = max(contours, key = cv2.contourArea)
# 輪郭の中最上の点を選ぶ
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
contour_img = cv2.drawContours(img, [cnt], 0, (0,255,0), 3)
contour_img = cv2.circle(contour_img , topmost, radius=5, color=(0, 0, 255), thickness=-1)
return contour_img
最後のコード
import cv2
import numpy as np
img=cv2.imread("WIN_20201203_01_38_27_Pro.jpg")
img_YCrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
YCrCb_mask = cv2.inRange(img_YCrCb, (0, 135, 85), (255,180,135))
YCrCb_mask = cv2.morphologyEx(YCrCb_mask, cv2.MORPH_OPEN, np.ones((3,3), np.uint8))
def apply_contours(contour_img):
ret, thresh = cv2.threshold(contour_img, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:]
# 一番大きい輪郭を選ぶ
cnt = max(contours, key = cv2.contourArea)
# 輪郭の中最上の点を選ぶ
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
contour_img = cv2.drawContours(img, [cnt], 0, (0,255,0), 3)
contour_img = cv2.circle(contour_img , topmost, radius=8, color=(0, 0, 255), thickness=-1)
return contour_img
YCrCb_result = apply_contours(YCrCb_mask)
#show results
# cv2.imshow("Show image",YCrCb_result)
cv2.imwrite("YCbCr_result.jpg",YCrCb_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Happy coding!