利用flandmark进行face alignment

flandmark是一个检测脸部特征点的开源代码库(http://cmp.felk.cvut.cz/~uricamic/flandmark/), 利用flandmark可以检测到左右眼睛的左右角点、鼻子、嘴的左右角点,位置如下:

/*
*    5   1    2   6
*
*
*          0/7
*
*
*       3       4
*
*/

检测效果如下图:



对于两幅脸部图像,检测到各自脸部特征点后,可以利用其中的三个对应特征点,进行仿射变换,将两幅脸部图像对齐。

代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include "libflandmark/flandmark_detector.h"  
  2. #include <opencv2/core/core.hpp>  
  3. #include <opencv2/imgproc/imgproc.hpp>  
  4. #include <opencv2/objdetect/objdetect.hpp>  
  5. #include <opencv2/highgui/highgui.hpp>  
  6. using namespace cv;  
  7.   
  8. #define _DEBUG_INFO  
  9.   
  10. int detectFaceInImage(IplImage *orig, IplImage* input, CvHaarClassifierCascade* cascade, FLANDMARK_Model *model, int *bbox, double *landmarks)  
  11. {  
  12.     int ret = 0;  
  13.   
  14.     // Smallest face size.  
  15.     CvSize minFeatureSize = cvSize(40, 40);  
  16.     int flags =  CV_HAAR_DO_CANNY_PRUNING;  
  17.     // How detailed should the search be.  
  18.     float search_scale_factor = 1.1f;  
  19.     CvMemStorage* storage;  
  20.     CvSeq* rects;  
  21.     int nFaces;  
  22.   
  23.     storage = cvCreateMemStorage(0);  
  24.     cvClearMemStorage(storage);  
  25.   
  26.     // Detect all the faces in the greyscale image.  
  27.     rects = cvHaarDetectObjects(input, cascade, storage, search_scale_factor, 2, flags, minFeatureSize);  
  28.     nFaces = rects->total;  
  29.   
  30.     double t = (double)cvGetTickCount();  
  31.     for (int iface = 0; iface < (rects ? nFaces : 0); ++iface)  
  32.     {  
  33.         CvRect *r = (CvRect*)cvGetSeqElem(rects, iface);  
  34.           
  35.         bbox[0] = r->x;  
  36.         bbox[1] = r->y;  
  37.         bbox[2] = r->x + r->width;  
  38.         bbox[3] = r->y + r->height;  
  39.           
  40.         ret = flandmark_detect(input, bbox, model, landmarks);  
  41.   
  42. #ifdef _DEBUG_INFO  
  43.         // display landmarks  
  44.         cvRectangle(orig, cvPoint(bbox[0], bbox[1]), cvPoint(bbox[2], bbox[3]), CV_RGB(255,0,0) );  
  45.         cvRectangle(orig, cvPoint(model->bb[0], model->bb[1]), cvPoint(model->bb[2], model->bb[3]), CV_RGB(0,0,255) );  
  46.         cvCircle(orig, cvPoint((int)landmarks[0], (int)landmarks[1]), 3, CV_RGB(0, 0,255), CV_FILLED);  
  47.         for (int i = 2; i < 2*model->data.options.M; i += 2)  
  48.         {  
  49.             cvCircle(orig, cvPoint(int(landmarks[i]), int(landmarks[i+1])), 3, CV_RGB(255,0,0), CV_FILLED);  
  50.   
  51.         }  
  52. #endif  
  53.   
  54.     }  
  55.     t = (double)cvGetTickCount() - t;  
  56.     int ms = cvRound( t / ((double)cvGetTickFrequency() * 1000.0) );  
  57.   
  58.     if (nFaces > 0)  
  59.     {  
  60.         printf("Faces detected: %d; Detection of facial landmark on all faces took %d ms\n", nFaces, ms);  
  61.     } else {  
  62.         printf("NO Face\n");  
  63.         ret = -1;  
  64.     }  
  65.       
  66.     cvReleaseMemStorage(&storage);  
  67.   
  68.     return ret;  
  69. }  
  70.   
  71. /* 
  72. *    5   1    2   6  
  73. * 
  74. * 
  75. *          0/7 
  76. * 
  77. * 
  78. *       3       4 
  79. * 
  80. */  
  81.   
  82.   
  83. int main( int argc, char** argv )   
  84. {  
  85.        
  86.     if (argc != 3)  
  87.     {  
  88.       fprintf(stderr, "Usage: %s <src_image> <dst_image>\n", argv[0]);  
  89.       exit(1);  
  90.     }  
  91.       
  92.       
  93.       
  94.     // Haar Cascade file, used for Face Detection.  
  95.     char faceCascadeFilename[] = "haarcascade_frontalface_alt.xml";  
  96.     // Load the HaarCascade classifier for face detection.  
  97.     CvHaarClassifierCascade* faceCascade;  
  98.     faceCascade = (CvHaarClassifierCascade*)cvLoad(faceCascadeFilename, 0, 0, 0);  
  99.     if( !faceCascade )  
  100.     {  
  101.         printf("Couldnt load Face detector '%s'\n", faceCascadeFilename);  
  102.         exit(1);  
  103.     }  
  104.   
  105.      // ------------- begin flandmark load model  
  106.     double t = (double)cvGetTickCount();  
  107.     FLANDMARK_Model * model = flandmark_init("flandmark_model.dat");  
  108.     if (model == 0)  
  109.     {  
  110.         printf("Structure model wasn't created. Corrupted file flandmark_model.dat?\n");  
  111.         exit(1);  
  112.     }  
  113.     t = (double)cvGetTickCount() - t;  
  114.     double ms = cvRound( t / ((double)cvGetTickFrequency() * 1000.0) );  
  115.     printf("Structure model loaded in %d ms.\n", ms);  
  116.     // ------------- end flandmark load model  
  117.       
  118.     // input image  
  119.     IplImage *src = cvLoadImage(argv[1]);  
  120.     IplImage *dst = cvLoadImage(argv[2]);  
  121.     if (src == NULL)  
  122.     {  
  123.       fprintf(stderr, "Cannot open image %s. Exiting...\n", argv[1]);  
  124.       exit(1);  
  125.     }  
  126.     if (dst == NULL)  
  127.     {  
  128.       fprintf(stderr, "Cannot open image %s. Exiting...\n", argv[2]);  
  129.       exit(1);  
  130.     }  
  131.   
  132.     // convert image to grayscale  
  133.     IplImage *src_gray = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);  
  134.     cvConvertImage(src, src_gray);  
  135.     IplImage *dst_gray = cvCreateImage(cvSize(dst->width, dst->height), IPL_DEPTH_8U, 1);  
  136.     cvConvertImage(dst, dst_gray);  
  137.       
  138.     // detect landmarks  
  139.     int *bbox_src = (int*)malloc(4*sizeof(int));  
  140.     int *bbox_dst = (int*)malloc(4*sizeof(int));  
  141.     double *landmarks_src = (double*)malloc(2*model->data.options.M*sizeof(double));  
  142.     double *landmarks_dst = (double*)malloc(2*model->data.options.M*sizeof(double));  
  143.     int ret_src = detectFaceInImage(src, src_gray, faceCascade, model, bbox_src, landmarks_src);  
  144.     int ret_dst = detectFaceInImage(dst, dst_gray, faceCascade, model, bbox_dst, landmarks_dst);  
  145.     if(0 != ret_src || 0 != ret_dst){  
  146.         printf("Landmark not detected!\n");  
  147.         return -1;  
  148.     }  
  149.   
  150.   
  151.     // *** face alignment begin *** //  
  152.     Point2f srcTri[3];  
  153.     Point2f dstTri[3];  
  154.     Mat src_mat(src);  
  155.     Mat dst_mat(dst);  
  156.     Mat warp_mat( 2, 3, CV_32FC1 );  
  157.     Mat warp_dst;  
  158.   
  159.     /// Set the dst image the same type and size as src  
  160.     warp_dst = Mat::zeros( src_mat.rows, src_mat.cols, src_mat.type() );  
  161.   
  162.     /// Set your 3 points to calculate the  Affine Transform  
  163.     srcTri[0] = Point2f( landmarks_src[5*2], landmarks_src[5*2+1] );  
  164.     srcTri[1] = Point2f( landmarks_src[6*2], landmarks_src[6*2+1] );  
  165.     srcTri[2] = Point2f( landmarks_src[0*2], landmarks_src[0*2+1] );  
  166.   
  167.     dstTri[0] = Point2f( landmarks_dst[5*2], landmarks_dst[5*2+1] );  
  168.     dstTri[1] = Point2f( landmarks_dst[6*2], landmarks_dst[6*2+1] );  
  169.     dstTri[2] = Point2f( landmarks_dst[0*2], landmarks_dst[0*2+1] );  
  170.   
  171.     /// Get the Affine Transform  
  172.     warp_mat = getAffineTransform( srcTri, dstTri );  
  173.   
  174.     /// Apply the Affine Transform just found to the src image  
  175.     warpAffine( src_mat, warp_dst, warp_mat, warp_dst.size() );  
  176.     // *** face alignment end *** //  
  177.   
  178.     // show images  
  179.     imshow("src", src_mat);  
  180.     imshow("dst", dst_mat);  
  181.     imshow("warp_dst", warp_dst);  
  182.     //imwrite("src.jpg", src_mat);  
  183.     //imwrite("dst.jpg", dst_mat);  
  184.     //imwrite("warp_dst.jpg", warp_dst);  
  185.     waitKey(0);  
  186.   
  187.   
  188.   
  189.     // cleanup  
  190.     free(bbox_src);  
  191.     free(landmarks_src);  
  192.     free(bbox_dst);  
  193.     free(landmarks_dst);  
  194.     cvDestroyAllWindows();  
  195.     cvReleaseImage(&src);  
  196.     cvReleaseImage(&src_gray);  
  197.     cvReleaseImage(&dst);  
  198.     cvReleaseImage(&dst_gray);  
  199.     cvReleaseHaarClassifierCascade(&faceCascade);  
  200.     flandmark_free(model);  
  201. }  



对齐效果如下,将第一幅图对齐到第二幅图,对齐后的图为第三幅图
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值