OpenCV -- 顔認識の概要

1. バックグラウンドデータセット

今回使用したデータ セットは、opencv によって提供されたチュートリアルの最初のデータ セットです。ORL 顔データベースとしても知られる AT&T Facedatabase、40 人、各 10 枚の写真です。さまざまな時間、さまざまな照明、さまざまな表情 (目を開けているときと閉じているとき、笑っているときと笑っていないとき)、および顔の詳細 (メガネの有無) を変えた写真が収集されました。すべての画像は、暗い均一な背景に対して、顔を直立させて(一部はわずかに回転させて)収集されました。 

 

2. 自分の顔データセット

自分自身を特定したい場合は、他人のデータセットだけでは十分ではなく、自分の顔写真も必要です。これには、独自の写真を収集し、上記のデータセットを使用してモデルをトレーニングする必要があります。

Qt開発学習ベース(学習無料登録):C/C++プロジェクト実践/Qt5/C言語/c++/データベース/OpenCV/MFC/QTプロジェクト学習ビデオチュートリアル - Tencent Classroom

2.1. 顔データの収集

次のプログラムは、openCV を呼び出して写真を撮り、P キーを押して写真を撮り、Esc キーを押して終了します。

/**写真プログラム**/

#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
namedWindow("photo",WINDOW_AUTOSIZE);
VideoCapture cap(0);
if(cap.isOpened())
qDebug()<<"打开摄像头成功!";
else
qDebug()<<"打开摄像头失败!";
Mat frame;
int i=1;
while (1)
{
char key = waitKey(100);
cap >> frame;
imshow("photo", frame);
QString filename = QString("D:/Qt/Project/OpenCV/ORL_92x112/s41/s41_%1.bmp").arg(i);
switch (key)
{
case 'p':
imwrite(filename.toStdString(), frame);
waitKey(500);
i++;
break;
default:
break;
}
int c = waitKey(0);
if ((char)c == 27)
return 0;
}
return a.exec();
}

アングルや表情の変化に注目して撮影後、イケメン写真を10枚選択し、自分の顔データセットにします。

 

2.2. 前処理

自分の顔の写真を取得したら、モデルのトレーニングに使用する前に、これらの写真に対していくつかの前処理を実行する必要があります。いわゆる前処理とは、実際には顔を検出してセグメント化し、顔画像のサイズを変更することを意味します。これは、ダウンロードされたデータセット内の画像のサイズ (92 x 112) と一致する必要があります。次のプログラムを使用して、顔を自動的に検出、セグメント化、サイズ変更、保存します。

注: opencv でトレーニングされた分類子と組み込みの検出関数を呼び出して顔を検出するには、事前に OpenCV ソース コード内の分類子を独自のプロジェクト ディレクトリに配置する必要があります。

分類子の場所: D:\Qt\opencv-3.4.5\opencv-3.4.5\data\haarcascades\haarcascade_frontalface_default.xml 移動先: 独自のプロジェクトのビルド ディレクトリ (このディレクトリは必須です)

 

#include <QApplication>
#include <QDebug>
#include <opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString face_cascade_name = "haarcascade_frontalface_default.xml";
CascadeClassifier face_cascade; //定义人脸分类器
QString window_name = "Capture - Face detection";
namedWindow(window_name.toStdString(),WINDOW_AUTOSIZE);
//-- 1. Load the cascades
if (!face_cascade.load(face_cascade_name.toStdString()))
{
qDebug()<<"--(!)Error loading face cascade";
return -1;
}
for(int i=1; i<=10; i++)
{
Mat img = imread(QString("D:/Qt/Project/OpenCV/ORL_92x112/s41/sources/s41_%1.bmp").arg(i).toStdString());
std::vector<Rect> faces;
Mat img_gray;
cvtColor(img, img_gray, COLOR_BGR2GRAY);
equalizeHist(img_gray, img_gray);
//-- Detect faces
face_cascade.detectMultiScale(img_gray, faces, 1.1, 3, CV_HAAR_DO_ROUGH_SEARCH, Size(50, 50));
for (size_t j = 0; j < faces.size(); j++)
{
Mat faceROI = img_gray(faces[j]);
Mat MyFace;
if (faceROI.cols > 100)
{
resize(faceROI, MyFace, Size(92, 112));
QString str = QString("D:/Qt/Project/OpenCV/ORL_92x112/s41/s41_%1.bmp").arg(i);
imwrite(str.toStdString(), MyFace);
imshow(window_name.toStdString(), MyFace);
}
waitKey(10);
}
}
int c = waitKey(0);
if ((char)c == 27)
return 0;
return a.exec();
}

 

 

