人工智能之口罩检测算法
由于疫情的影响,口罩检测已经成为各个程序员竞相开发的一种算法。
百度的人脸检测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容器存检测到的facesMat 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].xresize(faceROI, myFace, Size(92, 112));//将兴趣域size为92*112putText(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);//等待500usdestroyWindow(filename);//:销毁指定的窗口pic_num++;//序号加1if (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 model = createLBPHFaceRecognizer();model->train(img, labels);train函数的两个参数也很简单,训练的图像组vector和对应的标签组vector,这个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);elseputText(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
#include
#include
#include "opencv2\opencv.hpp"#include
#include
#include 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);elseputText(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 model = createLBPHFaceRecognizer();model->train(img, labels);train函数的两个参数也很简单,训练的图像组vector和对应的标签组vector,这个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容器存检测到的facesMat 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].xresize(faceROI, myFace, Size(92, 112));//将兴趣域size为92*112putText(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);//等待500usdestroyWindow(filename);//:销毁指定的窗口pic_num++;//序号加1if (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;}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
