ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

人工智能之口罩检测算法

2020-02-27 18:36:31  阅读:1236  来源: 互联网

标签:口罩 img 人工智能 frame cascade 算法 vector faces model


由于疫情的影响,口罩检测已经成为各个程序员竞相开发的一种算法。
百度的人脸检测SDK使用的还不错,他们还把口罩检测也给开源了
我这里使用基于OPENCV的检测

一般的思路可能就是手机带有口罩和没有戴口罩的数据集进行训练,但是我暂时没有找到这些数据集,我就采用使用opencv原来带有的训练集先检测出人脸,然后再对人脸检测鼻子和嘴巴。但是由于opencv的检测鼻子和嘴巴的算法准确性不高,需要经过附加条件检测是不是真正的嘴巴和鼻子,如果在人脸中检测出了嘴巴和鼻子的话,那么没有戴口罩puttext no mask,否则就进行人脸识别

那么要进行人脸识别的话,需要采集本人的数据,然后在获取ORL的数据集一同训练。我这里获取了ORL提供的40个样本,每个样本里面有10个bmp格式的图像。
现在我们开始获取数据集,思路很简单,就是打开摄像头,对每一帧图像进行处理。对这每一帧图像识别出人脸,如果人脸的size为1,那么表示这就是你的人脸,然后把处理后的人脸保存起来。
为了拍摄多角度图像,需要每处理一次都需要等待,设置一个计数器,当经过十次的拍摄后,就退出程序

int makepicture()
{
	CascadeClassifier cascada;
	cascada.load("E:/OPENCV/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml");
	VideoCapture cap(0);
	Mat frame, myFace;
	int pic_num = 1;
	while (1) {
		cap >> frame;
		vector<Rect> faces;//vector容器存检测到的faces
		Mat frame_gray;
		cvtColor(frame, frame_gray, COLOR_BGR2GRAY);//转灰度化,减少运算
		cascada.detectMultiScale(frame_gray, faces, 1.1, 4, CV_HAAR_DO_ROUGH_SEARCH, Size(70, 70), Size(1000, 1000));
		for (int i = 0; i < faces.size(); i++)
		{
			rectangle(frame, faces[i], Scalar(255, 0, 0), 2, 8, 0);
		}
		//当只有一个人脸时,开始拍照
		if (faces.size() == 1)
		{
			Mat faceROI = frame_gray(faces[0]);//在灰度图中将圈出的脸所在区域裁剪出
			//cout << faces[0].x << endl;//测试下face[0].x
			resize(faceROI, myFace, Size(92, 112));//将兴趣域size为92*112
			putText(frame, to_string(pic_num), faces[0].tl(), 3, 1.2, (0, 0, 225), 2, 0);//在 faces[0].tl()的左上角上面写序号
			string filename = "样本/s41/"+to_string(pic_num)+".bmp"; //存放在当前项目文件夹以1-10.jpg 命名,format就是转为字符串
			imwrite(filename, myFace);//存在当前目录下
			imshow(filename, myFace);//显示下size后的脸
			waitKey(500);//等待500us
			destroyWindow(filename);//:销毁指定的窗口
			pic_num++;//序号加1
			if (pic_num == 11)
			{
				return 0;//当序号为11时退出循环
			}
		}
		int c = waitKey(10);
		if ((char)c == 27) { break; } //10us内输入esc则退出循环
		imshow("frame", frame);//显示视频流
		waitKey(100);//等待100us
	}
	return 0;

}

然后需要对自己的样本进行处理

void initdata()
{
	/*
	对于训练样本:
	Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
	model->train(img, labels);train函数的两个参数也很简单,训练的图像组vector<Mat>和对应的标签组vector<int>,这个label标签只需保证同一个人的标签相同即可,不需要保证图像的按标签顺序输入。
	*/
	vector<Mat> img;
	vector<int> labels;//定义标签还有图片
	for (int i = 1; i <= 41; i++)
	{
		for (int j = 1; j < 11; j++)
		{
			string path = "样本/s"+to_string(i)+"/" + to_string(j) + ".bmp";
			Mat img_gray = imread(path);
			cvtColor(img_gray, img_gray, COLOR_BGR2GRAY);
			img.push_back(img_gray);
			labels.push_back(i);
		}
	}
	Ptr<FaceRecognizer> model = createFisherFaceRecognizer();//训练
	model->train(img, labels);
	model->save("model.xml");
}

ok,处理完自己的样本之后,就可以直接打开摄像头,对每一帧识别出人脸,如果人脸有嘴巴或者鼻子的时候,就把他视作没有带口罩;如果没有的话,加载数据集,然后预测人脸,显示预测结果
核心代码如下