この時点で、ORL 顔データベースと同じ顔サイズを持つ独自の顔データ セットを取得しました。次に自分を41人目として、ダウンロードした顔フォルダの下にs41というサブフォルダを作成し、その中に自分の顔データを入れます。次のようになります。 最後のフォルダーには、私自身のアバター写真が含まれています。

 

3.csvファイルの生成

顔モデルのトレーニング プログラムを作成するときは、顔とその顔に対応するタグを読み取る必要があります。データベースから直接読み取るのは明らかに効率が悪いため、csv ファイルを使用して読み取ります。CSV ファイルには 2 つの側面が含まれています: 第 1 に、各写真の位置、第 2 に、各顔に対応するラベル (各人物の番号)。以下に示すように:

 

この作業は自分で手作業で行うこともできますが、400枚以上の写真があるため、非常に時間もかかります。

コマンド ラインを開き、顔データ セット ディレクトリに切り替えて、次のコマンドを入力します。

dir /b/s *bmp > at.txt

 

 この記事の特典として、Qt 開発学習パッケージと技術ビデオ (C++ 言語の基礎、Qt プログラミングの概要、QT シグナルとスロットのメカニズム、QT インターフェイス開発イメージの描画、QT ネットワーク、QT データベース) を無料で受け取ることができます。プログラミング、QT プロジェクトの実践、QT 組み込み開発、Quick モジュールなど) ↓↓↓↓下記参照↓↓料金受け取り記事下部をクリック↓↓

 

 

この at.txt は必要な CSV ファイルですが、現在はパスのみが含まれており、ラベルはありません。次のプログラムを使用すると、at_temp.txt が生成されます。これにはパスとラベルの両方が含まれており、まさに必要なものです。以前の at.txt を削除し、生成された at_temp.txt の名前を at.txt に変更します。

#include <QApplication>
#include <QDebug>
#include <QFile>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString fileName1 = "D:/Qt/Project/OpenCV/ORL_92x112/at.txt";
QString fileName2 = "D:/Qt/Project/OpenCV/ORL_92x112/at_temp.txt";
QFile file1(fileName1);
QFile file2(fileName2);
file1.open(QIODevice::ReadOnly | QIODevice::Text);
file2.open(QIODevice::WriteOnly | QIODevice::Text);
int i=0;
int count = 0;
while (!file1.atEnd())
{
count++;
QTextStream stream(&file2);
QByteArray line = file1.readLine();
QString str(line);
str.replace('\\','/');
str.replace('\n',';');
stream << str<<QString("%1").arg(i)<<"\n";
if(count%10 == 0)
{
i++;
count=0;
}
}
file1.close();
file2.close();
qDebug()<<"Done!!!";
return a.exec();
}

 

 

4. モデルのトレーニング

