PythonのOpenCVを使った目の検出で鼻を囲まないようにする方法
PythonのOpenCVを使って目を検出すると、目以外の鼻の穴も目と検出されてしまいます。そして、検出した場所にcv2.rectangleをすると鼻も四角で囲んでしまうので、鼻を囲まないようにして目だけ囲む方法を動画を使って紹介します。
読み込んで表示した動画は「Pexels」の動画を使わさせてもらいました。
検出するのに使ったもと動画と鼻を囲んでしまっている動画、鼻を囲まないようにして目だけ囲んでいる動画をYouTubeで投稿しています。
顔と目を検出するときに使うhaarcascadeファイルのダウンロード方法は↓こちらで紹介しています。
「OpenCVを使った顔と目の検出方法 Python」
目次
・もと動画
・顔と目を検出するプログラム
・鼻を囲んでしまっている様子
・鼻を囲まないようにするプログラム
・目だけを囲んでいる様子
もと動画
顔と目を検出するのに使ったもと動画になります。
動画の読み込みと表示はこちら↓の投稿で紹介したプログラムを使いました。
顔と目を検出するプログラム
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import cv2 face_cascade=cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")#顔を検出するカスケードファイル eye_cascade = cv2.CascadeClassifier("haarcascade_eye.xml")#目を検出するカスケードファイル def detectface(img):# img_gray=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#グレイ画像 images = face_cascade.detectMultiScale(img_gray)#顔の検出 for x,y,w,h in images:# cv2.rectangle(img, (x, y), (x+w, y+h), (0,0,255), 3)#顔を囲む face=img[y:y+h,x:x+w]#顔切り取る face_gray=img_gray[y:y+h,x:x+w]#顔のグレイ画像 eyes = eye_cascade.detectMultiScale(face_gray)#目の検出 for ex,ey,ew,eh in eyes: cv2.rectangle(face, (ex, ey), (ex+ew, ey+eh), (255,0,0), thickness=3)#目を四角で囲む mv= cv2.VideoCapture('pexels-anastasia-shuraeva-6014532.mp4')#動画の読み込み frame_count =int(mv.get(cv2.CAP_PROP_FRAME_COUNT))#動画を画像にしたときの総枚数 for i in range(frame_count):#総枚数繰り返す ch,frame=mv.read()#動画から1フレーム(画像)を取り出す if ch==True:#取り出せたか確認 size=(640,480) frame=cv2.resize(frame,size)#サイズ調整 detectface(frame)#自作関数の呼び出し cv2.imshow('movie', frame)#表示 k=cv2.waitKey(1)#1ミリ秒wait if k==27:#ESCキーを押したとき break mv.release() cv2.destroyAllWindows() |
動画の読み込みとdef文で作成した自作関数の呼び出しはこちら→「Pythonで動画に写る人を検出する方法」の投稿で説明しているので、3~17行目の顔と目を検出して、四角で囲むプログラムの説明をします。
3、4行目は顔と目を検出するためのファイルを読み込んでいます。
6~17行目の自作関数detectfaceは、まず7行目で顔を検出するために読み込んだ画像をグレイ画像にしています。そして、8行目でグレイ画像からface_cascade.detectMultiScale(img_gray)をして顔を検出しています。
※顔と目を検出するときはグレイにした画像を使います。グレイ画像にして、色を少なくすることで処理を行いやすくしています。
10~14行目は検出した顔の座標の数、for文で繰り返す処理をし、検出した顔を四角で囲んでいます。そして、13行目でグレイ画像にした画像から検出した顔を切り取り、そこから14行目のeye_cascade.detectMultiScale(face_gray)をして目を検出しています。
16、17行目は検出した目の座標の数、for文で繰り返す処理をし、検出した目を四角で囲んでいます。
最後に28行目のcv2.imshow(‘movie’, frame)で四角で囲んだ画像を表示しています。この処理を20行目で動画から画像にした枚数を1フレームずつ繰り返すことで動画のように表示しています。
上の顔と目を検出するプログラムを実行したのがこちら↓になります。
鼻を囲んでしまっている様子
目以外の鼻も四角で囲んで四角でしまっています。
鼻を囲まないようにするプログラム
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
import cv2 face_cascade=cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")#顔を検出するカスケードファイル eye_cascade = cv2.CascadeClassifier("haarcascade_eye.xml")#目を検出するカスケードファイル def detectface(img):# img_gray=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#グレイ画像 images = face_cascade.detectMultiScale(img_gray)#顔の検出 for x,y,w,h in images:# cv2.rectangle(img, (x, y), (x+w, y+h), (0,0,255), 3)#顔を囲む face=img[y:y+h,x:x+w]#顔切り取る face_gray=img_gray[y:y+h,x:x+w]#顔のグレイ画像 eyes = eye_cascade.detectMultiScale(face_gray)#目の検出 half_face=face.shape[0]//2#顔の高さを半分にした値を求める for ex,ey,ew,eh in eyes: if ey <= half_face:#half_faceの値、以下の高さの位置で目を検出した場合 cv2.rectangle(face, (ex, ey), (ex+ew, ey+eh), (255,0,0), thickness=3)#目を四角で囲む mv= cv2.VideoCapture('pexels-anastasia-shuraeva-6014532.mp4')#動画の読み込み frame_count =int(mv.get(cv2.CAP_PROP_FRAME_COUNT))#動画を画像にしたときの総枚数 for i in range(frame_count):#総枚数繰り返す ch,frame=mv.read()#動画から1フレーム(画像)を取り出す if ch==True:#取り出せたか確認 size=(640,480) frame=cv2.resize(frame,size)#サイズ調整 detectface(frame)#自作関数の呼び出し cv2.imshow('movie', frame)#表示 k=cv2.waitKey(1)#1ミリ秒wait if k==27:#ESCキーを押したとき break mv.release() cv2.destroyAllWindows() |
鼻を囲まないようにする方法は、顔の上半分の位置で目を検出したら、その部分だけ四角で囲むようにしています。
「顔と目を検出するプログラム」から変更したのが16~19行目だけなので、その部分のプログラムを説明します。
16行目はface.shape[0]//2で顔の高さの値を//2で半分にした値を求めています。そして、求めた値を変数half_faceに入れています。
※face.shape[0]について、face.shapeはprint(face.shape)で表示すると このプログラムの場合は(262, 262, 3)このような表示になりす。これは(高さ、幅、色の数)を表しています。よって、face.shape[0]は[0]で高さの値だけを取り出しています。
17~19行目は検出した目の座標の数、for文で繰り返す処理をし、half_face(顔の高さの値を半分にした値)以下の値で目を検出した場合、その場所を四角で囲んでいます。これで、鼻の穴を目と検出したとしても、四角で囲まないようにしています。
画像の高さの座標は上から下にいくに連れて値が大きくなっているので、目の高さの座標は鼻よりも小さいです。
だから、if ey <= half_face(eyは目の高さの座標)このような条件にしています。
上の鼻を囲まないようにするプログラムを実行したのがこちら↓になります。