void fun(Mat& img, CascadeClassifier& face_cascade, CascadeClassifier& eyes_cascade, CascadeClassifier& nose_cascade, CascadeClassifier& mouse_cascade, Ptr<FaceRecognizer> model, Vector<string> name)
{
	vector<Rect> faces;//脸的存储
	vector<Rect> noses;
	vector<Rect> mouses;
	Mat frame;//需要使用灰度图
	Mat predect;
	cvtColor(img, frame, COLOR_BGR2GRAY);
	face_cascade.detectMultiScale(frame, faces, 1.2, 7, 0, Size(80, 80));//分类器检测人脸
	//输入照片,检测到的人脸序列,图像尺寸减小比例,检测5次,最小尺寸  最大尺寸
	for (int i = 0; i < faces.size(); i++)
	{
		frame(faces[i]).copyTo(predect);
		resize(predect,predect,Size(92,112));
		mouse_cascade.detectMultiScale(predect, mouses, 1.2, 8, 0, Size(5, 5));
		nose_cascade.detectMultiScale(predect, noses, 1.2, 8, 0, Size(5, 5));
		//imshow("",predect);
		int label=-1;
		double predectnumber=0;
		model->predict(predect,label, predectnumber);
		rectangle(img, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height),
			Scalar(0, 255, 0), 1, 8);    //框出人脸位置左上和右下
		if(mouses.size()>0||noses.size()>0)
			putText(img, "no mask", Point(faces[i].x, faces[i].y), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 4, 8);
		else
		{
			if (predectnumber>70)
				putText(img, name[label-1], Point(faces[i].x, faces[i].y), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 4, 8);
			else
				putText(img, "I dont know", Point(faces[i].x, faces[i].y), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255),4,8);
		}
		
	}
	imshow("FacesOfPrettyGirl", img);
}

测试的结果如下图
在这里插入图片描述

在这里插入图片描述

整个程序如下

#include <opencv2\contrib\contrib.hpp>  
#include <opencv2\core\core.hpp>  
#include <opencv2\highgui\highgui.hpp>  
#include "opencv2\opencv.hpp"

#include <iostream>  
#include <fstream>  
#include <sstream>  

using namespace std;
using namespace cv;


String face_cascade_name = "E:/OPENCV/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml";
String eyes_cascade_name = "E:\\OPENCV\\opencv\\sources\\data\\haarcascades\\haarcascade_eye_tree_eyeglasses.xml";
String mouse_cascade_name = "E:/OPENCV/opencv/sources/data/haarcascades/haarcascade_mcs_mouth.xml";
String nose_cascade_name = "E:/OPENCV/opencv/sources/data/haarcascades/haarcascade_mcs_nose.xml";
CascadeClassifier face_cascade;   //定义人脸分类器  
CascadeClassifier eyes_cascade;   //定义人眼分类器 
CascadeClassifier nose_cascade;   //定义鼻子分类器
CascadeClassifier mouse_cascade;   //定义嘴巴分类器    
String window_name = "Capture - Face detection";
void fun(Mat& img, CascadeClassifier& face_cascade, CascadeClassifier& eyes_cascade, CascadeClassifier& nose_cascade, CascadeClassifier& mouse_cascade, Ptr<FaceRecognizer> model, Vector<string> name);
void initdata();
void initdataname();
int makepicture();
int main() {
	if (!face_cascade.load(face_cascade_name)) { printf("--(!)Error loading face cascade\n"); return -1; };
	if (!eyes_cascade.load(eyes_cascade_name)) { printf("--(!)Error loading eyes cascade\n"); return -1; };
	if (!nose_cascade.load(nose_cascade_name)) { printf("--(!)Error loading nose cascade\n"); return -1; };
	if (!mouse_cascade.load(mouse_cascade_name)) { printf("--(!)Error loading mouse cascade\n"); return -1; };
	//initdataname();
	//initdata();
	//makepicture();
	Vector<string>name;
	ifstream infile("dataname.csv", ios::in);
	string line, field;
	for (int i = 0; i < 41; i++)
	{
		getline(infile, line);
		stringstream sin(line);
		getline(sin, field);
		name.push_back( field);
	}
	infile.close();

	VideoCapture capture(0);
	Ptr<FaceRecognizer> model = createFisherFaceRecognizer();
	model->load("model.xml");
	while (true) {
		Mat frame;
		capture >> frame;
		fun(frame, face_cascade, eyes_cascade,nose_cascade,mouse_cascade ,model,name);
		waitKey(1);
	}
	system("pause");
	return 0;
}

