赞
踩
1、加载一张原图,并识别人脸的68个特征点
cv::Mat img = cv::imread("5.jpg");
// 人脸68特征点的识别函数
vector<Point2f> points_vec = dectectFace68(img);
// 大眼效果函数
Mat dst0 = on_BigEye(800, img, points_vec);
2、函数
vector<Point2f> dectectFace68(Mat src) { vector<Point2f> points_vec; int* pResults = NULL; //在检测函数中使用了pBuffer。 //如果你调用多个线程中的函数,请为每个线程创建一个缓冲区! unsigned char* pBuffer = (unsigned char*)malloc(DETECT_BUFFER_SIZE); if (!pBuffer) { fprintf(stderr, "Can not alloc buffer.\n"); //return 100; } Mat gray; cvtColor(src, gray, CV_BGR2GRAY); int doLandmark = 1;// do landmark detection pResults = facedetect_multiview_reinforce(pBuffer, (unsigned char*)(gray.ptr(0)), gray.cols, gray.rows, (int)gray.step, 1.2f, 2, 48, 0, doLandmark); int cxa = *pResults; ofstream file("facedata.txt", ios::out); //打印检测结果 if (0 == cxa) { } else { for (int i = 0; i < (pResults ? *pResults : 0); i++) { short* p = ((short*)(pResults + 1)) + 142 * i; //rectangle(src, Rect(p[0], p[1], p[2], p[3]), Scalar(0, 255, 0), 2); if (doLandmark) { for (int j = 0; j < 68; j++) { char c[8]; _itoa(j, c, 10); Point2f ff(p[6 + 2 * j], p[6 + 2 * j + 1]); points_vec.push_back(ff); file << ff.x << "\t" << ff.y << endl; /* circle(src, Point((int)p[6 + 2 * j], (int)p[6 + 2 * j + 1]), 3, Scalar(0, 0, 255), 3); CvPoint font; putText(src, c, Point((int)p[6 + 2 * j], (int)p[6 + 2 * j + 1]), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 23, 0), 1);*/ } } } } return points_vec; } // 双线性插值算法 void BilinearInsert(Mat& src, Mat& dst, float ux, float uy, int i, int j) { auto Abs = [&](float f) { return f > 0 ? f : -f; }; int c = src.channels(); if (c == 3) { //存储图像得浮点坐标 CvPoint2D32f uv; CvPoint3D32f f1; CvPoint3D32f f2; //取整数 int iu = (int)ux; int iv = (int)uy; uv.x = iu + 1; uv.y = iv + 1; //step图象像素行的实际宽度 三个通道进行计算(0 , 1 2 三通道) f1.x = ((uchar*)(src.data + src.step * iv))[iu * 3] * (1 - Abs(uv.x - iu)) + \ ((uchar*)(src.data + src.step * iv))[(iu + 1) * 3] * (uv.x - iu); f1.y = ((uchar*)(src.data + src.step * iv))[iu * 3 + 1] * (1 - Abs(uv.x - iu)) + \ ((uchar*)(src.data + src.step * iv))[(iu + 1) * 3 + 1] * (uv.x - iu); f1.z = ((uchar*)(src.data + src.step * iv))[iu * 3 + 2] * (1 - Abs(uv.x - iu)) + \ ((uchar*)(src.data + src.step * iv))[(iu + 1) * 3 + 2] * (uv.x - iu); f2.x = ((uchar*)(src.data + src.step * (iv + 1)))[iu * 3] * (1 - Abs(uv.x - iu)) + \ ((uchar*)(src.data + src.step * (iv + 1)))[(iu + 1) * 3] * (uv.x - iu); f2.y = ((uchar*)(src.data + src.step * (iv + 1)))[iu * 3 + 1] * (1 - Abs(uv.x - iu)) + \ ((uchar*)(src.data + src.step * (iv + 1)))[(iu + 1) * 3 + 1] * (uv.x - iu); f2.z = ((uchar*)(src.data + src.step * (iv + 1)))[iu * 3 + 2] * (1 - Abs(uv.x - iu)) + \ ((uchar*)(src.data + src.step * (iv + 1)))[(iu + 1) * 3 + 2] * (uv.x - iu); ((uchar*)(dst.data + dst.step * j))[i * 3] = f1.x * (1 - Abs(uv.y - iv)) + f2.x * (Abs(uv.y - iv)); //三个通道进行赋值 ((uchar*)(dst.data + dst.step * j))[i * 3 + 1] = f1.y * (1 - Abs(uv.y - iv)) + f2.y * (Abs(uv.y - iv)); ((uchar*)(dst.data + dst.step * j))[i * 3 + 2] = f1.z * (1 - Abs(uv.y - iv)) + f2.z * (Abs(uv.y - iv)); } } //图像局部缩放算法 void LocalTranslationWarp_Eye(Mat& img, Mat& dst, int warpX, int warpY, int endX, int endY, float radius) { //平移距离 float ddradius = radius * radius; //计算|m-c|^2 //size_t mc = (endX - warpX) * (endX - warpX) + (endY - warpY) * (endY - warpY); //计算 图像的高 宽 通道数量 int height = img.rows; int width = img.cols; int chan = img.channels(); auto Abs = [&](float f) { return f > 0 ? f : -f; }; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { // # 计算该点是否在形变圆的范围之内 //# 优化,第一步,直接判断是会在(startX, startY)的矩阵框中 if ((Abs(i - warpX) > radius) && (Abs(j - warpY) > radius)) continue; float distance = (i - warpX) * (i - warpX) + (j - warpY) * (j - warpY); if (distance < ddradius) { float rnorm = sqrt(distance) / radius; float ratio = 1 - (rnorm - 1) * (rnorm - 1) * 0.5; //映射原位置 float UX = warpX + ratio * (i - warpX); float UY = warpY + ratio * (j - warpY); //根据双线性插值得到UX UY的值 BilinearInsert(img, dst, UX, UY, i, j); } } } } //大眼效果 Mat on_BigEye(int b, Mat src, vector<Point2f> points_vec) { Mat dst = src.clone(); Point2f left_landmark = points_vec[38]; Point2f left_landmark_down = points_vec[27]; Point2f right_landmark = points_vec[44]; Point2f right_landmark_down = points_vec[27]; Point2f endPt = points_vec[30]; //# 计算第4个点到第6个点的距离作为距离 /*float r_left = sqrt( (left_landmark.x - left_landmark_down.x) * (left_landmark.x - left_landmark_down.x) + (left_landmark.y - left_landmark_down.y) * (left_landmark.y - left_landmark_down.y)); cout << "左眼距离:" << r_left;*/ float r_left = b; // # 计算第14个点到第16个点的距离作为距离 //float r_right = sqrt( // (right_landmark.x - right_landmark_down.x) * (right_landmark.x - right_landmark_down.x) + // (right_landmark.y - right_landmark_down.y) * (right_landmark.y - right_landmark_down.y)); //cout << "右眼距离:" << r_right; float r_right = b; // # 瘦左 //LocalTranslationWarp_Eye(src, dst, left_landmark.x, left_landmark.y, endPt.x, endPt.y, r_left); // # 瘦右 LocalTranslationWarp_Eye(src, dst, right_landmark.x, right_landmark.y, endPt.x, endPt.y, r_right); return dst; }
3、图像结果
大眼睛结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。