利用3000fps把人脸面部抠出来(一)

思路:思路很简单,前面有一篇讲了如何利用3000fps检测人脸特征点,把特征点检测出来之后,就有了人脸的大概轮廓。如下图。
这里大东方
上图只是显示了部分特征点,从0-16个特征点可以知道大概的脸型。
但是还有上半部分没有特征点,无法确定头发部分。怎么办呢?通过查看文献,其中这篇论文《Face Image Quality Assessment Based on Learning to Rank》提到了一个方法把人脸抠出来,然后对齐。
如下图
这里写图片描述
图中(a)是一般的框人脸方法,图(b)是通过人脸的四个眼角,两个嘴角特征点画出一个圆,然后图(c)人眼睛的四个眼角确定矩形框的倾斜角度,矩形的长和宽是4r和2.4r时效果最好,对齐之后的效果图中(efg)。
借鉴这种画圆求半径的思想,那我能不能利用这个半径再往上取一个矩形框呢?
于是动手试了一下,效果如下图。
这里写图片描述
效果还可以啊,换一张图试一下。
这里写图片描述
测试了很多张图片效果都还行。于是就才用这种方法了。
下面是核心代码,比较多测试时用的注释哈,将就看一下,使用起来也方便。后续我会将代码放在github上,有兴趣可以去看看。

