新手求教opencv实现人脸替换

刚学习Opencv看的天旋地转,现在想实现一个可以在原图的基础上在另外一张图片截取人脸然后再贴到原图的脸上。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 看下这篇博客,也许你就懂了,链接:基于opencv人脸识别
  • 除此之外, 这篇博客: OpenCV实现人脸识别中的 2.人脸预处理 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    脸预处理是调整人脸图像,使其看起来更加清楚,也更加符合人识别人脸的过程。
    人眼检测对于人脸的预处理非常有用,对于人脸而言,面部表情、光照条件、摄像机的属性、与相机的距离等都会发生变化,但是人眼是水平的,并且对称分布在人脸上,两只眼睛在人脸的位置和大小是相当标准的。当人脸检测器将别的对象当成人脸时,可以通过眼部检测丢弃这种误判。人脸检测完成后,截取出人脸所在的区域,为了保持人脸在水平线上,将检测到眼睛中心位置的x为准线,将图像进行旋转和平移操作,以使眼睛能被对齐,保证训练图像和测试图像在同一位置。由于人脸识别的特征都在虹膜、鼻翼、嘴角等面像五官轮廓的大小、位置、距离等属性。对于截取的人脸图像在经过删除额头、下巴、耳朵和北京的操作,对于图像中含有噪声的影响,使用双边滤波器进行平滑操作减少噪声。最后使用椭圆掩码将图像中剩余的头发和人脸的背景去掉。
    检测人眼代码为

     cv::CascadeClassifier eye_cascade;
        if (!eye_cascade.load("haarcascade_eye_tree_eyeglasses.xml"))  //wear glass
        {
            qDebug()<< "Load haarcascade_face.xml failed!";
        }
         std::vector<cv::Rect> eyeRect;
         eye_cascade.detectMultiScale(Myface, eyeRect, 1.1, 4, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));      //detect eye  //4 depends the correct rate of eye,the num is bigger,the correct rate is higher
          int eye_num = 0;
          cv::Point Myeye[2];                                         //eye center
          for (size_t i = 0; i < eyeRect.size(); i++)
          {
             rectangle(Myface, eyeRect[i], Scalar(0, 255, 255));      //用矩形画出检测到的位置
             Myeye[eye_num] =getCenterPoint(eyeRect[i]);
             cv::circle(Myface,Myeye[eye_num],4,cv::Scalar(255,0,255));
             eye_num = eye_num+1;
          }
    
          resize(Myface,printImg,Size(500,500));
          //cv::imshow("6",printImg);
    

    找到正方形中心代码为

    cv::Point getCenterPoint(Rect rect)
    {
        cv::Point cpt;
        cpt.x = rect.x + cvRound(rect.width/2.0);
        cpt.y = rect.y + cvRound(rect.height/2.0);
        return cpt;
    }
    

    人脸预处理其步骤效果如图
    在这里插入图片描述
    识别出人眼截取掉额头和下巴信息,对人脸进行平滑滤波。
    处理代码如下

         cv::Point2f eyesCenter;
         eyesCenter.x = (Myeye[0].x+Myeye[1].x)*0.5f;
         eyesCenter.y = (Myeye[0].y+Myeye[1].y)*0.5f;
    
         double dy  = (Myeye[1].y - Myeye[0].y);
         double dx  = (Myeye[1].x - Myeye[0].x);
         double len = sqrt(dx*dx + dy*dy);
    
         double angle=atan2(dy,dx)*180.0/CV_PI;
    
         const double DESIRED_LEFT_EYE_X = 0.16;
         const double DESIRED_LEFT_EYE_Y = 0.14;
         const double DESIRED_RIGHT_EYE_X = (1.0f - 0.16);
    
         const int DESIRED_FACE_WIDTH = 150;
         const int DESIRED_FACE_HEIGHT= 150;
    
         double desiredLen = (DESIRED_RIGHT_EYE_X - 0.16);
         double scale = desiredLen * DESIRED_FACE_WIDTH /len;
    
         cv::Mat rot_mat = getRotationMatrix2D(eyesCenter,angle,scale);
         double ex = DESIRED_FACE_WIDTH * 0.5f - eyesCenter.x;
         double ey = DESIRED_FACE_HEIGHT* DESIRED_LEFT_EYE_Y - eyesCenter.y;
    
         rot_mat.at<double>(0,2) += ex;
         rot_mat.at<double>(1,2) += ey;
    
         cv::Mat warped = Mat(DESIRED_FACE_HEIGHT,DESIRED_FACE_WIDTH,CV_8U,Scalar(128));
         warpAffine(Myface,warped,rot_mat,warped.size());
    
          cv::Mat Smoothing_Myface;
          bilateralFilter(warped,Smoothing_Myface,0,20.0,2.0);
          resize(Smoothing_Myface,printImg,Size(500,500));
          //cv::imshow("smoothing processing",printImg);           //smoothing processing
    
          cv::Mat mask = Mat(warped.size(),CV_8UC1,Scalar(255));
          double dw = DESIRED_FACE_WIDTH;
          double dh = DESIRED_FACE_HEIGHT;
    
          Point faceCenter = Point(cvRound(dw*0.5),cvRound(dh*0.4));
          Size  size  = Size(cvRound(dw*0.5),cvRound(dh*0.8));
          ellipse(mask,faceCenter,size,0,0,360,Scalar(0),cv::FILLED);
    
          Smoothing_Myface.setTo(Scalar(0),mask);
          resize(Smoothing_Myface,printImg,Size(500,500));
    
          cv::Mat preprocess_IMG;
          resize(Smoothing_Myface,preprocess_IMG,Size(128,128));
          cv::cvtColor(preprocess_IMG,preprocess_IMG,cv::COLOR_BGR2GRAY);
    
          resize(mask,printImg,Size(500,500));
          //cv::imshow("mask",printImg);           //add mask processing
    
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^