#include <QApplication>
#include <opencv2\opencv.hpp>
#include <iostream>
#include <opencv2/face.hpp>
#include <QDebug>
using namespace cv;
using namespace std;
using namespace face;
//使用CSV文件去读图像和标签,主要使用stringstream和getline方法
static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
std::ifstream file(filename.c_str(), ifstream::in);
if (!file)
{
string error_message = "No valid input file was given, please check the given filename.";
CV_Error(CV_StsBadArg, error_message);
}
string line, path, classlabel;
while (getline(file, line))
{
stringstream liness(line);
getline(liness, path, separator);
getline(liness, classlabel);
if (!path.empty() && !classlabel.empty())
{
images.push_back(imread(path, 0));
labels.push_back(atoi(classlabel.c_str()));
}
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//读取你的CSV文件路径.
string fn_csv = "D:/Qt/Project/OpenCV/ORL_92x112/at.txt";
// 2个容器来存放图像数据和对应的标签
vector<Mat> images;
vector<int> labels;
// 读取数据. 如果文件不合法就会出错
// 输入的文件名已经有了.
try
{
read_csv(fn_csv, images, labels);
}
catch (cv::Exception& e)
{
cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
// 文件有问题,我们啥也做不了了,退出了
exit(1);
}
// 如果没有读取到足够图片,也退出.
if (images.size() <= 1)
{
string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(CV_StsError, error_message);
}
// 下面的几行代码仅仅是从你的数据集中移除最后一张图片
//[gm:自然这里需要根据自己的需要修改,他这里简化了很多问题]
Mat testSample = images[images.size() - 1];
int testLabel = labels[labels.size() - 1];
images.pop_back();
labels.pop_back();
// 下面几行创建了一个特征脸模型用于人脸识别,
// 通过CSV文件读取的图像和标签训练它。
// T这里是一个完整的PCA变换
//如果你只想保留10个主成分,使用如下代码
// cv::createEigenFaceRecognizer(10);
//
// 如果你还希望使用置信度阈值来初始化,使用以下语句:
// cv::createEigenFaceRecognizer(10, 123.0);
//
// 如果你使用所有特征并且使用一个阈值,使用以下语句:
// cv::createEigenFaceRecognizer(0, 123.0);
Ptr<FaceRecognizer> model = EigenFaceRecognizer::create();
model->train(images, labels);
model->save("MyFacePCAModel.xml");
Ptr<FaceRecognizer> model1 = FisherFaceRecognizer::create();
model1->train(images, labels);
model1->save("MyFaceFisherModel.xml");
Ptr<FaceRecognizer> model2 = LBPHFaceRecognizer::create();
model2->train(images, labels);
model2->save("MyFaceLBPHModel.xml");
// 下面对测试图像进行预测,predictedLabel是预测标签结果
int predictedLabel = model->predict(testSample);
int predictedLabel1 = model1->predict(testSample);
int predictedLabel2 = model2->predict(testSample);
QString result_message = QString("Predicted class = %1 | Actual class = %2").arg(predictedLabel).arg(testLabel);
QString result_message1 = QString("Predicted class = %1 | Actual class = %2").arg(predictedLabel1).arg(testLabel);
QString result_message2 = QString("Predicted class = %1 | Actual class = %2").arg(predictedLabel2).arg(testLabel);
qDebug() << result_message << endl;
qDebug() << result_message1 << endl;
qDebug() << result_message2 << endl;
waitKey(0);
return a.exec();
}

 

上記のプログラムは、顔データセットから最後の写真を取得して、トレーニングされたモデルをテストします。顔データセットには合計 40+1 人の人物が含まれていますが、ラベルは 0 から始まるため、最終的な顔ラベルは 40 になります。上記のプログラムの実行結果からわかるように、実際の数は 40 で、予測はも 40 であり、モデルのトレーニングが成功したことを示しています。3 つのトレーニング済みモデルを以下に示します。

 

5. 顔認識

#include <QApplication>
#include <opencv2\opencv.hpp>
#include <iostream>
#include <opencv2/face.hpp>
#include <QDebug>
using namespace cv;
using namespace std;
using namespace face;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
VideoCapture cap(0); //打开默认摄像头
if (!cap.isOpened())
{
return -1;
}
Mat frame;
Mat edges;
Mat gray;
CascadeClassifier cascade;
bool stop = false;
//训练好的文件名称,放置在可执行文件同目录下
cascade.load("D:/Qt/opencv-3.4.5/opencv-3.4.5/data/haarcascades/haarcascade_frontalface_default.xml");
//Ptr<FaceRecognizer> modelPCA = createEigenFaceRecognizer();
//modelPCA->load("MyFacePCAModel.xml");
Ptr<FaceRecognizer> modelPCA = EigenFaceRecognizer::create();
modelPCA->read("D:/Qt/Project/build-OpenCV-Desktop_Qt_5_13_2_MinGW_64_bit-Debug/MyFacePCAModel.xml");//训练的模型
while(!stop)
{
cap >> frame;
//建立用于存放人脸的向量容器
vector<Rect> faces(0);
cvtColor(frame, gray, CV_BGR2GRAY);
//改变图像大小,使用双线性差值
//resize(gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR);
//变换后的图像进行直方图均值化处理
equalizeHist(gray, gray);
cascade.detectMultiScale(gray, faces,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
| CV_HAAR_SCALE_IMAGE,
Size(30, 30));
Mat face;
Point text_lb;
for (size_t i = 0; i < faces.size(); i++)
{
if (faces[i].height > 0 && faces[i].width > 0)
{
face = gray(faces[i]);
text_lb = Point(faces[i].x, faces[i].y);
rectangle(frame, faces[i], Scalar(255, 0, 0), 1, 8, 0);
}
}
Mat face_test;
int predictPCA = 0;
if (face.rows >= 120)
{
resize(face, face_test, Size(92, 112));
imshow("缩放",face_test);
}
//Mat face_test_gray;
//cvtColor(face_test, face_test_gray, CV_BGR2GRAY);
if (!face_test.empty())
{
//测试图像应该是灰度图
predictPCA = modelPCA->predict(face_test);
}
cout << predictPCA << endl;
if (predictPCA == 40)
{
string name = "WangJiChuan";
putText(frame, name, text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(255, 0, 0));
}
imshow("face", frame);
if (waitKey(1) >= 0)
stop = true;
}
return a.exec();
}

