表情识别的简单实现(实时,C++,SVM+Dlib)
2016-12-15 13:17
555 查看
之前说要实现一个最简单的表情识别来着,用之前尝试的SVM分类器加上Dlib特征点的归一化之后。每个表情训练了50张图片,测试结果如下:
//这里简单分了三类:高兴,厌恶和平静
厌恶:
平静:
高兴:
动图如下:
--------------------------------------------准备工作-------------------------------------
之前也写过利用Opencv3实现SVM分类器:http://blog.csdn.net/zmdsjtu/article/details/53610244
以及Dlib提取特征点:http://blog.csdn.net/zmdsjtu/article/details/53454071
在这些的基础之上我们来进行表情的分类。
--------------------------------------------下面进入正片-------------------------------------
所有程序CPP+训练模型+训练原始数据打包下载地址:http://download.csdn.net/detail/zmdsjtu/9712182
主要思路:(训练模块+测试模块)
1.训练模块:
①人做出特定表情后提取Dlib特征点并进行归一化。
②每张图片存储136维数据存储进特定编号的TXT方便调用。
③利用SVM分类器进行分类,训练成XML
2.测试模块:
读入训练好的XML,对每帧图片进行分类,显示结果。
先放下测试部分的代码:
和Dlib提取特征点的代码没有很大的区别,只有一行很关键的代码(读取XML)
------------------利用训练好的XML进行表情识别的测试代码-------------------
训练模块:
①训练部分采集用代码:(采集特征点并存入TXT)
②训练(读入TXT并进行训练存入XML):
//有点感冒了,裹着最厚的羽绒服来码点字儿……(有点病恹恹的感觉,皂片凑合着看,hah……)
//祝感冒菌早点回家。
欢迎留言交流哈,祝开发愉快~
//这里简单分了三类:高兴,厌恶和平静
厌恶:
平静:
高兴:
动图如下:
--------------------------------------------准备工作-------------------------------------
之前也写过利用Opencv3实现SVM分类器:http://blog.csdn.net/zmdsjtu/article/details/53610244
以及Dlib提取特征点:http://blog.csdn.net/zmdsjtu/article/details/53454071
在这些的基础之上我们来进行表情的分类。
--------------------------------------------下面进入正片-------------------------------------
所有程序CPP+训练模型+训练原始数据打包下载地址:http://download.csdn.net/detail/zmdsjtu/9712182
主要思路:(训练模块+测试模块)
1.训练模块:
①人做出特定表情后提取Dlib特征点并进行归一化。
②每张图片存储136维数据存储进特定编号的TXT方便调用。
③利用SVM分类器进行分类,训练成XML
2.测试模块:
读入训练好的XML,对每帧图片进行分类,显示结果。
先放下测试部分的代码:
和Dlib提取特征点的代码没有很大的区别,只有一行很关键的代码(读取XML)
cv::Ptr<SVM> svm = StatModel::load<SVM>("SVM_DATA.xml");
------------------利用训练好的XML进行表情识别的测试代码-------------------
#pragma comment(linker, "/subsystem:windows /entry:mainCRTStartup")//去除CMD窗口 #include <dlib/opencv.h> #include <opencv2/opencv.hpp> #include <dlib/image_processing/frontal_face_detector.h> #include <dlib/image_processing/render_face_detections.h> #include <dlib/image_processing.h> #include <dlib/gui_widgets.h> //@author 2016-12-15 朱铭德 zmdsjtu@163.com using namespace dlib; using namespace std; //using namespace cv; using namespace cv::ml; int main() { try { cv::VideoCapture cap(0); if (!cap.isOpened()) { cerr << "Unable to connect to camera" << endl; return 1; } //image_window win; // Load face detection and pose estimation models. frontal_face_detector detector = get_frontal_face_detector(); shape_predictor pose_model; deserialize("shape_predictor_68_face_landmarks.dat") >> pose_model; cv::Ptr<SVM> svm = StatModel::load<SVM>("SVM_DATA.xml"); // Grab and process frames until the main window is closed by the user. while (cv::waitKey(30) != 27) { // Grab a frame cv::Mat temp; cap >> temp; cv_image<bgr_pixel> cimg(temp); // Detect faces std::vector<rectangle> faces = detector(cimg); // Find the pose of each face. std::vector<full_object_detection> shapes; for (unsigned long i = 0; i < faces.size(); ++i) shapes.push_back(pose_model(cimg, faces[i])); if (!shapes.empty()) { float testData[1][136]; float 系数 = -(faces[0].top() - faces[0].bottom()) / 300.0; for (int i = 0; i < 68; i++) { circle(temp, cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), 2, cv::Scalar(255, 0, 0), -1); testData[0][i * 2] = (shapes[0].part(i).x() - faces[0].left()) / 系数; testData[0][i * 2+1] = (shapes[0].part(i).y() - faces[0].top()) / 系数; // shapes[0].part(i).x();//68个 } cv::Mat 结果; cv::Mat query(1, 136, CV_32FC1, testData); if (svm->predict(query) == 250) { cv::putText(temp, "Happy" , cv::Point(20, 60),3, 2, cvScalar(0, 0, 255)); cout << "高兴" << endl; } if (svm->predict(query) == 170) { cv::putText(temp, "Common", cv::Point(20, 60), 3, 2, cvScalar(0, 0, 255)); cout << "平静" << endl; } if (svm->predict(query) == 300) { cv::putText(temp, "Disgust", cv::Point(20, 60), 3, 2, cvScalar(0, 0, 255)); cout << "厌恶" << endl; } // cout<< svm->predict(query)<<endl; // cout << 结果 << endl; } //Display it all on the screen imshow("表情识别 ESC退出", temp); } } catch (serialization_error& e) { cout << "You need dlib's default face landmarking model file to run this example." << endl; cout << "You can get it from the following URL: " << endl; cout << " http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << endl; cout << endl << e.what() << endl; } catch (exception& e) { cout << e.what() << endl; } }
训练模块:
①训练部分采集用代码:(采集特征点并存入TXT)
//@zmdsjtu@163.com //2016-12-15 //#pragma comment(linker, "/subsystem:windows /entry:mainCRTStartup")//去除CMD窗口 #include <dlib/opencv.h> #include <opencv2/opencv.hpp> #include <dlib/image_processing/frontal_face_detector.h> #include <dlib/image_processing/render_face_detections.h> #include <dlib/image_processing.h> #include <dlib/gui_widgets.h> #include<string> using namespace dlib; using namespace std; void 写入TXT(string 名字, string 内容, bool 是否覆盖); int main() { try { cv::VideoCapture cap(0); //image_window win; // Load face detection and pose estimation models. frontal_face_detector detector = get_frontal_face_detector(); shape_predictor pose_model; deserialize("shape_predictor_68_face_landmarks.dat") >> pose_model; std::vector<rectangle> faces2; // Grab and process frames until the main window is closed by the user. int 文件名 = 0; // while (cv::waitKey(30) != 27) // while (cv::waitKey(30) != 27){ // cv::VideoCapture cap("1.avi"); if (!cap.isOpened()) { cerr << "Unable to connect to camera" << endl; return 1; } int 帧数 = cap.get(7); // while (cv::waitKey(30) != 27 && --帧数 != 14) while (cv::waitKey(30) != 27) { // Grab a frame cv::Mat temp; cap >> temp; // temp = cv::imread("1.bmp"); cv_image<bgr_pixel> cimg(temp); // Detect faces std::vector<rectangle> faces = detector(cimg); if (!faces.empty())faces2 = faces; // Find the pose of each face. std::vector<full_object_detection> shapes; if (faces.empty()) { // for (unsigned long i = 0; i < faces2.size(); ++i) // shapes.push_back(pose_model(cimg, faces2[i])); } else { for (unsigned long i = 0; i < faces.size(); ++i) shapes.push_back(pose_model(cimg, faces[i])); } if (!shapes.empty()) { cv::line(temp, cvPoint(faces[0].left(), faces[0].top()), cvPoint( faces[0].right(), faces[0].top()), cv::Scalar(255, 0, 0)); cv::line(temp, cvPoint(faces[0].left(), faces[0].top()), cvPoint(faces[0].left(), faces[0].bottom()), cv::Scalar(255, 0, 0)); 文件名++; float 系数 = -(faces[0].top() - faces[0].bottom()) / 300.0; cout << 系数 << endl; for (int i = 0; i < 68; i++) { circle(temp, cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), 3, cv::Scalar(0, 0, 255), -1); putText(temp, to_string(i), cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), CV_FONT_HERSHEY_PLAIN, 1, cv::Scalar(255, 0, 0), 1, 4); //--------------这部分是想用来采集训练数据的 写入TXT((to_string(文件名)+".txt"), to_string((shapes[0].part(i).x()-faces[0].left())/ 系数), 0); 写入TXT((to_string(文件名) + ".txt"), to_string((shapes[0].part(i).y()- faces[0].top())/ 系数), 0); //---------------------------------------------------------------------------- } // Drawarrow(temp, shapes[0].part(36).x(), shapes[0].part(48).x(), shapes[0].part(30).x(), shapes[0].part(45).x(), shapes[0].part(54).x(), shapes[0].part(36).y(), shapes[0].part(48).y(), shapes[0].part(30).y(), shapes[0].part(45).y(), shapes[0].part(54).y()); } //Display it all on the screen // cv::namedWindow("Dlib特征点", CV_WINDOW_NORMAL); // cv::setWindowProperty("Dlib特征点", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN); imshow("Dlib特征点", temp); // cv::waitKey(-1); } //} cv::destroyAllWindows(); } catch (serialization_error& e) { cout << "You need dlib's default face landmarking model file to run this example." << endl; cout << "You can get it from the following URL: " << endl; cout << " http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << endl; cout << endl << e.what() << endl; } //catch (exception& e) //{ //cout << e.what() << endl; //} } void 写入TXT(string 名字, string 内容, bool 是否覆盖) { ofstream 写入(名字, 是否覆盖 ? ios::trunc : ios::app); if (写入.is_open()) {//如果成功的话 写入 << 内容 << endl; 写入.close(); } }
②训练(读入TXT并进行训练存入XML):
#include<opencv2\opencv.hpp> #include<string> #include<fstream> using namespace std; using namespace cv; using namespace cv::ml; void 读入数据(float 数组[150][136], int 开始, string 目录); int main() { float 一个数组[150][136]; 读入数据(一个数组, 0, "平静"); 读入数据(一个数组, 50, "高兴"); 读入数据(一个数组, 100, "厌恶"); int 人脸标签[150]; for (int i = 0; i < 50; i++) { 人脸标签[i] = 170; 人脸标签[i+50] = 250; 人脸标签[i + 100] = 300; } //训练需要用到的数据 // int 标签[4] = { 1, 2, 3, 4 }; // float 训练数据[4][2] = { { 31, 12 },{ 65, 220 },{ 440, 350 },{ 400, 400 } }; //转为Mat以调用 Mat 训练Mat(150, 136, CV_32FC1, 一个数组);//这边数据类型要处理好,不然粗事儿 Mat 标签label(150, 1, CV_32SC1, 人脸标签); //训练的初始化 Ptr<SVM> svm = SVM::create(); svm->setType(SVM::C_SVC); svm->setKernel(SVM::LINEAR); svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6)); //开始训练 svm->train(训练Mat, ROW_SAMPLE, 标签label); svm->save("SVM_DATA.xml"); } void 读入数据(float 数组[150][136], int 开始, string 目录) { fstream 读文件; // 读文件.imbue(std::locale("chs")); for (int i = 0; i < 50; i++) { 读文件.open(目录 +"\\"+ to_string(i+1) + ".txt"); for (int j = 0; j < 136; j++) { string 读入的东西; 读文件 >> 读入的东西; // cout << 读入的东西; 数组[i+开始][j] = atof(读入的东西.c_str()); } 读文件.close();//关闭是个好习惯 } }
//有点感冒了,裹着最厚的羽绒服来码点字儿……(有点病恹恹的感觉,皂片凑合着看,hah……)
//祝感冒菌早点回家。
欢迎留言交流哈,祝开发愉快~
相关文章推荐
- python+svmlib+opencv实现图片验证码的自动识别
- 使用DELPHI对图片中的文字进行识别的过程(最简单实现)
- 传智播客-Ajax(2)-利用jQuery简单模拟实现股票信息的实时显示
- 简单、直观的实现优于复杂、难懂的实现,最近开发扑克识别过程的总结
- SVM实现多分类的程序基础工作(二)——通过一个简单libsvm例子迈入libsvm学习的大门
- 从零使用OpenCV快速实现简单车牌识别系统
- 用最简单的方法实现QQ魔法表情效果!
- 从零使用OpenCV快速实现简单车牌识别系统
- 简单的图片浏览器和手势识别的功能实现
- 利用ICSharpCode.SharpZipLib.dll实现简单加解压 转
- eclipse + libsvm-3.12 用SVM实现简单线性分类
- -[Up,every,day] 之 №2_.NET Socket 简单的应用,实现服务器与客户端 实时更新对话.!
- 16—【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能
- 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- 委托+线程 winform下超简单实时进度条控件的实现
- 用RMI实现一个简单的实时聊天系统(java语言)
- 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- 去年的齐鲁软件大赛,关于语义识别方面,一种简单的实现想法。
- (转)【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!