#include "VideoProc.h" #include "TypeDef.h" #include "MatBase64.hpp" #include "json.hpp" #include "VideoSocketService.h" #include "WebSocketService.h" #include "TimeCount.h" #include VideoProc* VideoProc::getInstance() { static VideoProc _instance; return &_instance; } VideoProc::VideoProc():m_bRun(false) { char UserPath[MAX_PATH + 1] = { 0 }; SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, UserPath); m_tmp_path = std::string(UserPath) + std::string("\\AppData\\Local\\Temp\\"); std::thread(&VideoProc::onTimer, this).detach(); } VideoProc::~VideoProc() { } int VideoProc::openCam(int id) { if (m_bRun) {//摄像头已经打开 return err_is_opened; } else { m_capture_rgb.release(); m_capture_rgb.set(cv::CAP_PROP_FOCUS, 0); try { //if (!m_capture_rgb.open(id, cv::CAP_DSHOW)) if(!m_capture_rgb.open(id, cv::CAP_ANY)) //!< Video For Windows (obsolete, removed) {//打开摄像头失败 m_capture_rgb.release(); return err_open_cam; } std::thread(&VideoProc::videoFrameThread, this).detach(); } catch (cv::Exception& e) { MessageBoxA(0, e.what(), "错误", MB_OK); return err_open_cam; } catch (...) { } return err_ok_open_cam; } } int VideoProc::close() { if (m_bRun) { m_bRun = false; } m_take_photo_timer = 0; m_compare_timer = 0; return err_ok_close_cam; } int VideoProc::startCheckFace(std::string base64, int time_out) { cv::Mat idc_img = Base2Mat(base64); nlohmann::json root; root["action_code"] = action_start_check_face; root["action"] = u8"face_image_compare"; if (idc_img.empty()) { root["err_msg"] = u8"输入的人脸比对图片错误"; root["err_code"] = err_face_compare_input; WebSocketService::getInstance()->SendMsg(root.dump()); return err_face_compare_input; } std::vector faceList; FaceDetect(idc_img, faceList); int face_num = faceList.size(); if (face_num > 0) { if (face_num == 1) { int ret = GetFaceFeature(idc_img, faceList[0].landmarks, m_idc_feature); if (ret == 0) { m_compare_timer = time_out; return err_ok; } else { root["err_msg"] = u8"输入的人脸图片提取特征失败"; root["err_code"] = err_face_compare_get_feature; WebSocketService::getInstance()->SendMsg(root.dump()); return err_face_compare_get_feature; } } else { root["err_msg"] = u8"输入的人脸比对图片存在多张人脸"; root["err_code"] = err_face_compare_multiple_face; WebSocketService::getInstance()->SendMsg(root.dump()); return err_face_compare_multiple_face; } } else { root["err_msg"] = u8"输入的人脸比对图片未检测到人脸"; root["err_code"] = err_face_compare_no_face; WebSocketService::getInstance()->SendMsg(root.dump()); return err_face_compare_no_face; } } void VideoProc::stopCheckFace() { m_compare_timer = 0; } void VideoProc::StartAutoTakePhoto(int timeOut) { if (!m_bRun) { nlohmann::json root; root["action"] = u8"start_auto_take_photo"; root["action_code"] = action_start_auto_take_photo; root["err_code"] = err_is_closed; root["err_msg"] = u8"摄像头未开启"; WebSocketService::getInstance()->SendMsg(root.dump()); return; } m_take_photo_timer = timeOut; } void VideoProc::StopAutoTakePhoto() { m_take_photo_timer = 0; } void VideoProc::TakePhoto() { m_bTackPtoto = true; } void VideoProc::setFaceThreshold(float threshold) { } void VideoProc::onTimer() { while (true) { if (m_compare_timer > 0) { m_compare_timer--; //std::wstring msg = L"{\"event_id\":5,\"time_out\":" + std::to_wstring(m_compare_timer) + std::wstring(L",\"message\":\"人脸比对倒计时\"}"); nlohmann::json root; root["action_code"] = action_time_auto_check_face; root["action"] = u8"人脸核验倒计时"; root["time_out"] = (int)m_compare_timer; WebSocketService::getInstance()->SendMsg(root.dump()); } else { //std::wstring msg = L"{\"event_id\":4,\"message\":\"停止人脸比对\"}"; if (m_compare_timer == 0) { m_compare_timer = -1; nlohmann::json root; root["action_code"] = action_stop_check_face; root["action"] = u8"停止人脸核验"; WebSocketService::getInstance()->SendMsg(root.dump()); } } //////////////////////////////////////// if (m_take_photo_timer > 0) { nlohmann::json root; root["action"] = u8"自动拍照倒计时"; root["action_code"] = action_time_auto_take_photo; root["time_out"] = (int)m_take_photo_timer; WebSocketService::getInstance()->SendMsg(root.dump()); m_take_photo_timer--; } else { if (m_take_photo_timer == 0) { m_take_photo_timer = -1; nlohmann::json root; root["action"] = u8"停止自动拍照"; root["action_code"] = action_stop_auto_take_photo; WebSocketService::getInstance()->SendMsg(root.dump()); } } std::this_thread::sleep_for(std::chrono::seconds(1)); } } void VideoProc::videoFrameThread() { bool bLiveness = true; if (!m_capture_rgb.isOpened()) {//RGB摄像头打开失败 nlohmann::json root; root["err_code"] = err_open_cam; root["err_msg"] = u8"打开RGB摄像头失败"; WebSocketService::getInstance()->SendMsg(root.dump()); return; } cv::Scalar color(0, 0, 255); m_bRun = true; while (m_bRun) { cv::Mat frame_rgb; m_capture_rgb >> frame_rgb; if (frame_rgb.empty()) { if (!m_capture_rgb.isOpened()) { nlohmann::json root; root["err_code"] = err_cam_closed; root["err_msg"] = u8"摄像头异常停止工作"; WebSocketService::getInstance()->SendMsg(root.dump()); break; } else { continue; } } cv::flip(frame_rgb, frame_rgb, 1); //拍照 if (m_bTackPtoto) { std::string photo_path = m_tmp_path + std::string("photo.jpg"); cv::imwrite(photo_path, frame_rgb); //m_tackPhotoData = Mat2Base64(frame_rgb, "jpg"); m_bTackPtoto = false; nlohmann::json root; root["action_code"] = action_take_photo; root["action"] = u8"拍照"; root["err_code"] = err_ok_take_photo; root["err_msg"] = u8"拍照成功"; root["photo"] = photo_path; WebSocketService::getInstance()->SendMsg(root.dump()); } if (m_take_photo_timer > 0 || m_compare_timer > 0 /*|| bLiveness*/)//需要进行活体检测 { std::vector faceList; FaceDetect(frame_rgb, faceList); if (faceList.size() > 0) { float liveness_score = 0.f; FaceInfo& _face_box = faceList[0]; FaceLivenesRgb(frame_rgb, _face_box.landmarks, liveness_score); if (liveness_score < 0.5) {//非活体 color = cv::Scalar(0, 0, 255); cv::Rect _rt(cv::Point(_face_box.x1, _face_box.y1), cv::Point(_face_box.x2, _face_box.y2)); rectangleFace(frame_rgb, _rt, color); //cv::putText(frame_rgb, std::string("non-liveness: ") + std::to_string(liveness_score), cv::Point(5, 50), 1, 2, color, 2); static long st1 = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); long st2 = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); if (st2 - st1 > 1) { st1 = st2; nlohmann::json root; root["action_code"] = action_event; root["action"] = u8"事件通知"; root["err_code"] = err_liveness_fail; root["err_msg"] = u8"活体检测失败"; WebSocketService::getInstance()->SendMsg(root.dump()); } } else { color = cv::Scalar(0, 255, 0); personCardCheck(frame_rgb); //cv::putText(frame_rgb, std::string("liveness: ") + std::to_string(liveness_score), cv::Point(5, 50), 1, 2, color, 2); //std::wstring msg = std::wstring(L"{\"code\":3,\"ret\":1,\"score\":") + std::to_wstring(liveness_score) + std::wstring(L",\"message\":\"活体检测成功\"}"); //PostMessageW(WM_MSG_JS, (WPARAM)msg.c_str(), msg.length()); } } else { if (m_compare_timer > 0 || m_take_photo_timer > 0) { nlohmann::json root; root["action_code"] = action_event; root["action"] = u8"事件通知"; root["err_code"] = err_no_face; root["err_msg"] = u8"未检测到人脸"; WebSocketService::getInstance()->SendMsg(root.dump()); } } } else {//不做活体检测,检测人脸和身份证照片进行比对 personCardCheck(frame_rgb); } if (m_compare_timer > 0) { //绘制人脸比对倒计时 cv::putText(frame_rgb, std::to_string(m_compare_timer) + std::string("S"), cv::Point(frame_rgb.cols - 60, 30), 1, 2, cv::Scalar(0, 0, 255), 2); } else if (m_take_photo_timer > 0) { //绘制人脸比对倒计时 cv::putText(frame_rgb, std::to_string(m_take_photo_timer) + std::string("S"), cv::Point(frame_rgb.cols - 60, 30), 1, 2, cv::Scalar(0, 0, 255), 2); } else { } //cv::imshow("frame_rgb",frame_rgb); VideoSocketService::getInstance()->PushImg(Mat2Base64(frame_rgb, "jpg")); cv::waitKey(10); } m_compare_timer = 0; m_capture_rgb.release(); //m_capture_ir.release(); m_cv.notify_one(); } int VideoProc::personCardCheck(cv::Mat& rgb_img) { cv::Mat tmp_rgb_img = rgb_img.clone(); float qua = 0.f; std::vector faceList; FaceDetect(tmp_rgb_img, faceList); if (faceList.size() > 0) { cv::Rect _rt(cv::Point(faceList[0].x1, faceList[0].y1), cv::Point(faceList[0].x2, faceList[0].y2)); GetFaceQuality(tmp_rgb_img, faceList[0].x1, faceList[0].y1, faceList[0].x2, faceList[0].y2, qua); if (qua > 85) { if (m_take_photo_timer > 0)//自动拍照 { if (qua > 90) { //std::string photoData = Mat2Base64(tmp_rgb_img, "jpg"); //std::string faceImg = getFaceImg(tmp_rgb_img, faceList[0]); std::string photo_path = m_tmp_path + std::string("photo.jpg"); std::string face_img_path = m_tmp_path + std::string("faceImg.jpg"); cv::imwrite(photo_path, tmp_rgb_img); cv::imwrite(face_img_path, getFaceMat(tmp_rgb_img, faceList[0])); m_take_photo_timer = 0; nlohmann::json root; root["action_code"] = action_start_auto_take_photo; root["action"] = u8"自动拍照"; root["err_code"] = err_ok_auto_take_photo; root["err_msg"] = u8"自动拍照成功"; root["photo"] = photo_path; root["face_img"] = face_img_path; WebSocketService::getInstance()->SendMsg(root.dump()); } else { static long st1 = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); long st2 = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); if (st2 - st1 > 1) { st1 = st2; nlohmann::json root; root["action_code"] = action_event; root["action"] = u8"事件通知"; root["err_code"] = err_keep_face; root["err_msg"] = u8"人脸质量太低,请正对着摄像头"; WebSocketService::getInstance()->SendMsg(root.dump()); } } } if (m_compare_timer > 0) { float score = 0.f; float feature[512] = { 0 }; int ret = GetFaceFeature(tmp_rgb_img, faceList[0].landmarks, feature); if (ret == 0) { FaceFeatureCompare(feature, m_idc_feature, score); if (score >= m_threshold) { m_compare_timer = 0; std::string photo_path = m_tmp_path + std::string("photo.jpg"); std::string face_img_path = m_tmp_path + std::string("faceImg.jpg"); cv::imwrite(photo_path, tmp_rgb_img); cv::imwrite(face_img_path, getFaceMat(tmp_rgb_img, faceList[0])); nlohmann::json root; root["action_code"] = action_start_check_face; root["action"] = u8"人脸核验"; root["err_code"] = err_ok_face_compare; root["err_msg"] = u8"人脸比对成功"; root["score"] = score; root["photo"] = photo_path; root["face_image"] = face_img_path; WebSocketService::getInstance()->SendMsg(root.dump()); return err_ok_face_compare; } else { nlohmann::json root; root["action_code"] = action_event; root["action"] = u8"事件通知"; root["err_code"] = err_face_compare_fail; root["err_msg"] = u8"人脸比对失败"; root["score"] = score; WebSocketService::getInstance()->SendMsg(root.dump()); return err_face_compare_fail; } } } rectangleFace(rgb_img, _rt, cv::Scalar(0, 255, 0)); } else { if (m_compare_timer > 0 || m_take_photo_timer > 0) { static long st1 = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); long st2 = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); if (st2 - st1 > 1) { st1 = st2; nlohmann::json root; root["action_code"] = action_event; root["action"] = u8"事件通知"; root["err_code"] = err_keep_face; root["err_msg"] = u8"人脸质量太低,请正对着摄像头"; WebSocketService::getInstance()->SendMsg(root.dump()); } } rectangleFace(rgb_img, _rt, cv::Scalar(255, 0, 0)); } //cv::putText(rgb_img, std::string("score: ") + std::to_string(score), cv::Point(5, 100), 1, 2, cv::Scalar(0, 0, 255), 2); //cv::putText(rgb_img, std::string("qua: ") + std::to_string(qua), cv::Point(5, 130), 1, 2, cv::Scalar(0, 255, 0), 2); } else { if (m_compare_timer > 0 || m_take_photo_timer > 0) { nlohmann::json root; root["action_code"] = action_event; root["action"] = u8"事件通知"; root["err_code"] = err_no_face; root["err_msg"] = u8"未检测到人脸"; WebSocketService::getInstance()->SendMsg(root.dump()); } } return 0; } int VideoProc::FaceCompare(std::string img1, std::string img2) { cv::Mat mat1 = Base2Mat(img1); cv::Mat mat2 = Base2Mat(img2); if (mat1.empty() || mat2.empty()) { nlohmann::json root; root["action_code"] = action_face_compare; root["action"] = u8"face_image_compare"; root["err_code"] = err_face_compare_input; root["err_msg"] = u8"输入的人脸图片错误"; WebSocketService::getInstance()->SendMsg(root.dump()); return err_face_compare_input; } std::vector faceList1, faceList2; FaceDetect(mat1, faceList1); FaceDetect(mat2, faceList2); if (faceList1.size() > 1 || faceList2.size() > 1) { nlohmann::json root; root["action_code"] = action_face_compare; root["action"] = u8"face_image_compare"; root["err_code"] = err_face_compare_multiple_face; root["err_msg"] = u8"输入的比对图片存在多张人脸"; WebSocketService::getInstance()->SendMsg(root.dump()); return err_face_compare_multiple_face; } if (faceList1.size() < 0 || faceList2.size() < 0) { nlohmann::json root; root["action_code"] = action_face_compare; root["action"] = u8"face_image_compare"; root["err_code"] = err_face_compare_no_face; root["err_msg"] = u8"输入的比对图片未检测到人脸"; WebSocketService::getInstance()->SendMsg(root.dump()); return err_face_compare_no_face; } float f1[512] = { 0 }; float f2[512] = { 0 }; GetFaceFeature(mat1, faceList1[0].landmarks, f1); GetFaceFeature(mat2, faceList2[0].landmarks, f2); float score = 0.f; FaceFeatureCompare(f1, f2, score); nlohmann::json root; root["action_code"] = action_face_compare; root["action"] = u8"人脸图片比对"; root["err_code"] = err_ok_face_compare; root["err_msg"] = u8"人脸图片比对完成"; root["score"] = score; WebSocketService::getInstance()->SendMsg(root.dump()); return err_ok_face_compare; } std::string VideoProc::getFaceImg(cv::Mat& img, FaceInfo& face_info) { int ew = face_info.GetWidth() * 1.0 / 1.5; int eh = face_info.GetHeight() * 1.0 / 2.8; face_info.x1 -= ew; face_info.y1 -= eh; face_info.x2 += ew; face_info.y2 += eh; if (face_info.x1 < 0) { face_info.x1 = 0; } if (face_info.y1 < 0) { face_info.y1 = 0; } if (face_info.x2 >= img.cols) { face_info.x2 = img.cols - 5; } if (face_info.y2 >= img.rows) { face_info.y2 = img.rows - 5; } cv::Rect face_rect; face_rect.x = face_info.x1; face_rect.y = face_info.y1; face_rect.width = face_info.GetWidth(); face_rect.height = face_info.GetHeight(); std::string base64; try { cv::Mat faceImg = img(face_rect); base64 = Mat2Base64(faceImg, "jpg"); } catch (const cv::Exception& e) { } catch (...) { } return base64; } cv::Mat VideoProc::getFaceMat(cv::Mat& img, FaceInfo& face_info) { int ew = face_info.GetWidth() * 1.0 / 1.5; int eh = face_info.GetHeight() * 1.0 / 2.8; face_info.x1 -= ew; face_info.y1 -= eh; face_info.x2 += ew; face_info.y2 += eh; if (face_info.x1 < 0) { face_info.x1 = 0; } if (face_info.y1 < 0) { face_info.y1 = 0; } if (face_info.x2 >= img.cols) { face_info.x2 = img.cols - 5; } if (face_info.y2 >= img.rows) { face_info.y2 = img.rows - 5; } cv::Rect face_rect; face_rect.x = face_info.x1; face_rect.y = face_info.y1; face_rect.width = face_info.GetWidth(); face_rect.height = face_info.GetHeight(); cv::Mat faceImg; try { faceImg = img(face_rect); } catch (const cv::Exception& e) { } catch (...) { } return faceImg; } void VideoProc::rectangleFace(cv::Mat& img, cv::Rect face_rect, cv::Scalar color) { //cv::rectangle(img, face_rect, cv::Scalar(0,100,100)); int line_len = 15; int thickness = 2; cv::line(img, cv::Point(face_rect.x, face_rect.y), cv::Point(face_rect.x + line_len, face_rect.y), color, thickness); cv::line(img, cv::Point(face_rect.x, face_rect.y), cv::Point(face_rect.x, face_rect.y + line_len), color, thickness); cv::line(img, cv::Point(face_rect.x + face_rect.width - line_len, face_rect.y), cv::Point(face_rect.x + face_rect.width, face_rect.y), color, thickness); cv::line(img, cv::Point(face_rect.x + face_rect.width, face_rect.y), cv::Point(face_rect.x + face_rect.width, face_rect.y + line_len), color, thickness); cv::line(img, cv::Point(face_rect.x, face_rect.y + face_rect.height - line_len), cv::Point(face_rect.x, face_rect.y + face_rect.height), color, thickness); cv::line(img, cv::Point(face_rect.x, face_rect.y + face_rect.height), cv::Point(face_rect.x + line_len, face_rect.y + face_rect.height), color, thickness); cv::line(img, cv::Point(face_rect.x + face_rect.width, face_rect.y + face_rect.height - line_len), cv::Point(face_rect.x + face_rect.width, face_rect.y + face_rect.height), color, thickness); cv::line(img, cv::Point(face_rect.x + face_rect.width - line_len, face_rect.y + face_rect.height), cv::Point(face_rect.x + face_rect.width, face_rect.y + face_rect.height), color, thickness); }