void fun(Mat& img, CascadeClassifier& face_cascade, CascadeClassifier& eyes_cascade, CascadeClassifier& nose_cascade, CascadeClassifier& mouse_cascade, Ptr<FaceRecognizer> model, Vector<string> name)
{
	vector<Rect> faces;//脸的存储
	vector<Rect> noses;
	vector<Rect> mouses;
	Mat frame;//需要使用灰度图
	Mat predect;
	cvtColor(img, frame, COLOR_BGR2GRAY);
	face_cascade.detectMultiScale(frame, faces, 1.2, 7, 0, Size(80, 80));//分类器检测人脸
	//输入照片,检测到的人脸序列,图像尺寸减小比例,检测5次,最小尺寸  最大尺寸
	for (int i = 0; i < faces.size(); i++)
	{
		frame(faces[i]).copyTo(predect);
		resize(predect,predect,Size(92,112));
		mouse_cascade.detectMultiScale(predect, mouses, 1.2, 8, 0, Size(5, 5));
		nose_cascade.detectMultiScale(predect, noses, 1.2, 8, 0, Size(5, 5));
		//imshow("",predect);
		int label=-1;
		double predectnumber=0;
		model->predict(predect,label, predectnumber);
		rectangle(img, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height),
			Scalar(0, 255, 0), 1, 8);    //框出人脸位置左上和右下
		if(mouses.size()>0||noses.size()>0)
			putText(img, "no mask", Point(faces[i].x, faces[i].y), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 4, 8);
		else
		{
			if (predectnumber>70)
				putText(img, name[label-1], Point(faces[i].x, faces[i].y), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 4, 8);
			else
				putText(img, "I dont know", Point(faces[i].x, faces[i].y), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255),4,8);
		}
		
	}
	imshow("FacesOfPrettyGirl", img);
}

void initdata()
{
	/*
	对于训练样本:
	Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
	model->train(img, labels);train函数的两个参数也很简单,训练的图像组vector<Mat>和对应的标签组vector<int>,这个label标签只需保证同一个人的标签相同即可,不需要保证图像的按标签顺序输入。
	*/
	vector<Mat> img;
	vector<int> labels;//定义标签还有图片
	for (int i = 1; i <= 41; i++)
	{
		for (int j = 1; j < 11; j++)
		{
			string path = "样本/s"+to_string(i)+"/" + to_string(j) + ".bmp";
			Mat img_gray = imread(path);
			cvtColor(img_gray, img_gray, COLOR_BGR2GRAY);
			img.push_back(img_gray);
			labels.push_back(i);
		}
	}
	Ptr<FaceRecognizer> model = createFisherFaceRecognizer();//训练
	model->train(img, labels);
	model->save("model.xml");
}
void initdataname()
{
	ofstream file1("dataname.csv", ios::out);
	for (int i = 1; i <= 40; i++)
	{
		file1 << "s" << i << endl;
	}
	file1 << "qianpli" << endl;
	file1.close();
}
int makepicture()
{
	CascadeClassifier cascada;
	cascada.load("E:/OPENCV/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml");
	VideoCapture cap(0);
	Mat frame, myFace;
	int pic_num = 1;
	while (1) {
		cap >> frame;
		vector<Rect> faces;//vector容器存检测到的faces
		Mat frame_gray;
		cvtColor(frame, frame_gray, COLOR_BGR2GRAY);//转灰度化,减少运算
		cascada.detectMultiScale(frame_gray, faces, 1.1, 4, CV_HAAR_DO_ROUGH_SEARCH, Size(70, 70), Size(1000, 1000));
		for (int i = 0; i < faces.size(); i++)
		{
			rectangle(frame, faces[i], Scalar(255, 0, 0), 2, 8, 0);
		}
		//当只有一个人脸时,开始拍照
		if (faces.size() == 1)
		{
			Mat faceROI = frame_gray(faces[0]);//在灰度图中将圈出的脸所在区域裁剪出
			//cout << faces[0].x << endl;//测试下face[0].x
			resize(faceROI, myFace, Size(92, 112));//将兴趣域size为92*112
			putText(frame, to_string(pic_num), faces[0].tl(), 3, 1.2, (0, 0, 225), 2, 0);//在 faces[0].tl()的左上角上面写序号
			string filename = "样本/s41/"+to_string(pic_num)+".bmp"; //存放在当前项目文件夹以1-10.jpg 命名,format就是转为字符串
			imwrite(filename, myFace);//存在当前目录下
			imshow(filename, myFace);//显示下size后的脸
			waitKey(500);//等待500us
			destroyWindow(filename);//:销毁指定的窗口
			pic_num++;//序号加1
			if (pic_num == 11)
			{
				return 0;//当序号为11时退出循环
			}
		}
		int c = waitKey(10);
		if ((char)c == 27) { break; } //10us内输入esc则退出循环
		imshow("frame", frame);//显示视频流
		waitKey(100);//等待100us
	}
	return 0;

}

鹏鹏诶 发布了9 篇原创文章 · 获赞 6 · 访问量 448 私信 关注

标签:口罩,img,人工智能,frame,cascade,算法,vector,faces,model
来源: https://blog.csdn.net/qq_43294951/article/details/104541794

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有