the first submit
0 parents
Showing
9 changed files
with
706 additions
and
0 deletions
README.md
0 → 100644
| 1 | |||
| 2 | opencv4.5.5 | ||
| 3 | |||
| 4 | 模型初始化 | ||
| 5 | |||
| 6 | FaceRecognize face_rec=FaceRecognize(det_model_path,landm_model_path,rec_model_path) | ||
| 7 | |||
| 8 | det_model_path:人脸检测模型retinaface的onnx模型路径 | ||
| 9 | landm_model_path:106人脸关键点模型的onnx模型路径 | ||
| 10 | rec_model_path:人脸识别模型的onnx模型路径 | ||
| 11 | |||
| 12 | 重要参数(.h文件) | ||
| 13 | |||
| 14 | bool use_gpu=true; //是否使用gpu | ||
| 15 | float confidence_threshold = 0.5; //人脸检测阈值 | ||
| 16 | float nms_threshold = 0.4; //nms阈值 | ||
| 17 | double face_recongnize_thr = 0.2; //人脸相似度阈值 | ||
| 18 | |||
| 19 | 接口(返回结果 bool:true/false) | ||
| 20 | |||
| 21 | bool face_recognize(string image1_path,string image2_path);参数为两张图像地址,其中iamge1_path为face_id图像输入 | ||
| 22 | bool face_recognize_image(Mat image1,Mat image2);参数为两张opencv读取的图像矩阵,其中iamge1为face_id图像输入 | ||
| 23 | |||
| 24 | 编译 | ||
| 25 | |||
| 26 | g++ main.cpp -L . -lfacerecognize -o main | ||
| 27 | 如果报错无法找到改用:g++ main.cpp -L . -lfacerecognize -o main pkg-config --libs --cflags opencv4 | ||
| 28 | ./main |
det_face_retina_torch_1.4_v0.0.2.onnx
0 → 100644
No preview for this file type
det_landmarks_106_v0.0.1.onnx
0 → 100644
No preview for this file type
facerecognize.cpp
0 → 100644
| 1 | #include "facerecognize.h" | ||
| 2 | #include<iostream> | ||
| 3 | //人脸检测部分 | ||
| 4 | // 生成anchors | ||
| 5 | vector<vector<float>> FaceRecognize::priorBox(vector<float> image_size){ | ||
| 6 | vector<int> tmp1={16,32}; | ||
| 7 | vector<int> tmp2={64,128}; | ||
| 8 | vector<int> tmp3={256,512}; | ||
| 9 | vector<vector<int>> min_sizes_; | ||
| 10 | min_sizes_.push_back(tmp1); | ||
| 11 | min_sizes_.push_back(tmp2); | ||
| 12 | min_sizes_.push_back(tmp3); | ||
| 13 | vector<int> steps={8,16,32}; | ||
| 14 | vector<vector<int>> feature_maps; | ||
| 15 | vector<vector<float>> anchors; | ||
| 16 | for(int &step:steps){ | ||
| 17 | vector<int> tmp(2,0); | ||
| 18 | tmp[0]=ceil(image_size[0]/step); | ||
| 19 | tmp[1]=ceil(image_size[1]/step); | ||
| 20 | feature_maps.push_back(tmp); | ||
| 21 | } | ||
| 22 | for(int k=0;k<feature_maps.size();k++){ | ||
| 23 | vector<int> min_sizes=min_sizes_[k]; | ||
| 24 | |||
| 25 | for(int i=0;i<feature_maps[k][0];i++){ | ||
| 26 | for(int j=0;j<feature_maps[k][1];j++){ | ||
| 27 | for(int &min_size:min_sizes){ | ||
| 28 | float s_kx=float(min_size)/float(image_size[1]); | ||
| 29 | float s_ky=float(min_size)/float(image_size[0]); | ||
| 30 | float dense_cx=float((float(j)+float(0.5))*steps[k])/float(image_size[1]); | ||
| 31 | float dense_cy=float((float(i)+float(0.5))*steps[k])/float(image_size[1]); | ||
| 32 | vector<float> tmp_anchor={dense_cx,dense_cy,s_kx,s_ky}; | ||
| 33 | anchors.push_back(tmp_anchor); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | return anchors; | ||
| 39 | } | ||
| 40 | |||
| 41 | // 解析bounding box 包含置信度 | ||
| 42 | vector<Bbox> FaceRecognize::decode(vector<vector<float>> loc,vector<vector<float>> score,vector<vector<float>>pre,vector<vector<float>> priors,vector<float> variances){ | ||
| 43 | vector<Bbox> boxes; | ||
| 44 | for(int i=0;i<priors.size();++i){ | ||
| 45 | float b1=priors[i][0]+loc[i][0]*variances[0]*priors[i][2]; | ||
| 46 | float b2=priors[i][1]+loc[i][1]*variances[0]*priors[i][3]; | ||
| 47 | float b3=priors[i][2]*exp(loc[i][2]*variances[1]); | ||
| 48 | float b4=priors[i][3]*exp(loc[i][3]*variances[1]); | ||
| 49 | b1=b1-b3/float(2); | ||
| 50 | b2=b2-b4/float(2); | ||
| 51 | b3=b3+b1; | ||
| 52 | b4=b4+b2; | ||
| 53 | float l1=priors[i][0]+pre[i][0]*variances[0]*priors[i][2]; | ||
| 54 | float l2=priors[i][1]+pre[i][1]*variances[0]*priors[i][3]; | ||
| 55 | float l3=priors[i][0]+pre[i][2]*variances[0]*priors[i][2]; | ||
| 56 | float l4=priors[i][1]+pre[i][3]*variances[0]*priors[i][3]; | ||
| 57 | float l5=priors[i][0]+pre[i][4]*variances[0]*priors[i][2]; | ||
| 58 | float l6=priors[i][1]+pre[i][5]*variances[0]*priors[i][3]; | ||
| 59 | float l7=priors[i][0]+pre[i][6]*variances[0]*priors[i][2]; | ||
| 60 | float l8=priors[i][1]+pre[i][7]*variances[0]*priors[i][3]; | ||
| 61 | float l9=priors[i][0]+pre[i][8]*variances[0]*priors[i][2]; | ||
| 62 | float l10=priors[i][1]+pre[i][9]*variances[0]*priors[i][3]; | ||
| 63 | Bbox tmp_box={.xmin=b1*input_size[0]/resize_scale,.ymin=b2*input_size[1]/resize_scale,.xmax=b3*input_size[0]/resize_scale,.ymax=b4*input_size[1]/resize_scale, | ||
| 64 | .score=float(score[i][0]),.x1=(l1*input_size[0])/resize_scale,.y1=l2*input_size[1]/resize_scale,.x2=l3*input_size[0]/resize_scale,.y2=l4*input_size[1]/resize_scale, | ||
| 65 | .x3=l5*input_size[0]/resize_scale,.y3=l6*input_size[1]/resize_scale,.x4=l7*input_size[0]/resize_scale,.y4=l8*input_size[1]/resize_scale,.x5=l9*input_size[0]/resize_scale,.y5=l10*input_size[1]/resize_scale}; | ||
| 66 | boxes.push_back(tmp_box); | ||
| 67 | } | ||
| 68 | return boxes; | ||
| 69 | } | ||
| 70 | |||
| 71 | //NMS | ||
| 72 | void FaceRecognize::nms_cpu(std::vector<Bbox> &bboxes, float threshold){ | ||
| 73 | if (bboxes.empty()){ | ||
| 74 | return ; | ||
| 75 | } | ||
| 76 | // 1.之前需要按照score排序 | ||
| 77 | std::sort(bboxes.begin(), bboxes.end(), [&](Bbox b1, Bbox b2){return b1.score>b2.score;}); | ||
| 78 | // 2.先求出所有bbox自己的大小 | ||
| 79 | std::vector<float> area(bboxes.size()); | ||
| 80 | for (int i=0; i<bboxes.size(); ++i){ | ||
| 81 | area[i] = (bboxes[i].xmax - bboxes[i].xmin + 1) * (bboxes[i].ymax - bboxes[i].ymin + 1); | ||
| 82 | } | ||
| 83 | // 3.循环 | ||
| 84 | for (int i=0; i<bboxes.size(); ++i){ | ||
| 85 | for (int j=i+1; j<bboxes.size(); ){ | ||
| 86 | float left = std::max(bboxes[i].xmin, bboxes[j].xmin); | ||
| 87 | float right = std::min(bboxes[i].xmax, bboxes[j].xmax); | ||
| 88 | float top = std::max(bboxes[i].ymin, bboxes[j].ymin); | ||
| 89 | float bottom = std::min(bboxes[i].ymax, bboxes[j].ymax); | ||
| 90 | float width = std::max(right - left + 1, 0.f); | ||
| 91 | float height = std::max(bottom - top + 1, 0.f); | ||
| 92 | float u_area = height * width; | ||
| 93 | float iou = (u_area) / (area[i] + area[j] - u_area); | ||
| 94 | if (iou>=threshold){ | ||
| 95 | bboxes.erase(bboxes.begin()+j); | ||
| 96 | area.erase(area.begin()+j); | ||
| 97 | }else{ | ||
| 98 | ++j; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | // Mat转vector | ||
| 104 | vector<vector<float>> FaceRecognize::mat2vector(Mat mat){ | ||
| 105 | vector<vector<float>> vec; | ||
| 106 | for(int i=0;i<mat.rows;++i){ | ||
| 107 | vector<float> m; | ||
| 108 | for(int j=0;j<mat.cols;++j){ | ||
| 109 | m.push_back(mat.at<float>(i,j)); | ||
| 110 | } | ||
| 111 | vec.push_back(m); | ||
| 112 | } | ||
| 113 | return vec; | ||
| 114 | } | ||
| 115 | // 根据阈值筛选 | ||
| 116 | vector<Bbox> FaceRecognize::select_score(vector<Bbox> bboxes,float threshold,float w_r,float h_r){ | ||
| 117 | vector<Bbox> results; | ||
| 118 | for(Bbox &box:bboxes){ | ||
| 119 | if (float(box.score)>=threshold){ | ||
| 120 | box.xmin=box.xmin/w_r; | ||
| 121 | box.ymin=box.ymin/h_r; | ||
| 122 | box.xmax=box.xmax/w_r; | ||
| 123 | box.ymax=box.ymax/h_r; | ||
| 124 | box.x1=box.x1/w_r; | ||
| 125 | box.y1=box.y1/h_r; | ||
| 126 | box.x2=box.x2/w_r; | ||
| 127 | box.y2=box.y2/h_r; | ||
| 128 | box.x3=box.x3/w_r; | ||
| 129 | box.y3=box.y3/h_r; | ||
| 130 | box.x4=box.x4/w_r; | ||
| 131 | box.y4=box.y4/h_r; | ||
| 132 | box.x5=box.x5/w_r; | ||
| 133 | box.y5=box.y5/h_r; | ||
| 134 | results.push_back(box); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | return results; | ||
| 138 | } | ||
| 139 | |||
| 140 | // 数据后处理 | ||
| 141 | vector<Bbox> FaceRecognize::bbox_process(vector<Bbox> bboxes,float frame_w,float frame_h){ | ||
| 142 | vector<Bbox> result_bboxes; | ||
| 143 | for(Bbox &bbox:bboxes){ | ||
| 144 | Bbox new_bbox; | ||
| 145 | float face_w=bbox.xmax-bbox.xmin; | ||
| 146 | float face_h=bbox.ymax-bbox.ymin; | ||
| 147 | new_bbox.xmin=bbox.xmin-face_w*0.15; | ||
| 148 | new_bbox.xmax=bbox.xmax+face_w*0.15; | ||
| 149 | new_bbox.ymin=bbox.ymin; | ||
| 150 | new_bbox.ymax=bbox.ymax+face_h*0.15; | ||
| 151 | new_bbox.xmin=new_bbox.xmin>0?new_bbox.xmin:0; | ||
| 152 | new_bbox.ymin=new_bbox.ymin>0?new_bbox.ymin:0; | ||
| 153 | new_bbox.xmax=new_bbox.xmax>frame_w?frame_w:new_bbox.xmax; | ||
| 154 | new_bbox.ymax=new_bbox.ymax>frame_h?frame_h:new_bbox.ymax; | ||
| 155 | new_bbox.score=bbox.score; | ||
| 156 | new_bbox.x1=bbox.x1>0?bbox.x1:0; | ||
| 157 | new_bbox.y1=bbox.y1>0?bbox.y1:0; | ||
| 158 | new_bbox.x2=bbox.x2>0?bbox.x2:0; | ||
| 159 | new_bbox.y2=bbox.y2>0?bbox.y2:0; | ||
| 160 | new_bbox.x3=bbox.x3>0?bbox.x3:0; | ||
| 161 | new_bbox.y3=bbox.y3>0?bbox.y3:0; | ||
| 162 | new_bbox.x4=bbox.x4>0?bbox.x4:0; | ||
| 163 | new_bbox.y4=bbox.y4>0?bbox.y4:0; | ||
| 164 | new_bbox.x5=bbox.x5>0?bbox.x5:0; | ||
| 165 | new_bbox.y5=bbox.y5>0?bbox.y5:0; | ||
| 166 | result_bboxes.push_back(new_bbox); | ||
| 167 | |||
| 168 | } | ||
| 169 | return result_bboxes; | ||
| 170 | } | ||
| 171 | // 推理 | ||
| 172 | vector<Bbox> FaceRecognize::detect(string image_path){ | ||
| 173 | cv::Mat image = cv::imread(image_path); // 读取图片 | ||
| 174 | float w_r=float(640)/float(image.cols); | ||
| 175 | float h_r=float(640)/float(image.rows); | ||
| 176 | cv::Mat blob = cv::dnn::blobFromImage(image,resize_scale,Size(input_size[0],input_size[1]),Scalar(mean_data[0],mean_data[1],mean_data[2])); // 由图片加载数据 这里还可以进行缩放、归一化等预处理 | ||
| 177 | det_net.setInput(blob); // 设置模型输入 | ||
| 178 | std::vector<cv::Mat> det_netOutputImg; | ||
| 179 | det_net.forward(det_netOutputImg,det_net.getUnconnectedOutLayersNames()); // 推理出结果 | ||
| 180 | cv::Mat scores_ = det_netOutputImg[2].reshape(1,16800); | ||
| 181 | cv::Mat boxes_ = det_netOutputImg[0].reshape(1,16800); | ||
| 182 | cv::Mat landms_ = det_netOutputImg[1].reshape(1,16800); | ||
| 183 | std::vector<vector<float>> scores,boxes,landms; | ||
| 184 | |||
| 185 | scores=mat2vector(scores_); | ||
| 186 | boxes=mat2vector(boxes_); | ||
| 187 | landms=mat2vector(landms_); | ||
| 188 | |||
| 189 | |||
| 190 | vector<vector<float>> anchors=priorBox(input_size); | ||
| 191 | vector<Bbox> result_boxes=decode(boxes,scores,landms,anchors,variances); | ||
| 192 | vector<Bbox> results=select_score(result_boxes,confidence_threshold,w_r,h_r); | ||
| 193 | |||
| 194 | // vector<Bbox> result_bboxes=vec2Bbox(boxes,w_r,h_r); | ||
| 195 | |||
| 196 | nms_cpu(results,nms_threshold); | ||
| 197 | if(is_bbox_process){ | ||
| 198 | vector<Bbox> res_bboxes=bbox_process(results,input_size[0],input_size[1]); | ||
| 199 | return res_bboxes; | ||
| 200 | |||
| 201 | }else{ | ||
| 202 | return results; | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | vector<Bbox> FaceRecognize::detect_image(Mat image){ | ||
| 207 | float w_r=float(640)/float(image.cols); | ||
| 208 | float h_r=float(640)/float(image.rows); | ||
| 209 | cv::Mat blob = cv::dnn::blobFromImage(image,resize_scale,Size(input_size[0],input_size[1]),Scalar(mean_data[0],mean_data[1],mean_data[2])); // 由图片加载数据 这里还可以进行缩放、归一化等预处理 | ||
| 210 | det_net.setInput(blob); // 设置模型输入 | ||
| 211 | std::vector<cv::Mat> det_netOutputImg; | ||
| 212 | det_net.forward(det_netOutputImg,det_net.getUnconnectedOutLayersNames()); // 推理出结果 | ||
| 213 | cv::Mat scores_ = det_netOutputImg[2].reshape(1,16800); | ||
| 214 | cv::Mat boxes_ = det_netOutputImg[0].reshape(1,16800); | ||
| 215 | cv::Mat landms_ = det_netOutputImg[1].reshape(1,16800); | ||
| 216 | std::vector<vector<float>> scores,boxes,landms; | ||
| 217 | |||
| 218 | scores=mat2vector(scores_); | ||
| 219 | boxes=mat2vector(boxes_); | ||
| 220 | landms=mat2vector(landms_); | ||
| 221 | |||
| 222 | |||
| 223 | vector<vector<float>> anchors=priorBox(input_size); | ||
| 224 | vector<Bbox> result_boxes=decode(boxes,scores,landms,anchors,variances); | ||
| 225 | vector<Bbox> results=select_score(result_boxes,confidence_threshold,w_r,h_r); | ||
| 226 | |||
| 227 | // vector<Bbox> result_bboxes=vec2Bbox(boxes,w_r,h_r); | ||
| 228 | |||
| 229 | nms_cpu(results,nms_threshold); | ||
| 230 | if(is_bbox_process){ | ||
| 231 | vector<Bbox> res_bboxes=bbox_process(results,image.cols,image.rows); | ||
| 232 | return res_bboxes; | ||
| 233 | |||
| 234 | }else{ | ||
| 235 | return results; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | |||
| 240 | //人脸关键点部分 | ||
| 241 | vector<vector<float>> FaceRecognize::detect_landmarks(string image_path){ | ||
| 242 | cv::Mat image=cv::imread(image_path); | ||
| 243 | float w_r=image.cols/112; | ||
| 244 | float h_r=image.rows/112; | ||
| 245 | |||
| 246 | cv::Mat blob = cv::dnn::blobFromImage(image,1.0,Size(112,112)); // 由图片加载数据 这里还可以进行缩放、归一化等预处理 | ||
| 247 | landm_net.setInput(blob); // 设置模型输入 | ||
| 248 | std::vector<cv::Mat> landm_netOutputImg; | ||
| 249 | landm_net.forward(landm_netOutputImg,landm_net.getUnconnectedOutLayersNames()); // 推理出结果 | ||
| 250 | cv::Mat predict_landmarks = landm_netOutputImg[0].reshape(1,106); | ||
| 251 | vector<vector<float>> result_landmarks; | ||
| 252 | for(int i=0;i<predict_landmarks.rows;++i){ | ||
| 253 | vector<float> tmp_landm={predict_landmarks.at<float>(i,0)*w_r,predict_landmarks.at<float>(i,1)*h_r}; | ||
| 254 | result_landmarks.push_back(tmp_landm); | ||
| 255 | } | ||
| 256 | return result_landmarks; | ||
| 257 | } | ||
| 258 | |||
| 259 | vector<vector<float>> FaceRecognize::detect_image_landmarks(cv::Mat image){ | ||
| 260 | float w_r=image.cols/float(112); | ||
| 261 | float h_r=image.rows/float(112); | ||
| 262 | cv::Mat blob = cv::dnn::blobFromImage(image,1.0,Size(112,112)); // 由图片加载数据 这里还可以进行缩放、归一化等预处理 | ||
| 263 | landm_net.setInput(blob); // 设置模型输入 | ||
| 264 | std::vector<cv::Mat> landm_netOutputImg; | ||
| 265 | landm_net.forward(landm_netOutputImg,landm_net.getUnconnectedOutLayersNames()); // 推理出结果 | ||
| 266 | cv::Mat predict_landmarks = landm_netOutputImg[0].reshape(1,106); | ||
| 267 | vector<vector<float>> result_landmarks; | ||
| 268 | for(int i=0;i<predict_landmarks.rows;++i){ | ||
| 269 | vector<float> tmp_landm={predict_landmarks.at<float>(i,0)*w_r,predict_landmarks.at<float>(i,1)*h_r}; | ||
| 270 | result_landmarks.push_back(tmp_landm); | ||
| 271 | } | ||
| 272 | return result_landmarks; | ||
| 273 | } | ||
| 274 | |||
| 275 | |||
| 276 | |||
| 277 | //人脸识别部分 | ||
| 278 | |||
| 279 | cv::Mat FaceRecognize::meanAxis0(const cv::Mat &src) | ||
| 280 | { | ||
| 281 | int num = src.rows; | ||
| 282 | int dim = src.cols; | ||
| 283 | |||
| 284 | // x1 y1 | ||
| 285 | // x2 y2 | ||
| 286 | |||
| 287 | cv::Mat output(1,dim,CV_32F); | ||
| 288 | for(int i = 0 ; i < dim; i ++) | ||
| 289 | { | ||
| 290 | float sum = 0 ; | ||
| 291 | for(int j = 0 ; j < num ; j++) | ||
| 292 | { | ||
| 293 | sum+=src.at<float>(j,i); | ||
| 294 | } | ||
| 295 | output.at<float>(0,i) = sum/num; | ||
| 296 | } | ||
| 297 | |||
| 298 | return output; | ||
| 299 | } | ||
| 300 | |||
| 301 | cv::Mat FaceRecognize::elementwiseMinus(const cv::Mat &A,const cv::Mat &B) | ||
| 302 | { | ||
| 303 | cv::Mat output(A.rows,A.cols,A.type()); | ||
| 304 | |||
| 305 | assert(B.cols == A.cols); | ||
| 306 | if(B.cols == A.cols) | ||
| 307 | { | ||
| 308 | for(int i = 0 ; i < A.rows; i ++) | ||
| 309 | { | ||
| 310 | for(int j = 0 ; j < B.cols; j++) | ||
| 311 | { | ||
| 312 | output.at<float>(i,j) = A.at<float>(i,j) - B.at<float>(0,j); | ||
| 313 | } | ||
| 314 | } | ||
| 315 | } | ||
| 316 | return output; | ||
| 317 | } | ||
| 318 | |||
| 319 | cv::Mat FaceRecognize::varAxis0(const cv::Mat &src) | ||
| 320 | { | ||
| 321 | cv:Mat temp_ = elementwiseMinus(src,meanAxis0(src)); | ||
| 322 | cv::multiply(temp_ ,temp_ ,temp_ ); | ||
| 323 | return meanAxis0(temp_); | ||
| 324 | |||
| 325 | } | ||
| 326 | |||
| 327 | int FaceRecognize::MatrixRank(cv::Mat M) | ||
| 328 | { | ||
| 329 | Mat w, u, vt; | ||
| 330 | SVD::compute(M, w, u, vt); | ||
| 331 | Mat1b nonZeroSingularValues = w > 0.0001; | ||
| 332 | int rank = countNonZero(nonZeroSingularValues); | ||
| 333 | return rank; | ||
| 334 | |||
| 335 | } | ||
| 336 | |||
| 337 | cv::Mat FaceRecognize::similarTransform(cv::Mat src,cv::Mat dst) { | ||
| 338 | int num = src.rows; | ||
| 339 | int dim = src.cols; | ||
| 340 | cv::Mat src_mean = meanAxis0(src); | ||
| 341 | cv::Mat dst_mean = meanAxis0(dst); | ||
| 342 | cv::Mat src_demean = elementwiseMinus(src, src_mean); | ||
| 343 | cv::Mat dst_demean = elementwiseMinus(dst, dst_mean); | ||
| 344 | cv::Mat A = (dst_demean.t() * src_demean) / static_cast<float>(num); | ||
| 345 | cv::Mat d(dim, 1, CV_32F); | ||
| 346 | d.setTo(1.0f); | ||
| 347 | if (cv::determinant(A) < 0) { | ||
| 348 | d.at<float>(dim - 1, 0) = -1; | ||
| 349 | |||
| 350 | } | ||
| 351 | Mat T = cv::Mat::eye(dim + 1, dim + 1, CV_32F); | ||
| 352 | cv::Mat U, S, V; | ||
| 353 | SVD::compute(A, S,U, V); | ||
| 354 | |||
| 355 | // the SVD function in opencv differ from scipy . | ||
| 356 | |||
| 357 | |||
| 358 | int rank = MatrixRank(A); | ||
| 359 | if (rank == 0) { | ||
| 360 | assert(rank == 0); | ||
| 361 | |||
| 362 | } else if (rank == dim - 1) { | ||
| 363 | if (cv::determinant(U) * cv::determinant(V) > 0) { | ||
| 364 | T.rowRange(0, dim).colRange(0, dim) = U * V; | ||
| 365 | } else { | ||
| 366 | int s = d.at<float>(dim - 1, 0) = -1; | ||
| 367 | d.at<float>(dim - 1, 0) = -1; | ||
| 368 | |||
| 369 | T.rowRange(0, dim).colRange(0, dim) = U * V; | ||
| 370 | cv::Mat diag_ = cv::Mat::diag(d); | ||
| 371 | cv::Mat twp = diag_*V; //np.dot(np.diag(d), V.T) | ||
| 372 | Mat B = Mat::zeros(3, 3, CV_8UC1); | ||
| 373 | Mat C = B.diag(0); | ||
| 374 | T.rowRange(0, dim).colRange(0, dim) = U* twp; | ||
| 375 | d.at<float>(dim - 1, 0) = s; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | else{ | ||
| 379 | cv::Mat diag_ = cv::Mat::diag(d); | ||
| 380 | cv::Mat twp = diag_*V.t(); //np.dot(np.diag(d), V.T) | ||
| 381 | cv::Mat res = U* twp; // U | ||
| 382 | T.rowRange(0, dim).colRange(0, dim) = -U.t()* twp; | ||
| 383 | } | ||
| 384 | cv::Mat var_ = varAxis0(src_demean); | ||
| 385 | float val = cv::sum(var_).val[0]; | ||
| 386 | cv::Mat res; | ||
| 387 | cv::multiply(d,S,res); | ||
| 388 | float scale = 1.0/val*cv::sum(res).val[0]; | ||
| 389 | T.rowRange(0, dim).colRange(0, dim) = - T.rowRange(0, dim).colRange(0, dim).t(); | ||
| 390 | cv::Mat temp1 = T.rowRange(0, dim).colRange(0, dim); // T[:dim, :dim] | ||
| 391 | cv::Mat temp2 = src_mean.t(); //src_mean.T | ||
| 392 | cv::Mat temp3 = temp1*temp2; // np.dot(T[:dim, :dim], src_mean.T) | ||
| 393 | cv::Mat temp4 = scale*temp3; | ||
| 394 | T.rowRange(0, dim).colRange(dim, dim+1)= -(temp4 - dst_mean.t()) ; | ||
| 395 | T.rowRange(0, dim).colRange(0, dim) *= scale; | ||
| 396 | return T; | ||
| 397 | } | ||
| 398 | |||
| 399 | Mat FaceRecognize::preprocess_face(Mat image,vector<vector<float>> land){ | ||
| 400 | Mat out; | ||
| 401 | cv::resize(image,out,Size(112,112)); | ||
| 402 | float default1[5][2] = { | ||
| 403 | {38.2946f, 51.6963f}, | ||
| 404 | {73.5318f, 51.6963f}, | ||
| 405 | {56.0252f, 71.7366f}, | ||
| 406 | {41.5493f, 92.3655f}, | ||
| 407 | {70.7299f, 92.3655f} | ||
| 408 | }; | ||
| 409 | |||
| 410 | float lands[5][2]={ | ||
| 411 | {float(land[0][0]*112.0)/float(image.cols),float(land[0][1]*112.0)/float(image.rows)}, | ||
| 412 | {float(land[1][0]*112.0)/float(image.cols),float(land[1][1]*112.0)/float(image.rows)}, | ||
| 413 | {float(land[2][0]*112.0)/float(image.cols),float(land[2][1]*112.0)/float(image.rows)}, | ||
| 414 | {float(land[3][0]*112.0)/float(image.cols),float(land[3][1]*112.0)/float(image.rows)}, | ||
| 415 | {float(land[4][0]*112.0)/float(image.cols),float(land[4][1]*112.0)/float(image.rows)} | ||
| 416 | }; | ||
| 417 | cv::Mat src(5,2,CV_32FC1,default1); | ||
| 418 | memcpy(src.data, default1, 2 * 5 * sizeof(float)); | ||
| 419 | cv::Mat dst(5,2,CV_32FC1,lands); | ||
| 420 | memcpy(dst.data, lands, 2 * 5 * sizeof(float)); | ||
| 421 | cv::Mat M = similarTransform(dst, src); | ||
| 422 | float M_[2][3]={ | ||
| 423 | {M.at<float>(0,0),M.at<float>(0,1),M.at<float>(0,2)}, | ||
| 424 | {M.at<float>(1,0),M.at<float>(1,1),M.at<float>(1,2)}, | ||
| 425 | }; | ||
| 426 | |||
| 427 | cv::Mat M__(2,3,CV_32FC1,M_); | ||
| 428 | cv::Mat align_image; | ||
| 429 | cv::warpAffine(out,align_image,M__,Size(112, 112)); | ||
| 430 | return align_image; | ||
| 431 | } | ||
| 432 | |||
| 433 | double FaceRecognize::getMold(const vector<double>& vec) | ||
| 434 | { | ||
| 435 | int n = vec.size(); | ||
| 436 | double sum = 0.0; | ||
| 437 | for (int i = 0; i < n; ++i) | ||
| 438 | sum += vec[i] * vec[i]; | ||
| 439 | return sqrt(sum); | ||
| 440 | } | ||
| 441 | |||
| 442 | double FaceRecognize::cos_distance(const vector<double>& base, const vector<double>& target) | ||
| 443 | { | ||
| 444 | int n = base.size(); | ||
| 445 | assert(n == target.size()); | ||
| 446 | double tmp = 0.0; | ||
| 447 | for (int i = 0; i < n; ++i) | ||
| 448 | tmp += base[i] * target[i]; | ||
| 449 | double simility = tmp / (getMold(base)*getMold(target)); | ||
| 450 | return simility; | ||
| 451 | } | ||
| 452 | |||
| 453 | double FaceRecognize::get_samilar(Mat image1,Mat image2){ | ||
| 454 | cv::Mat blob1 = cv::dnn::blobFromImage(image1,1.0/127.5,Size(112,112),Scalar(127.5,127.5,127.5),true); // 由图片加载数据 这里还可以进行缩放、归一化等预处理 | ||
| 455 | rec_net.setInput(blob1); // 设置模型输入 | ||
| 456 | std::vector<cv::Mat> rec_netOutputImg1; | ||
| 457 | rec_net.forward(rec_netOutputImg1,rec_net.getUnconnectedOutLayersNames()); // 推理出结果 | ||
| 458 | cv::Mat blob2 = cv::dnn::blobFromImage(image2,1.0/127.5,Size(112,112),Scalar(127.5,127.5,127.5),true); // 由图片加载数据 这里还可以进行缩放、归一化等预处理 | ||
| 459 | rec_net.setInput(blob2); // 设置模型输入 | ||
| 460 | std::vector<cv::Mat> rec_netOutputImg2; | ||
| 461 | rec_net.forward(rec_netOutputImg2,rec_net.getUnconnectedOutLayersNames()); // 推理出结果 | ||
| 462 | cv::Mat feature1=rec_netOutputImg1[0].reshape(1,512); | ||
| 463 | cv::Mat feature2=rec_netOutputImg2[0].reshape(1,512); | ||
| 464 | vector<double> v1,v2; | ||
| 465 | for(int i=0;i<feature1.rows;i++){ | ||
| 466 | v1.push_back((double)feature1.at<float>(i,0)); | ||
| 467 | v2.push_back((double)feature2.at<float>(i,0)); | ||
| 468 | } | ||
| 469 | double cos_score=cos_distance(v1,v2); | ||
| 470 | return cos_score; | ||
| 471 | } | ||
| 472 | |||
| 473 | |||
| 474 | //整体pipeline | ||
| 475 | bool FaceRecognize::face_recognize(string image1_path,string image2_path){ | ||
| 476 | bool result=false; | ||
| 477 | cv::Mat image1=cv::imread(image1_path); | ||
| 478 | cv::Mat image2=cv::imread(image2_path); | ||
| 479 | vector<Bbox> box1=detect_image(image1); | ||
| 480 | vector<Bbox> box2=detect_image(image2); | ||
| 481 | |||
| 482 | int max_box1=0,max_box2=0; | ||
| 483 | double max_area1=0,max_area2=0; | ||
| 484 | for(int i=0;i<box1.size();++i){ | ||
| 485 | double tmp_area1=(box1[i].ymax-box1[i].ymin)*(box1[i].xmax-box1[i].xmin); | ||
| 486 | if(tmp_area1>max_area1){ | ||
| 487 | max_box1=i; | ||
| 488 | max_area1=tmp_area1; | ||
| 489 | } | ||
| 490 | } | ||
| 491 | Rect rect1=Rect(box1[max_box1].xmin,box1[max_box1].ymin,box1[max_box1].xmax-box1[max_box1].xmin,box1[max_box1].ymax-box1[max_box1].ymin); | ||
| 492 | Mat face_area1=image1(rect1); | ||
| 493 | vector<vector<float>> landms1=detect_image_landmarks(face_area1); | ||
| 494 | vector<vector<float>> land1={ | ||
| 495 | {float(landms1[104][0]),float(landms1[104][1])}, | ||
| 496 | {float(landms1[105][0]),float(landms1[105][1])}, | ||
| 497 | {float(landms1[46][0]),float(landms1[46][1])}, | ||
| 498 | {float(landms1[84][0]),float(landms1[84][1])}, | ||
| 499 | {float(landms1[90][0]),float(landms1[90][1])} | ||
| 500 | }; | ||
| 501 | Mat align_resize_image1=preprocess_face(face_area1,land1); | ||
| 502 | for(int j=0;j<box2.size();++j){ | ||
| 503 | Rect rect2=Rect(box2[max_box2].xmin,box2[max_box2].ymin,box2[max_box2].xmax-box2[max_box2].xmin,box2[max_box2].ymax-box2[max_box2].ymin); | ||
| 504 | Mat face_area2=image2(rect2); | ||
| 505 | vector<vector<float>> landms2=detect_image_landmarks(face_area2); | ||
| 506 | vector<vector<float>> land2={ | ||
| 507 | {float(landms2[104][0]),float(landms2[104][1])}, | ||
| 508 | {float(landms2[105][0]),float(landms2[105][1])}, | ||
| 509 | {float(landms2[46][0]),float(landms2[46][1])}, | ||
| 510 | {float(landms2[84][0]),float(landms2[84][1])}, | ||
| 511 | {float(landms2[90][0]),float(landms2[90][1])} | ||
| 512 | }; | ||
| 513 | Mat align_resize_image2=preprocess_face(face_area2,land2); | ||
| 514 | double samilar_score=get_samilar(align_resize_image1,align_resize_image2); | ||
| 515 | if(samilar_score>face_recongnize_thr){ | ||
| 516 | result=true; | ||
| 517 | } | ||
| 518 | } | ||
| 519 | return result; | ||
| 520 | } | ||
| 521 | |||
| 522 | bool FaceRecognize::face_recognize_image(Mat image1,Mat image2){ | ||
| 523 | bool result=false; | ||
| 524 | vector<Bbox> box1=detect_image(image1); | ||
| 525 | vector<Bbox> box2=detect_image(image2); | ||
| 526 | |||
| 527 | int max_box1=0,max_box2=0; | ||
| 528 | double max_area1=0,max_area2=0; | ||
| 529 | for(int i=0;i<box1.size();++i){ | ||
| 530 | double tmp_area1=(box1[i].ymax-box1[i].ymin)*(box1[i].xmax-box1[i].xmin); | ||
| 531 | if(tmp_area1>max_area1){ | ||
| 532 | max_box1=i; | ||
| 533 | max_area1=tmp_area1; | ||
| 534 | } | ||
| 535 | } | ||
| 536 | Rect rect1=Rect(box1[max_box1].xmin,box1[max_box1].ymin,box1[max_box1].xmax-box1[max_box1].xmin,box1[max_box1].ymax-box1[max_box1].ymin); | ||
| 537 | Mat face_area1=image1(rect1); | ||
| 538 | vector<vector<float>> landms1=detect_image_landmarks(face_area1); | ||
| 539 | vector<vector<float>> land1={ | ||
| 540 | {float(landms1[104][0]),float(landms1[104][1])}, | ||
| 541 | {float(landms1[105][0]),float(landms1[105][1])}, | ||
| 542 | {float(landms1[46][0]),float(landms1[46][1])}, | ||
| 543 | {float(landms1[84][0]),float(landms1[84][1])}, | ||
| 544 | {float(landms1[90][0]),float(landms1[90][1])} | ||
| 545 | }; | ||
| 546 | Mat align_resize_image1=preprocess_face(face_area1,land1); | ||
| 547 | for(int j=0;j<box2.size();++j){ | ||
| 548 | Rect rect2=Rect(box2[max_box2].xmin,box2[max_box2].ymin,box2[max_box2].xmax-box2[max_box2].xmin,box2[max_box2].ymax-box2[max_box2].ymin); | ||
| 549 | Mat face_area2=image2(rect2); | ||
| 550 | vector<vector<float>> landms2=detect_image_landmarks(face_area2); | ||
| 551 | vector<vector<float>> land2={ | ||
| 552 | {float(landms2[104][0]),float(landms2[104][1])}, | ||
| 553 | {float(landms2[105][0]),float(landms2[105][1])}, | ||
| 554 | {float(landms2[46][0]),float(landms2[46][1])}, | ||
| 555 | {float(landms2[84][0]),float(landms2[84][1])}, | ||
| 556 | {float(landms2[90][0]),float(landms2[90][1])} | ||
| 557 | }; | ||
| 558 | Mat align_resize_image2=preprocess_face(face_area2,land2); | ||
| 559 | double samilar_score=get_samilar(align_resize_image1,align_resize_image2); | ||
| 560 | if(samilar_score>face_recongnize_thr){ | ||
| 561 | result=true; | ||
| 562 | } | ||
| 563 | } | ||
| 564 | return result; | ||
| 565 | } | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
facerecognize.h
0 → 100644
| 1 | #ifndef FACERECOGNIZE_H | ||
| 2 | #define FACERECOGNIZE_H | ||
| 3 | #include<opencv2/opencv.hpp> | ||
| 4 | |||
| 5 | using namespace std; | ||
| 6 | using namespace cv; | ||
| 7 | struct Bbox{ | ||
| 8 | float xmin; | ||
| 9 | float ymin; | ||
| 10 | float xmax; | ||
| 11 | float ymax; | ||
| 12 | float score; | ||
| 13 | float x1; | ||
| 14 | float y1; | ||
| 15 | float x2; | ||
| 16 | float y2; | ||
| 17 | float x3; | ||
| 18 | float y3; | ||
| 19 | float x4; | ||
| 20 | float y4; | ||
| 21 | float x5; | ||
| 22 | float y5; | ||
| 23 | }; | ||
| 24 | class FaceRecognize{ | ||
| 25 | |||
| 26 | private: | ||
| 27 | //是否使用gpu? | ||
| 28 | bool use_gpu=true; | ||
| 29 | |||
| 30 | //人脸检测 | ||
| 31 | vector<float> input_size={640,640}; | ||
| 32 | vector<float> variances={0.1,0.2}; | ||
| 33 | vector<float> mean_data={104,117,128}; | ||
| 34 | float confidence_threshold = 0.5; //人脸检测阈值 | ||
| 35 | float keep_top_k = 100; | ||
| 36 | float vis_threshold = 0.5; | ||
| 37 | float nms_threshold = 0.4; | ||
| 38 | float resize_scale = 1.0; | ||
| 39 | bool is_bbox_process=true; //人脸外扩 | ||
| 40 | |||
| 41 | //人脸识别 | ||
| 42 | double face_recongnize_thr = 0.2; //人脸相似度阈值 | ||
| 43 | cv::dnn::Net det_net,landm_net,rec_net; | ||
| 44 | |||
| 45 | |||
| 46 | public: | ||
| 47 | FaceRecognize(); | ||
| 48 | FaceRecognize(string face_det_model_path,string face_landm_model_path,string face_rec_model_path){ | ||
| 49 | det_net = cv::dnn::readNetFromONNX(face_det_model_path); | ||
| 50 | landm_net = cv::dnn::readNetFromONNX(face_landm_model_path); | ||
| 51 | rec_net = cv::dnn::readNetFromONNX(face_rec_model_path); | ||
| 52 | if(use_gpu){ | ||
| 53 | det_net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA); | ||
| 54 | det_net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); | ||
| 55 | landm_net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA); | ||
| 56 | landm_net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); | ||
| 57 | rec_net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA); | ||
| 58 | rec_net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); | ||
| 59 | } | ||
| 60 | |||
| 61 | } | ||
| 62 | //人脸检测部分 | ||
| 63 | vector<vector<float>> priorBox(vector<float> image_size); | ||
| 64 | vector<Bbox> decode(vector<vector<float>> loc,vector<vector<float>> score,vector<vector<float>>pre,vector<vector<float>> priors,vector<float> variances); | ||
| 65 | void nms_cpu(std::vector<Bbox> &bboxes, float threshold); | ||
| 66 | vector<vector<float>> mat2vector(Mat mat); | ||
| 67 | vector<Bbox> select_score(vector<Bbox> bboxes,float threshold,float w_r,float h_r); | ||
| 68 | vector<Bbox> bbox_process(vector<Bbox> bboxes,float frame_w,float frame_h); | ||
| 69 | vector<Bbox> detect(string image_path); | ||
| 70 | vector<Bbox> detect_image(Mat image); | ||
| 71 | |||
| 72 | |||
| 73 | //人脸关键点部分 | ||
| 74 | vector<vector<float>> detect_landmarks(string image_path); | ||
| 75 | vector<vector<float>> detect_image_landmarks(cv::Mat image); | ||
| 76 | |||
| 77 | |||
| 78 | //人脸识部分 | ||
| 79 | cv::Mat meanAxis0(const cv::Mat &src); | ||
| 80 | cv::Mat elementwiseMinus(const cv::Mat &A,const cv::Mat &B); | ||
| 81 | cv::Mat varAxis0(const cv::Mat &src); | ||
| 82 | int MatrixRank(cv::Mat M); | ||
| 83 | cv::Mat similarTransform(cv::Mat src,cv::Mat dst); | ||
| 84 | Mat preprocess_face(Mat image,vector<vector<float>> land); | ||
| 85 | double getMold(const vector<double>& vec); | ||
| 86 | double cos_distance(const vector<double>& base, const vector<double>& target); | ||
| 87 | double get_samilar(Mat image1,Mat image2); | ||
| 88 | |||
| 89 | |||
| 90 | //整体 | ||
| 91 | bool face_recognize(string image1_path,string image2_path); | ||
| 92 | bool face_recognize_image(Mat image1,Mat image2); | ||
| 93 | }; | ||
| 94 | |||
| 95 | |||
| 96 | #endif | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
libfacerecognize.so
0 → 100755
No preview for this file type
main
0 → 100755
No preview for this file type
main.cpp
0 → 100644
| 1 | #include"facerecognize.h" | ||
| 2 | #include "ctime" | ||
| 3 | |||
| 4 | int main(){ | ||
| 5 | FaceRecognize face_rec=FaceRecognize("/home/situ/qfs/sdk_project/mobile_face_recognize/det_face_retina_torch_1.4_v0.0.2.onnx","/home/situ/qfs/sdk_project/mobile_face_recognize/det_landmarks_106_v0.0.1.onnx","/home/situ/qfs/sdk_project/mobile_face_recognize/ms1mv3_r18.onnx"); | ||
| 6 | clock_t start, end; | ||
| 7 | cv::Mat image1=cv::imread("/data/face_recognize/pipeline_test/59297ec0094211ecaf3d00163e514671/310faceImageContent163029410817774.jpg"); | ||
| 8 | cv::Mat image2=cv::imread("/data/face_recognize/pipeline_test/59297ec0094211ecaf3d00163e514671/310cardImageContent163029410836583.jpg"); | ||
| 9 | cout<<"start"<<endl; | ||
| 10 | start = clock(); | ||
| 11 | bool result=face_rec.face_recognize_image(image1,image2); | ||
| 12 | end = clock(); | ||
| 13 | double elapsedTime = static_cast<double>(end-start) / CLOCKS_PER_SEC ; | ||
| 14 | |||
| 15 | printf("PROCESSING TIME: %f",elapsedTime); | ||
| 16 | |||
| 17 | } |
ms1mv3_r18.onnx
0 → 100644
This file is too large to display.
-
Please register or sign in to post a comment