利用3000fps把人脸的脸部区域抠出来(二)

上一篇已经把人脸的脸部区域框出来了,那么要把人脸抠出来,只需要把轮廓的特征点放在一个verctor中组成一个ROI区域,然后根据OpenCV多边形抠图原理,把人脸抠出来就可以了。注意一下,把特征点放入的时候需要顺序加进vertor中,不然抠出的区域会出现会有交叉。
下面来看看代码:

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);

    }

}

其中读取16位深度图
Mat image = imread(“E:/201842516518997.png”,
CV_LOAD_IMAGE_UNCHANGED);//CV_16UC1类型的数据
//读取16位的深度图
特别注意,一定要将点按顺序放入vector中。
还用到了其他几个函数,一并放这里吧。
参数分别是图片和轮廓点的集合
返回值是抠出的区域图像。

cv::Mat contour_roi(cv::Mat img,std::vector<Point> polygon) {

    Mat dst;
    Mat roi = Mat::zeros(img.size(), CV_8U);
    contour.push_back(polygon);

    // 画出
    drawContours(roi, contour, 0, Scalar::all(255), -1);
    img.copyTo(dst, roi);

    imshow("roi", roi);
    //waitKey(100);
    //imshow("img", img);
    //waitKey(100);
    //imshow("dst", dst);
    //waitKey(100);

    waitKey(10);
    return dst;

}

字符替换函数

//************************************
// Method:    string_replace
// FullName:  string_replace
// Access:    public 
// Returns:   void
// Qualifier: 把字符串的strsrc替换成strdst
// Parameter: std::string & strBig
// Parameter: const std::string & strsrc
// Parameter: const std::string & strdst
//************************************
std::string string_replace(std::string strBig, const std::string &strsrc, const std::string &strdst)
{
    std::string::size_type pos = 0;
    std::string::size_type srclen = strsrc.size();
    std::string::size_type dstlen = strdst.size();

    while ((pos = strBig.find(strsrc, pos)) != std::string::npos)
    {
        strBig.replace(pos, srclen, strdst);
        pos += dstlen;
    }
    return strBig;
}

人脸区域抠出来的效果图
这里写图片描述

这里写图片描述

测试了一下时间,看看速度怎么样

这里写图片描述
这种方法对正脸效果很好,但是对于侧脸效果一般。
抠人脸主要是为了去掉深度摄像头获取的深度图在人脸周围的毛刺,如下图。
这里写图片描述
从深度摄像头获取的深度图
通过初步处理之后
这里写图片描述
但是还是很多毛刺。
抠出人脸区域之后
这里写图片描述
通过进一步处理
这里写图片描述
很干净了。处理方法在后续博客会更新。

C++代码后续也会上传到github上。

猜你喜欢

转载自blog.csdn.net/fengzhongluoleidehua/article/details/80440797
FPS
今日推荐