シヨツ鬼のブログ

初心者向けに分かりやすくIT関連の情報を発信しています。

【OpenCV C++】顔認識をリアルタイムで行いたい ~1日目~

f:id:shiyotsuki:20200426151531p:plain
どうも、プログラミングの鬼シヨツ鬼です。
この記事では「OpenCV(C++)でWebカメラから取り込んだ映像の顔認識をリアルタイムに行いたいぜ」って人に向けて、僕が試行錯誤した開発記を連載6回で書いています。

ソースコードも載せていますので、ぜひ、参考にしてください。


ちなみに、この記事は下記の動画と関連しています。
こちらの動画を先に見ていただくと、実際に動く際のイメージが掴めます。

YouTube:【自作】ゆゆうたさんをバーチャルユーチューバー化してみた

また、OpenCVのインストール方法はこちらの動画をご覧ください。
YouTube:OpenCVのインストール方法【Visual Studio】【C++】

目次

本記事は次のように、日記っぽく、だんだんアップグレードしていく構成で書いています。
初心者の人は最初から読んでいくと、開発していく気分を味わって頂けます。
中級者以上の方は必要なところだけつまみ食いする感じでもOKです。

※記事が長くなりすぎるため、2~6日目は後続記事へのリンクです

1日目:とりあえずカメラ起動して、顔認識してみた

やりたいこと

・カメラの起動
・顔認識

f:id:shiyotsuki:20200502160141p:plain
完成イメージ

ソースコード

カメラキャプチャのみ

とりあえずカメラを起動しないと何も始まらないので、OpenCVを使ってプログラムからWebカメラを開いてみたいと思います。

#include <opencv2\opencv.hpp>
#include <opencv2/highgui.hpp>
#include <vector>

int main(void) {
	//デバイスのオープン
	cv::VideoCapture cap(0);	
	//カメラデバイスが正常にオープンしたか確認.
	if (!cap.isOpened())
	{
		//読み込みに失敗したときの処理
		return -1;
	}
	//取得したフレーム
	cv::Mat frame; 
	//無限ループ
	while (1)
	{
		//USBカメラが得た動画の1フレームを格納
		cap >> frame;		
		//画像を表示.
		cv::imshow("win", frame);
		//キーボード入力を受け付ける	
		const int key = cv::waitKey(1);
		//qボタンが押されたとき
		if (key == 'q'/*113*/)
		{
			break;//whileループから抜ける.
		}
	}
	//すべてのウィンドウを閉じる
	cv::destroyAllWindows();
	return 0;
}

単純な顔認識

単純な顔認識なら簡単に実現できるので、開いたカメラ映像から顔を検出してみます。

#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
#include <vector>

using namespace cv;
using namespace std;

int main(void) {

	//デバイスのオープン
	VideoCapture cap(0);

	//カメラデバイスが正常にオープンしたか確認.
	if (!cap.isOpened())
	{
		//読み込みに失敗したときの処理
		return -1;
	}

	//取得したフレーム
	Mat frame;

	//カスケード分類器格納場所
	CascadeClassifier cascade; 

	//正面顔情報が入っているカスケード
	cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml"); 
	
	//輪郭情報を格納場所
	vector<Rect> faces; 


	//無限ループ
	while (1)
	{
		//USBカメラが得た動画の1フレームを格納
		cap >> frame;

		//格納されたフレームに対してカスケードファイルに基づいて顔を検知
		cascade.detectMultiScale(frame, faces, 1.1, 3, 0, Size(20, 20));

		//検出した顔の個数"faces.size()"分ループを行う
		for (int i = 0; i < faces.size(); i++) 
		{
			//検出した顔を赤色矩形で囲む
			rectangle(frame, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), Scalar(0, 0, 255), 3); 
		}


		//画像を表示.
		imshow("win", frame);

		//キーボード入力を受け付ける	
		const int key = waitKey(1);

		//qボタンが押されたとき
		if (key == 'q'/*113*/)
		{
			break;//whileループから抜ける.
		}

	}
	//すべてのウィンドウを閉じる
	destroyAllWindows();

	return 0;
}

解説

顔の学習データxmlファイルをちゃんと指定することが大切。
ここが間違っているとエラーで動きません。

まとめ

とりあえずカメラを開くことができました!
また、単純に顔認識をするだけなら、数行付け加えるだけで実現することができました。
しかし、検出に時間がかかるため、映像が非常にカクつきます。。。
2日目は検出速度を上げる工夫をしていきます!

2日目:検出範囲を半分にしたら、検出が早くなった!

続きはこちらの記事へ
【OpenCV C++】顔認識をリアルタイムで行いたい ~2日目~ - シヨツ鬼のブログ

3日目:結論の出ない試行錯誤。。。

続きはこちらの記事へ
【OpenCV C++】顔認識をリアルタイムで行いたい ~3日目~ - シヨツ鬼のブログ

4日目:顔の追従検索で検出速度向上!

続きはこちらの記事へ
【OpenCV C++】顔認識をリアルタイムで行いたい ~4日目~ - シヨツ鬼のブログ

5日目:端っこ対策と斜め対策

続きはこちらの記事へ
【OpenCV C++】顔認識をリアルタイムで行いたい ~5日目~ - シヨツ鬼のブログ

6日目:ついに、バーチャルユーチューバー化!?

続きはこちらの記事へ
【OpenCV C++】顔認識をリアルタイムで行いたい ~6日目~ - シヨツ鬼のブログ

まとめ

画像認識は面白いなぁ
最後まで読んでくれてありがとう。
参考になったら「☆」を押してね。そして僕のYouTubeTwitterもよろしくね。