上の図からわかるように、自分の顔ラベルは 35 です。認識された顔が 35 の場合、正常に自分であると認識され、顔がマークされ、名前が付けられます。 

 

 

C++ Qt は、豊富な UI コンポーネントと API ライブラリを備えた、C++ 言語に基づくクロスプラットフォーム アプリケーション開発フレームワークです。Qt には、Qt Core、Qt GUI、Qt Network などの多くのモジュールが含まれています。各モジュールは一連のクラスと関数を提供します。Qt は、開発者が Qt アプリケーションを作成、コンパイル、デバッグ、デプロイできる統合開発環境 (IDE) Qt Creator も提供します。 

Qt 開発を学ぶときに何をすればよいかわかりませんか? 私が皆さんのためにまとめた分野は、Qt 開発に関係します: 組み込み分野、デスクトップ開発、モバイル端末、マイコン MCU、クライアント (ゲーム、生放送など)、自動車産業、家電機器、医療分野、産業、産業オートメーション分野、等

Qt フレームワーク、GUI アプリケーション、クロスプラットフォーム開発、シグナルおよびスロット メカニズム、QML 言語、モデル ビュー プログラミング、マルチスレッド プログラミング、データベース プログラミング、ネットワーク プログラミング、XML 解析、JSON 解析、グラフィックスおよび画像処理、ユーザー インターフェイス設計、アニメーションエフェクト、OpenGL、WebKit、組み込み開発、クライアント/サーバー アプリケーション、カスタム コントロール QT6、C++ 言語の基礎、qt 基本プログラミング、qt ソフトウェア開発、Qt アーキテクチャ設計、qt レイアウト マネージャー、qt 組み込み開発、qt プログラミング入門、qt データベース プログラミング、 QT クロスプラットフォーム フレームワーク、QT プロジェクトの実践、クイック モジュール、OpenCV、Qt の実践、OpenCV チュートリアル、QT インターフェイス開発、Qt フレームワーク、C++ データ構造、Qt スレッド、デスクトップ アプリケーション開発、QT デスクトップ アプリケーション開発、ソケット ネットワーク プログラミング、QT 開発エンジニア、qt 開発、アプリケーション開発フレームワーク、グラフィカル ビュー フレームワーク、データベース プログラミング、Qt 開発プログラミング、Qt 開発制御、Qt 開発エンジニア、QT 開発必須スキル スタック、Qt コーディング、Qt ネットワーク プログラミング、Qt ネットワーク通信、Qt シグナル、Qt スロットメカニズム、qt 文字列、qt データ型、qt コンテナ、qt クライアント開発、qt ソフトウェア エンジニア、qt ページ描画

 

 この記事の特典として、Qt 開発学習パッケージと技術ビデオ (C++ 言語の基礎、Qt プログラミングの概要、QT シグナルとスロットのメカニズム、QT インターフェイス開発イメージの描画、QT ネットワーク、QT データベース) を無料で受け取ることができます。プログラミング、QT プロジェクトの実践、QT 組み込み開発、Quick モジュールなど) ↓↓↓↓下記参照↓↓料金受け取り記事下部をクリック↓↓

おすすめ

転載: blog.csdn.net/hw5230/article/details/131263967