OpenCV--Introducción al reconocimiento facial

1. Conjunto de datos de antecedentes

El conjunto de datos utilizado esta vez es el primer conjunto de datos del tutorial proporcionado por opencv: AT&T Facedatabase, también conocida como base de datos de rostros ORL, 40 personas, 10 fotos cada una. Las fotografías fueron recopiladas en diferentes momentos, con diferente iluminación, con diferentes expresiones (ojos abiertos y cerrados, sonriendo o no sonriendo) y con diferentes detalles faciales (con o sin gafas). Todas las imágenes fueron tomadas sobre un fondo oscuro uniforme, con los rostros erguidos (algunos ligeramente girados). 

 

2. Tu propio conjunto de datos faciales

Si desea identificarse, no basta con disponer únicamente de los conjuntos de datos de otras personas, también necesita fotografías de su propio rostro. Esto requiere que recopilemos nuestras propias fotografías y luego entrenemos el modelo con los datos establecidos anteriormente.

Base de aprendizaje de desarrollo de Qt (registro gratuito para aprender): práctica de proyectos C/C++/lenguaje Qt5/C/c++/database/OpenCV/MFC/QT video tutorial de aprendizaje de proyectos-Tencent Classroom

2.1 Recopilación de datos faciales

El siguiente programa llama a openCV para tomar una fotografía, presiona la tecla P para tomar una fotografía y presiona Esc para salir.

/**Programa de fotografía**/

#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();
}

Preste atención a los cambios de ángulo y expresión. Después de tomar la foto, seleccione diez fotos hermosas para su propio conjunto de datos faciales.

 

2.2 Preprocesamiento

Después de obtener fotografías de su propio rostro, debe realizar un preprocesamiento en estas fotografías antes de poder usarlas para entrenar el modelo. El llamado preprocesamiento en realidad significa detectar y segmentar rostros y cambiar el tamaño de las imágenes de los rostros, que deben ser consistentes con el tamaño de las imágenes en el conjunto de datos descargados (92 x 112). Utilice los siguientes programas para detectar, segmentar, cambiar el tamaño y almacenar caras automáticamente.

Nota: Para llamar al clasificador entrenado en opencv y a la función de detección incorporada para detectar caras, debe colocar el clasificador en el código fuente de OpenCV en el directorio de su propio proyecto con anticipación;

Ubicación del clasificador: D:\Qt\opencv-3.4.5\opencv-3.4.5\data\haarcascades\haarcascade_frontalface_default.xml​ Mover a: el directorio de compilación de su propio proyecto (este directorio es obligatorio)

 

#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();
}

 

 

En este punto, hemos obtenido nuestro propio conjunto de datos faciales con el mismo tamaño de cara que la base de datos de caras ORL. Luego nos consideramos la persona número 41, creamos una subcarpeta de s41 en la carpeta de rostros que descargamos y colocamos nuestros propios datos faciales en ella. Se ve así: La última carpeta contiene mi propia foto de avatar:

 

3. generación de archivos csv

Cuando escribimos el programa de entrenamiento para el modelo facial, necesitamos leer la cara y las etiquetas correspondientes a la cara. Leer directamente desde la base de datos es obviamente ineficiente, por lo que usamos un archivo csv para leer. El archivo csv contiene dos aspectos: primero, la ubicación de cada imagen; segundo, la etiqueta correspondiente a cada rostro, que es el número de cada persona. Como se muestra abajo:

 

Este trabajo lo puedes hacer tú mismo manualmente, pero con más de 400 imágenes, también lleva mucho tiempo. ¡Aprecia tu vida y toma el siguiente camino!

Abra la línea de comando, cambie al directorio del conjunto de datos faciales e ingrese el siguiente comando:

dir /b/s *bmp > at.txt

 

 Como beneficio de este artículo, puede recibir un paquete de aprendizaje de desarrollo de Qt y videos técnicos de forma gratuita, que incluyen (conceptos básicos del lenguaje C++, introducción a la programación de Qt, mecanismo de ranura y señal de QT, dibujo de imágenes de desarrollo de interfaz de QT, red de QT, base de datos de QT). programación, práctica de proyectos QT , para recibir la tarifa↓↓

 

 

