SeetaFace2代码阅读
SeetaFace2代码阅读
一、Face Alignment
人脸对齐做仿射变换:
- bool face_crop_core_ex(
- const uint8_t *image_data, int image_width, int image_height, int image_channels,
- uint8_t *crop_data, int crop_width, int crop_height,
- const float *points, int points_num,
- const float *mean_shape, int mean_shape_width, int mean_shape_height,
- int pad_top, int pad_bottom, int pad_left, int pad_right,
- float *final_points,
- SAMPLING_TYPE type,
- PADDING_TYPE ptype )
- {
- //std::unique_ptr<double[]> transformation(new double[TFORM_SIZE]);
- double transformation[TFORM_SIZE];
- bool check1 = transformation_maker(
- crop_width, crop_height,
- points, points_num, mean_shape, mean_shape_width, mean_shape_height,
- transformation );
- if( !check1 ) return false;
- bool check2 = spatial_transform( image_data, image_width, image_height, image_channels,
- crop_data, crop_width, crop_height,
- transformation,
- pad_top, pad_bottom, pad_left, pad_right,
- type,
- ptype );
- if( !check2 ) return false;
- bool check3 = true;
- if( final_points )
- {
- check3 = caculate_final_points( points, points_num,
- transformation,
- pad_top, pad_left, final_points );
- }
- if( !check3 ) return false;
- return true;
- }
二、Face Tracker
FaceTracker::track
函数中调用了FaceTracker::Implement::DetectV2
函数得到所有跟踪的人脸:
- SeetaTrackingFaceInfoArray FaceTracker::Implement::DetectV2(const SeetaImageData &image, int frame_no) const {
- auto &faces = Detect(image, frame_no);
- tracked_faces.clear();
- for (auto &face : faces) {
- SeetaTrackingFaceInfo info;
- info.PID = face.PID;
- info.score = face.conf;
- info.frame_no = face.frame_no;
- info.pos = face.pos;
- tracked_faces.push_back(info);
- }
- SeetaTrackingFaceInfoArray result = {nullptr, 0};
- result.data = tracked_faces.data();
- result.size = tracked_faces.size();
- return result;
- }
DetectV2
函数调用Detect
函数,使用pFD
人脸检测器进行人脸检测,检测出来的人脸分别与之间保存的人脸计算IOU,然后对IOU进行排序降序排序,设置iou thresh为0.3,大于此值表示匹配上,否则匹配失败,把它当作一个新的;如果大于0.5,则表明重合度很高,取两帧的平均坐标做为新坐标。
- const std::vector<TrackedFace> &FaceTracker::Implement::Detect(const SeetaImageData &image, int frame_no) const {
- if (!this->pFD) {
- pre_tracked_faces.clear();
- return pre_tracked_faces;
- }
- if (frame_no < 0) {
- frame_no = this->frame_no;
- ++this->frame_no;
- }
- int num = 0;
- auto face_array = this->pFD->detect(image);
- std::vector<SeetaRect> faces;
- num = int(face_array.size);
- for (int i = 0; i < num; ++i) {
- faces.push_back(face_array.data[i].pos);
- }
- // prepare scored trakced faces
- std::deque<ScoredTrackedFace> scored_tracked_faces(pre_tracked_faces.begin(), pre_tracked_faces.end());
- std::vector<TrackedFace> now_trakced_faces;
- for (int i = 0; i < num; ++i) {
- auto &face = faces[i];
- for (auto &scored_tracked_face : scored_tracked_faces) {
- scored_tracked_face.iou_score = IoU(scored_tracked_face.face.pos, face);
- std::cout << scored_tracked_face.iou_score << std::endl;
- }
- if (scored_tracked_faces.size() > 1) {
- std::partial_sort(scored_tracked_faces.begin(), scored_tracked_faces.begin() + 1,
- scored_tracked_faces.end(),
- [](const ScoredTrackedFace &a, const ScoredTrackedFace &b) {
- return a.iou_score > b.iou_score;
- });
- }
- if (!scored_tracked_faces.empty() && scored_tracked_faces.front().iou_score > this->min_score) {
- ScoredTrackedFace matched_face = scored_tracked_faces.front();
- scored_tracked_faces.pop_front();
- TrackedFace &tracked_face = matched_face.face;
- if (matched_face.iou_score < max_score) {
- tracked_face.pos.x = (tracked_face.pos.x + face.x) / 2;
- tracked_face.pos.y = (tracked_face.pos.y + face.y) / 2;
- tracked_face.pos.width = (tracked_face.pos.width + face.width) / 2;
- tracked_face.pos.height = (tracked_face.pos.height + face.height) / 2;
- } else {
- tracked_face.pos = face;
- }
- tracked_face.conf = face_array.data[i].score;
- tracked_face.frame_no = frame_no;
- now_trakced_faces.push_back(tracked_face);
- } else {
- TrackedFace tracked_face;
- tracked_face.pos = face;
- tracked_face.PID = max_PID;
- tracked_face.conf = face_array.data[i].score;
- tracked_face.frame_no = frame_no;
- max_PID++;
- now_trakced_faces.push_back(tracked_face);
- }
- }
- pre_tracked_faces = now_trakced_faces;
- return pre_tracked_faces;
- }
三、Face Quality Assessor
质量评估主要分为四个方面:
- brightness
- resolution
- pose
- clarity
1. brightness
求face区域所有像素的平均亮度值,满足40到180则通过检测
2. resolution
人脸框大于80
人脸框高/宽在在0.9~1.8
3. pose
满足如下条件:
- static const float roll0 = 1 / 3.0f;
- static const float yaw0 = 0.5f;
- static const float pitch0 = 0.5f;
- return roll < roll0 && yaw < yaw0 && pitch < pitch0;
4. clarity
清晰度检测使用如下算法进行评估,参照如下论文:
The blur effect: perception and estimation with a new no-reference perceptual blur metric
四、整体流程
总体流程如下:
- seeta::FaceTracker * m_tracker;
- m_tracker = new seeta::FaceTracker(fd_model, videowidth,videoheight);
- m_tracker->SetMinFaceSize(100); //set(seeta::FaceTracker::PROPERTY_MIN_FACE_SIZE, 100);
- m_tracker->SetMinFaceSize(gparamters.MinFaceSize);
- m_tracker->SetThreshold(gparamters.Fd_Threshold);
- m_tracker->SetVideoSize(gparamters.VideoWidth, gparamters.VideoHeight);
-
- auto faces = m_tracker->Track(image);
- //qDebug() << "-----track size:" << faces.size;
- if( faces.size > 0 )
- {
- m_mutex.lock();
- if(!m_readimage)
- {
- clone_image(image, *m_mainImage);
- //cv::Mat tmpmat;
- //cv::cvtColor(mat, tmpmat, cv::COLOR_BGR2RGB);
- m_mainmat = mat2.clone();//tmpmat.clone();
- m_mainfaceinfos.clear();
- for(int i=0; i<faces.size; i++)
- {
- m_mainfaceinfos.push_back(faces.data[i]);
- }
- m_readimage = true;
- }
- m_mutex.unlock();
- for(int i=0; i<faces.size; i++)
- {
- auto &face = faces.data[i].pos;
- //std::cout << "Clarity = " << clarity << ", Reality = " << reality << std::endl;
- //auto end = system_clock::now();
- //auto duration = duration_cast<microseconds>(end - start);
- //int spent = duration.count() / 1000;
- //std::string str = std::to_string(spent);
- //str = stateOfTheFace + " " + str;
- //cv::putText( mat, str.c_str(), cv::Point( face.x, face.y - 10 ), cv::FONT_HERSHEY_SIMPLEX, 1, color, 2 );
- //cv::rectangle( mat, cv::Rect( face.x, face.y, face.width, face.height ), color, 2, 8, 0 );
- cv::rectangle( mat2, cv::Rect( face.x, face.y, face.width, face.height ), color, 2, 8, 0 );
- }
- }