void Detection( std::vector<cv::String> files) {
    LBFRegressor regressor;
    extern string cascadeName;
    CascadeClassifier cascade;
    double scale = 1.0;
    int i = 0;
    regressor.Load(modelPath + "LBF.model");
    // -- 1. Load the cascades
    if (!cascade.load(cascadeName)) {
        cerr << "ERROR: Could not load classifier cascade" << endl;
    }
    const static Scalar colors[] = { CV_RGB(0,0,255),
        CV_RGB(0,128,255),
        CV_RGB(0,255,255),
        CV_RGB(0,255,0),
        CV_RGB(255,128,0),
        CV_RGB(255,255,0),
        CV_RGB(255,0,0),
        CV_RGB(255,0,255) };
    int count = files.size();
    for (int j = 0; j < count; j++)
    {
        Mat gray;
        double t = 0;
        vector<Rect> faces;
        //vector<double> polygonX;//多边形轮廓点集合
        //vector<double> polygonY;
        vector<Point> polygon;
        Mat img = imread(files[j]);
        cvtColor(img, gray, CV_BGR2GRAY);

        // --Detection
        t = (double)cvGetTickCount();
        //cascade.detectMultiScale(gray, faces,
        //  1.1, 2, 0
        //  //|CV_HAAR_FIND_BIGGEST_OBJECT
        //  //|CV_HAAR_DO_ROUGH_SEARCH
        //  | CV_HAAR_SCALE_IMAGE
        //  ,
        //  Size(30, 30));
        cascade.detectMultiScale(gray, faces, 1.3, 1, 0, Size(30, 30));
        t = (double)cvGetTickCount() - t;
        printf("detection time = %g ms\n", t / ((double)cvGetTickFrequency()*1000.));




        // --Alignment
        t = (double)cvGetTickCount();
        //检测到超过一个人脸,则只计算一个人脸的特征,因为送入的图片本身就只包含一张人脸,检测出现两个
        //人脸,则检测出错,所以加facesize,保证只检测大的人脸特征点。不然特征点会多于18个,绘制的roi中间
        //会被挖空。
        //for (vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++) {
        for (vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r= faces.end(), i++) {
            Point center;
            Scalar color = colors[i % 8];
            BoundingBox boundingbox;

            boundingbox.start_x = r->x*scale;
            boundingbox.start_y = r->y*scale;
            boundingbox.width = (r->width - 1)*scale;
            boundingbox.height = (r->height - 1)*scale;
            boundingbox.centroid_x = boundingbox.start_x + boundingbox.width / 2.0;
            boundingbox.centroid_y = boundingbox.start_y + boundingbox.height / 2.0;

            t = (double)cvGetTickCount();
            Mat_<double> current_shape = regressor.Predict(gray, boundingbox, 1);
            t = (double)cvGetTickCount() - t;
            printf("alignment time = %g ms\n", t / ((double)cvGetTickFrequency()*1000.));
            //        // draw bounding box
            //        rectangle(img, cvPoint(boundingbox.start_x,boundingbox.start_y),
            //                  cvPoint(boundingbox.start_x+boundingbox.width,boundingbox.start_y+boundingbox.height),Scalar(0,255,0), 1, 8, 0);
            // draw result :: red
            double deta = current_shape(0, 0) - current_shape(15, 0);
            double rec_point1_y = current_shape(0, 1) + deta / 2;//第0个特征点与第15个特征点的差值的一般作为矩形的宽
            double rec_point1_x = current_shape(0, 0);
            //如果超过则赋值为0,到图片边界
            if (rec_point1_x < 0) { rec_point1_x = 0.0; }
            if (rec_point1_y < 0) { rec_point1_y = 0.0; }
            Point  rec_point1 = Point(rec_point1_x, rec_point1_y);//对角线两个点
            Point  rec_point2 = Point(current_shape(16, 0), current_shape(16, 1));
            Point  rec_point3 = Point(rec_point1_x, current_shape(16, 1));
            Point  rec_point4 = Point(current_shape(16, 0), rec_point1_y);
            polygon.push_back(rec_point1);
            polygon.push_back(rec_point3);
            //cout << deta << endl;
            //cout << rec_point1 << endl;
            //cout << rec_point2<< endl;
            //rectangle(img, rec_point1, rec_point2, Scalar(255, 255, 0), 2, 8, 0);
            for (int i = 0; i <16 /*global_params.landmark_num*/; i++) {
                //circle(img, Point2d(current_shape(i, 0), current_shape(i, 1)), 3, Scalar(255, 255, 255), -1, 8, 0);
                //cout << current_shape(i, 0) << endl;
                //cout << current_shape(i, 1) << endl;
                //cout << global_params.landmark_num << endl;
                Point pp = Point (current_shape(i, 0), current_shape(i, 1));
                Point pp2 = Point (current_shape(i+1, 0), current_shape(i+1, 1));

                //putText(img, std::to_string(i), pp, FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255),1, 4);//在图片上写文字
                //cout << std::to_string(i)<<pp << endl;
                //cout << pp << endl;
                //line(img, pp,pp2, Scalar(255, 255, 0),2);
                //imshow("底板", img);

                //polygonX.push_back(current_shape(i, 0));//添加多边形轮廓点
                //polygonY.push_back(current_shape(i, 1));//添加多边形轮廓点
                polygon.push_back(pp);
                //cout << polygonX[i] << endl;
                //waitKey(300);

            }
            //double deta = current_shape(0, 0) - current_shape(15, 0);
            //double rec_point1_y = current_shape(0, 1) + deta / 2;//第0个特征点与第15个特征点的差值的一般作为矩形的宽
            //double rec_point1_x = current_shape(0, 0);
            如果超过则赋值为0,到图片边界
            //if (rec_point1_x < 0) { rec_point1_x = 0.0; }
            //if (rec_point1_y < 0) { rec_point1_y = 0.0; }
            //Point  rec_point1 = Point(rec_point1_x, rec_point1_y);//对角线两个点
            //Point  rec_point2 = Point(current_shape(16, 0), current_shape(16, 1));
            //Point  rec_point3 = Point(rec_point1_x, current_shape(16, 1));
            //Point  rec_point4 = Point(current_shape(16, 0), rec_point1_y);
            cout << deta << endl;
            cout << rec_point1 << endl;
            cout << rec_point2<< endl;
            //rectangle(img, rec_point1,rec_point2,Scalar(255,255,0), 2, 8, 0);
            //line(img, Point(current_shape(36,0),current_shape(36,1)), Point(current_shape(45,0),current_shape(45,1)), Scalar(255, 255, 0), 2);
            //cv::imshow("result", img);
            //waitKey(300);

            polygon.push_back(rec_point2);
            polygon.push_back(rec_point4);


            //cout << files[j] << endl;
            string depthFace_dir, RGBFace_dir;
            string roi_depthFace_dir, roi_RGBFace_dir;//抠出的人脸轮廓
                                                      //depthFace_dir = files[j];//RGB图片绝对路径
            RGBFace_dir = files[j];//RGB图片绝对路径
                                   //depthFace_dir.replace()
            depthFace_dir = string_replace(RGBFace_dir, "RGBFace", "DepthFace");
            depthFace_dir = string_replace(depthFace_dir, "jpg", "png");
            Mat Depth_image = imread(depthFace_dir, CV_LOAD_IMAGE_UNCHANGED);//读取CV_16UC1类型的数据

            //cout << depthFace_dir << endl;
            if (!Depth_image.empty()) {
                Mat roi_depthFace = contour_roi(Depth_image, polygon);
                //新建一个roi_depthFace_dir文件夹,用于保存处理后的深度图片
                roi_depthFace_dir = string_replace(depthFace_dir, "DepthFace", "roi_DepthFace");
                //cout << roi_depthFace_dir << endl;
                imwrite(roi_depthFace_dir, roi_depthFace);
                Mat roi_RGBFace = contour_roi(img, polygon);
                //新建一个roi_RGBFace_dir文件夹,用于保存处理后的RGB图片
                //保存这个图是为了方便删除抠出的人脸是无效的,可以直接删除
                roi_RGBFace_dir = string_replace(RGBFace_dir, "RGBFace", "roi_RGBFace");
                //cout << roi_RGBFace_dir << endl;
                imwrite(roi_RGBFace_dir, roi_RGBFace);
            }
            else {
                cout << depthFace_dir << endl;
                ofstream out;
                out.open("E:/学习/深度学习/活体检测/数据集/Captrue_Data/dataset/real/read_image_emtpy.txt",ios::out);
                out << depthFace_dir << "\n";
                continue;
            }

        }
        //cv::imshow("result", img);
        //waitKey(10);
        //Mat image = imread("E:/201842516518997.png", CV_LOAD_IMAGE_UNCHANGED);//CV_16UC1类型的数据
                                                //读取16位的深度图


        //waitKey(100);
        //waitKey(100);

    }

}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值