OpenCVでの顔へのモザイク処理
最近、久々に触ったOpenCVにハマっていますww。

顔認識ができたので顔にモザイクでもつけてみようかな?と思い実施。
合わせて目にのみもモザイクを付けてみたのでそちらも報告!!
使用しているプログラミング言語はpythonです。
■モザイク処理方法
特定領域のモザイク処理はこちらで実行できます。
import cv2
ratio = 0.05
def mosaic(src):
small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)srcにはモザイクをかけたい画像領域を渡します。
渡されたsrcに対して、ratioの値でモザイク処理を行います。
ratioの値は高いほどモザイクが細かく、低いほどモザイクが荒くなります。
例えば顔の領域全体にモザイク処理を行う場合にはこんな感じで実行すればよいです。
import cv2
ratio = 0.08
def mosaic(src):
small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)
cascade_path = "haarcascade_frontalface_default.xml"
img1 = cv2.imread('lena.jpg')
img1 = cv2.resize(img1,(500,500))
# RGBからGray画像に変換.
gry_img = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
# カスケードファイル読み込み.
cascade = cv2.CascadeClassifier(cascade_path)
facerect = cascade.detectMultiScale(gry_img,scaleFactor=1.5,minNeighbors=2,minSize=(30,30))
if len(facerect) > 0:
x = facerect[0][0]
y = facerect[0][1]
w = facerect[0][2]
h = facerect[0][3]
face = img1[y:y+h,x:x+w]
msc = mosaic(face)
img1[y:y+h,x:x+w] = msc
# フレームを表示する
cv2.imshow("test", img1)
# escキーが押されたらループ終了
cv2.waitKey(0)モザイク処理を行う上で重要なのはこちらで、
facerect = cascade.detectMultiScale(gry_img,scaleFactor=1.5,minNeighbors=2,minSize=(30,30))
if len(facerect) > 0:
x = facerect[0][0]
y = facerect[0][1]
w = facerect[0][2]
h = facerect[0][3]
face = img1[y:y+h,x:x+w]
msc = mosaic(face)
img1[y:y+h,x:x+w] = mscfacerectで顔だと判定した領域を取得し、
顔判定した始点をx,yに格納すると同時に画像の幅や高さをw,hに格納。
顔領域のみをface変数に格納し、先ほどのmosaic関数に突っ込むとモザイクした結果が得られます。
最後に、モザイク結果を元画像に代入します。
ratioを切り替えた時のモザイク画像はこちらになります。
【元画像】

【ratio = 0.2】

【ratio = 0.08】

【ratio = 0.03】

ついでに、、、
ratioを小さくしすぎると荒いモザイクが作成できずエラーとなります。
error: (-215:Assertion failed) !dsize.empty() in function 'cv::resize'
■目にだけモザイク処理
OpenCVには顔のみでなく目のみを検知するカスケードファイルが存在します。
haarcascade_eye.xml
です。
目に対してのみモザイク処理を実施する場合には、
import cv2
ratio = 0.08
def mosaic(src):
small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)
cascade_path = "haarcascade_frontalface_default.xml"
img1 = cv2.imread('lena.jpg')
img1 = cv2.resize(img1,(500,500))
# RGBからGray画像に変換.
gry_img = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
# カスケードファイル読み込み.
cascade = cv2.CascadeClassifier(cascade_path)
facerect = cascade.detectMultiScale(gry_img,scaleFactor=1.5,minNeighbors=2,minSize=(30,30))
if len(eyerect) > 0:
ex_left = eyerect[0][0]
ey_left = eyerect[0][1]
ew_left = eyerect[0][2]
eh_left = eyerect[0][3]
ex_right = eyerect[1][0]
ey_right = eyerect[1][1]
ew_right = eyerect[1][2]
eh_right = eyerect[1][3]
eyes_left = img1[ey_left:ey_left+eh_left,ex_left:ex_right+ew_left]
msc_left = mosaic(eyes_left)
eyes_right = img1[ey_right:ey_right+eh_right,ex_right:ex_right+ew_right]
msc_right = mosaic(eyes_right)
img1[ey_left:ey_left+eh_left,ex_left:ex_right+ew_left] = msc_left
# フレームを表示する
cv2.imshow("test", img1)
# escキーが押されたらループ終了
cv2.waitKey(0)とすればOKです。
下記パラメータの意味ですが、
ex_left = eyerect[0][0]
ey_left = eyerect[0][1]
ew_left = eyerect[0][2]
eh_left = eyerect[0][3]
ex_right = eyerect[1][0]
ey_right = eyerect[1][1]
ew_right = eyerect[1][2]
eh_right = eyerect[1][3]こちらのような関係となっております。

上記を実行させた結果はこんな感じになっており、
目の領域を長方形でモザイク処理しております。

■カメラモジュールからストリーミング配信された画像に対するモザイク処理
今までは画像に対してモザイク処理を行ってきましたが、今度はストリーミング配信された画像に対するモザイク処理です。
ソースはこんな感じ。
import cv2
ratio = 0.05
def mosaic(src):
small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)
# ストリーミング配信されるリンクを指定.
cap = cv2.VideoCapture("リンクパス")
cascade_path = "haarcascade_frontalface_default.xml"
img = cv2.imread('hat.png', cv2.COLOR_BGR2RGB)
img = cv2.resize(img,(100,100))
# リンクが開けなかった場合
if not cap.isOpened():
print("Cannot open a video capture.")
exit(-1)
while True:
# 送られてくる映像のフレームを取得.
ret, frame = cap.read()
frame_mosaic = mosaic(frame)
# RGBからGray画像に変換.
gry_mosaic = cv2.cvtColor(frame_mosaic,cv2.COLOR_BGR2GRAY)
gry_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
# カスケードファイル読み込み.
cascade = cv2.CascadeClassifier(cascade_path)
facerect = cascade.detectMultiScale(gry_img,scaleFactor=1.5,minNeighbors=2,minSize=(30,30))
# 顔認証部分を囲う色の指定.
rectange_color = (255,0,0)
# 顔認識部分を四角で囲う.
if len(facerect) > 0:
x = facerect[0][0]
y = facerect[0][1]
w = facerect[0][2]
h = facerect[0][3]
face = frame[y:y+h,x:x+w]
msc = mosaic(face)
frame[y:y+h,x:x+w] = msc
# もしフレームが取得できなかった場合
if not ret:
continue
# フレームを表示する
cv2.imshow("EV3 Streaming", gry_mosaic)
cv2.imshow("test", frame)
# escキーが押されたらループ終了
k = cv2.waitKey(1)
if k == 27:
break
# キャプチャーの開放&ウィンドウ閉じる
cap.release()
cv2.destroyAllWindows()実行した結果はこんな感じ!!

ちゃんと顔領域のみがモザイクかかってますね。
精度もまぁ、こんなもんかな?って感じです。
■最後に
結構しっかりとモザイク処理が出来ていて結構楽しかったです!!
AIを用いるとモザイク処理した結果を復元できるようなので、今度調べてみようかな??
写真のモザイクを除去して“ほぼ”復元させるAIが登場 | Ledge.ai