はじめに
前回の第5回でWebカメラの映像をkivyにうまく表示できるようになりました。
今回はこれをさらに改良してOpenCVの顔検出器を使って顔認識を行います。
顔に赤枠を付けたりモザイクをかけたりしますので、画面も少々改良します。
顔検出カスケードファイルのダウンロード
OpenCVの顔検出器で利用するカスケードファイルをダウンロードしてきます。
いろいろなファイルがあるのですが、今回は顔正面のファイル「haarcascade_frontalface_alt.xml」を利用します。
次のサイト(GitHub)へアクセスします。
赤枠のhaarcascade_frontalface_alt.xmlをクリックすると次の画面が表示されます。
赤枠のRawを右クリックしてリンク先を保存します。
保存先は、D:\PyDev\GuiKivy としました。
改良したソースファイル
保存先は、D:\PyDev\GuiKivyです。
仮想環境のアクティブ化を忘れずに実行します。env\Scripts\activate
from kivy.app import App from kivy.lang import Builder from kivy.uix.boxlayout import BoxLayout import time import cv2 from kivy.uix.image import Image from kivy.graphics.texture import Texture from kivy.properties import StringProperty, ObjectProperty from kivy.clock import Clock Builder.load_string(''' <CameraClick>: orientation: 'vertical' BoxLayout: orientation: 'horizontal' padding: 0 spacing: 1 size_hint: 1, 0.1 Image: id: camera size_hint: None, None size: 640, 480 BoxLayout: orientation: 'vertical' ToggleButton: text: 'Face' on_press: root.face() size_hint_y: None height: '48dp' ToggleButton: text: 'Mosaic' on_press: root.mosaic() size_hint_y: None height: '48dp' ToggleButton: text: 'Play' on_press: root.play() size_hint_y: None height: '48dp' Button: text: 'Capture' size_hint_y: None height: '48dp' on_press: root.capture() ''') class CameraClick(BoxLayout): image_texture = ObjectProperty(None) image_capture = ObjectProperty(None) def face(self): global flgFace flgFace = not flgFace def mosaic(self): global flgMosaic flgMosaic = not flgMosaic def play(self): global flgPlay flgPlay = not flgPlay if flgPlay == True: self.image_capture = cv2.VideoCapture(0) Clock.schedule_interval(self.update, 1.0 / 30) else: Clock.unschedule(self.update) self.image_capture.release() def update(self, dt): ret, frame = self.image_capture.read() if ret: if flgFace == True or flgMosaic == True: # カスケードファイルを指定して検出器を作成 cascade_file = "haarcascade_frontalface_alt.xml" cascade = cv2.CascadeClassifier(cascade_file) # カメラ映像をグレースケールに変換 frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 顔検出 face_list = cascade.detectMultiScale(frame_gray, minSize=(30, 30)) if len(face_list) > 0: red = (0, 0, 255) for (x, y, w, h) in face_list: if flgFace == True: frame = cv2.rectangle(frame, (x, y), (x+w, y+h), red, thickness = 2) if flgMosaic == True: frame = self.procMosaic(frame, (x, y, x+w, y+h), 5) # カメラ映像を上下左右反転 buf = cv2.flip(frame, -1) image_texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr') image_texture.blit_buffer(buf.tostring(), colorfmt='bgr', bufferfmt='ubyte') camera = self.ids['camera'] camera.texture = image_texture def capture(self): ''' Function to capture the images and give them the names according to their captured time and date. ''' camera = self.ids['camera'] timestr = time.strftime("%Y%m%d_%H%M%S") camera.export_to_png("IMG_{}.png".format(timestr)) print("Captured") def procMosaic(self, img, rect, size): # モザイクをかける領域を取得 (x1, y1, x2, y2) = rect w = x2 - x1 h = y2 -y1 i_rect =img[y1:y2, x1:x2] # 一度縮小して拡大する i_small = cv2.resize(i_rect, (size, size)) i_mos = cv2.resize(i_small, (w, h), interpolation=cv2.INTER_AREA) # 画像にモザイク画像を重ねる img2 = img.copy() img2[y1:y2, x1:x2] = i_mos return img2 class TestCamera(App): def build(self): return CameraClick() flgPlay = False flgFace = False flgMosaic = False TestCamera().run()
ちょこっと解説
kv言語
・今回、顔認識用とモザイク用の2つのトグルボタンを追加したのですが、カメラ映像の右側に表示させました。
・BoxLayoutを利用して、追加する2つのトグルボタンを縦並びにし(24行目から35行目)、カメラ映像のイメージコントロールと横並びにします。(14行目から35行目)
・追加する2つのトグルボタンは、Playと同じようにフラグのOnOffで利用します。
・トグルボタンはそれぞれ、FaceとMosaicとしました。
pythonコード
・FaceトグルボタンがクリックされたときにFaceフラグを変化させる処理を追加。(54行目から56行目)
・MosaicトグルボタンがクリックされたときにMosaicフラグを変化させる処理を追加。(58行目から60行目)
・FaceフラグかMosaicフラグがTrueの場合の処理を追加します。(75行目から89行目)
・ダウンロードしたカスケードファイルを指定して検出器を作成します。(77行目、78行目)
・カメラ映像をグレースケールに変換します。(80行目)
・顔検出させます。(82行目)
・FaceフラグがTrueの場合、赤枠で顔を囲みます。(86行目、87行目)
・MosaicフラグがTrueの場合、顔にモザイクをかけます。(88行目、89行目)
・モザイクをかける処理を追加します。(107行目から119行目)
・FaceフラグとMosaicフラグの初期化を行います。(129行目、130行目)
実行結果
起動すると次の画面が表示されます。
PlayしてFaceボタンとMosaicボタンを押してCaptureしたときの画像が次のものです。
証明写真と一緒に顔検出&モザイクがかかりました。赤枠だけやモザイクだけでも動作しますので是非お試しください。
最後に
上手く動作して少しニヤニヤしてしまい、その顔が画面に表示されてさらにニヤニヤ。あぶないおっさんの出来上がり。
どんどん面白くなってきました。
ボタンを配置するスペースもまだあるし色々な画像処理を加えてみるのも楽しいかもしれません。
また、多重処理になるのでどのくらいまでレスポンスに耐えられるものなのかも気になるところですね。