std::vector<std::vector<float>> find_skin_mask(const cv::Mat &image, const std::vector<std::array<std::array<long, 2>, 68>> &landmarks){ /*find skin pixels in the face. This is done by finding the convex hull defined by the face landmarks, then subtracting the convex hulls around the eyes and the mouth.*/ long num_rows = image.dims[0]; long num_cols = image.dims[1]; std::vector<std::vector<long>> face = copy_subset_vector(landmarks, face_dlib); std::vector<std::vector<long>> left_eye = copy_subset_vector(landmarks, leye_dlib); std::vector<std::vector<long>> right_eye = copy_subset_vector(landmarks, reye_dlib); std::vector<std::vector<long>> teeth = copy_subset_vector(landmarks, innermouth_dlib); std::vector<std::vector<long>> left_eyebrow = copy_subset_vector(landmarks, leyebrow_dlib); std::vector<std::vector<long>> right_eyebrow = copy_subset_vector(landmarks, reyebrow_dlib); std::vector<std::vector<long>> _full_face = face.insert(face.end(), left_eyebrow.begin(), left_eyebrow.end()); std::vector<std::vector<long>> full_face = _full_face.insert( _full_face.end(), right_eyebrow.begin(), right_eyebrow.end()); std::vector<std::vector<float>> left_eye_mask = convex_mask(num_rows, num_cols, left_eye); std::vector<std::vector<float>> invert_left_eye_mask = invert_mask(left_eye_mask); std::vector<std::vector<float>> right_eye_mask = convex_mask(num_rows, num_cols, right_eye); std::vector<std::vector<float>> invert_right_eye_mask = invert_mask(right_eye_mask); std::vector<std::vector<float>> teeth_mask = convex_mask(num_rows, num_cols, teeth); std::vector<std::vector<float>> invert_teeth_mask = invert_mask(teeth_mask); std::vector<std::vector<float>> face_mask = convex_mask(num_rows, num_cols, full_face); std::vector<std::vector<float>> skin_a = elementwise_product(face_mask, invert_left_eye_mask); std::vector<std::vector<float>> skin_b = elementwise_product(invert_right_eye_mask, invert_teeth_mask); std::vector<std::vector<float>> skin_mask = elementwise_product(skin_a, skin_b); return skin_mask; };
void improve_skin(const cv::Mat &image, const cv::Mat &image_hsv, const vector<std::array<std::array<long, 2>, 68>> &landmarks, int blur_patch_size_hsv, int blur_patch_size_rgb){ /*returns a new image in which the skin has been smoothed.*/ double blur_factor = estimate_image_blur(image, landmarks); std::vector<std::vector<float>> skin_mask = find_skin_mask(image, landmarks); std::vector<std::vector<float>> not_skin_mask = invert_mask(skin_mask); /*HSV smoothing*/ smooth_layers(image_hsv, blur_patch_size_hsv); cv::Mat image_hsv_copy = image_hsv; elementwise_product_cvmat(image_hsv, skin_mask); elementwise_product_cvmat(image_hsv_copy, not_skin_mask); elementwise_sum_cvmat(image_hsv, image_hsv_copy); cv::cvCvtColor(image_hsv, image, CV_HSV2RGB); cv::Mat image_original = image; /*RGB smoothing*/ smooth_layers(image, blur_patch_size_rgb); cv::Mat image_rgb_copy = image_original; cv::Mat image_rgb_copy2 = image_original; elementwise_product_cvmat(image, skin_mask); elementwise_product_cvmat(image_rgb_copy, skin_mask); elementwise_product_cvmat(image_rgb_copy2, not_skin_mask); elementwise_product_cvmat_scalar(image, blur_factor); elementwise_product_cvmat_scalar(image_rgb_copy, 1.0 - blur_factor); elementwise_sum_cvmat(image, image_rgb_copy2); elementwise_sum_cvmat(image, image_rgb_copy); };
void poisson_solver_with_init(float *out, float *in, float *dat, int w, int h, float *init) { // build list of masked pixels int nmask, (*mask)[3] = build_mask(&nmask, in, w, h); if (!nmask) { for (int i = 0; i < w*h; i++) out[i] = isfinite(in[i]) ? in[i] : init[i]; return; } int *invmask = xmalloc(w*h*sizeof(int)); invert_mask(invmask, mask, nmask, w, h); // define the linear map A=laplacian_operator struct cgpois_state e[1]; e->w = w; e->h = h; e->mask = mask; e->invmask = invmask; e->nmask = nmask; e->boundary_data = xmalloc(w*h*sizeof(double)); e->interior_data = xmalloc(w*h*sizeof(double)); for (int i = 0; i < w*h; i++) e->boundary_data[i] = in[i]; for (int i = 0; i < w*h; i++) e->interior_data[i] = 0;//dat[i]; // fill-in the independent term b double *b = xmalloc(nmask * sizeof(double)); double *tmp = xmalloc(nmask * sizeof(double)); for (int p = 0; p < nmask; p++) tmp[p] = 0; minus_operator(b, tmp, nmask, e); free(tmp); for (int p = 0; p < nmask; p++) b[p] = -dat[mask[p][0]+w*mask[p][1]] - b[p]; for (int i = 0; i < w*h; i++) if (e->invmask[i] < 0) e->boundary_data[i] = 0; // compute the solution double *solution = xmalloc(nmask * sizeof(double)); double *initialization = xmalloc(nmask * sizeof(double)); for (int i = 0; i < nmask; i++) initialization[i] = init[mask[i][0]+w*mask[i][1]]; //conjugate_gradient(solution, minus_laplacian_operator, b, nmask, e); int cg_maxit = CG_MAXIT() >= 0 ? CG_MAXIT() : nmask; float cg_eps = CG_EPS() >= 0 ? CG_EPS() : 1e-6; fancy_conjugate_gradient(solution, minus_operator, b, nmask, e, initialization, cg_maxit, cg_eps); // copy the solution to its place for (int i = 0; i < w*h; i++) out[i] = in[i]; for (int p = 0; p < nmask; p++) { if (nmask < 33) fprintf(stderr, "sol[%d] = %g\n", p, solution[p]); out[mask[p][2]] = solution[p]; } free(e->interior_data); free(e->boundary_data); free(solution); free(mask); free(invmask); free(b); }