Este at.txt es el archivo csv que necesitamos, pero ahora solo tiene una ruta y no tiene etiqueta. Usando el siguiente programa, se generará un at_temp.txt. Este tiene tanto una ruta como una etiqueta, que es exactamente lo que queremos. Elimina el at.txt anterior y cambia el nombre del at_temp.txt generado a 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. Entrenamiento modelo

#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();
}

 

El programa anterior toma la última foto del conjunto de datos faciales para probar el modelo entrenado. Hay un total de 40 + 1 personas en el conjunto de datos faciales, pero las etiquetas comienzan desde 0, por lo que la etiqueta facial final es 40. Como se puede ver en los resultados de ejecución del programa anterior, el número real es 40 y la predicción También es 40, lo que indica que el entrenamiento del modelo fue exitoso Tres Un modelo entrenado se muestra a continuación:

 

5. Reconocimiento facial

#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();
}

Como se puede ver en la imagen de arriba, la etiqueta de su propia cara es 35. Cuando la cara reconocida es 35, se reconoce con éxito como usted mismo, se marca con una cara y se le coloca un nombre. 

 

 

C++ Qt es un marco de desarrollo de aplicaciones multiplataforma basado en el lenguaje C++, con componentes de interfaz de usuario enriquecidos y bibliotecas API. Qt incluye muchos módulos, como Qt Core, Qt GUI, Qt Network, etc. Cada módulo proporciona una serie de clases y funciones. Qt también proporciona un entorno de desarrollo integrado (IDE) Qt Creator, que permite a los desarrolladores crear, compilar, depurar e implementar aplicaciones Qt. 

¿No sabes qué hacer al aprender a desarrollar Qt? Los campos que he recopilado para todos ustedes involucran el desarrollo de Qt: campo integrado, desarrollo de escritorio, terminal móvil, microcontrolador MCU, cliente (juegos, transmisión en vivo, etc.), industria automotriz, equipos de electrónica de consumo, industria médica, campo de automatización industrial, etc.

Marco Qt, aplicaciones GUI, desarrollo multiplataforma, mecanismo de señal y ranura, lenguaje QML, programación de vista de modelo, programación multiproceso, programación de bases de datos, programación de redes, análisis XML, análisis JSON, procesamiento de gráficos e imágenes, diseño de interfaz de usuario, animación efectos, OpenGL, WebKit, desarrollo integrado, aplicaciones cliente/servidor, control personalizado QT6, conceptos básicos del lenguaje C++, programación básica qt, desarrollo de software qt, diseño de arquitectura Qt, administrador de diseño qt, desarrollo integrado qt, introducción a la programación qt, programación de bases de datos qt, Marco multiplataforma qt, práctica de proyectos QT, módulo rápido, OpenCV, práctica de Qt, tutorial de OpenCV, desarrollo de interfaz QT, marco Qt, estructura de datos C++, hilo Qt, desarrollo de aplicaciones de escritorio, desarrollo de aplicaciones de escritorio qt, programación de redes de socket, desarrollo qt ingeniero, desarrollo qt, marco de desarrollo de aplicaciones, marco de vista gráfica, programación de bases de datos, programación de desarrollo Qt, control de desarrollo Qt, ingeniero de desarrollo Qt, pila de habilidades esenciales de desarrollo QT, codificación qt, programación de red qt, comunicación de red qt, señal Qt, ranura Qt mecanismo, cadena qt, tipo de datos qt, contenedor qt, desarrollo de cliente qt, ingeniero de software qt, dibujo de página qt

 

 Como beneficio de este artículo, puede recibir un paquete de aprendizaje de desarrollo de Qt y videos técnicos de forma gratuita, que incluyen (conceptos básicos del lenguaje C++, introducción a la programación de Qt, mecanismo de ranura y señal de QT, dibujo de imágenes de desarrollo de interfaz de QT, red de QT, base de datos de QT). programación, práctica de proyectos QT , para recibir la tarifa↓↓

Supongo que te gusta

Origin blog.csdn.net/hw5230/article/details/131263967
Recomendado
Clasificación