| 1125 | } |
| 1126 | |
| 1127 | cv::Mat cloneFace(const std::string& user_image_path, const std::string& model_image_path, const std::string& datadir) |
| 1128 | { |
| 1129 | TIME_START; |
| 1130 | |
| 1131 | Mat user = imread(user_image_path); |
| 1132 | Mat model = imread(model_image_path); |
| 1133 | assert(user.data && model.data); // make sure image does exist and path is correct. |
| 1134 | TIME_STOP("cloneFace > imread"); |
| 1135 | |
| 1136 | Mat user_image_gray, model_image_gray; |
| 1137 | cv::cvtColor(user, user_image_gray, CV_BGR2GRAY); |
| 1138 | cv::cvtColor(model, model_image_gray, CV_BGR2GRAY); |
| 1139 | TIME_STOP("cloneFace > cvtColor"); |
| 1140 | |
| 1141 | std::vector<Point2f> user_points = getFaceFeaturePoints(user_image_gray, user_image_path, datadir); |
| 1142 | std::vector<Point2f> model_points = getFaceFeaturePoints(model_image_gray, model_image_path, datadir); |
| 1143 | TIME_STOP("cloneFace > getFaceFeaturePoints"); |
| 1144 | if(user_points.empty() || model_points.empty()) |
| 1145 | { |
| 1146 | LOGE("no face detectd, return raw image"); |
| 1147 | return user; |
| 1148 | } |
| 1149 | |
| 1150 | RoiInfo user_face_info = calcuateFaceRegionInfo(user_points); |
| 1151 | RoiInfo model_face_info = calcuateFaceRegionInfo(model_points); |
| 1152 | TIME_STOP("cloneFace > calcuateFaceRoiInfo"); |
| 1153 | |
| 1154 | // make all the stuff relative to face, not entire image. |
| 1155 | Rect user_face_rect(cvRound(user_face_info.origion.x), cvRound(user_face_info.origion.y), user_face_info.mask.cols, user_face_info.mask.rows); |
| 1156 | Rect model_face_rect(cvRound(model_face_info.origion.x), cvRound(model_face_info.origion.y), model_face_info.mask.cols, model_face_info.mask.rows); |
| 1157 | Mat user_face = user(user_face_rect); |
| 1158 | Mat model_face = model(model_face_rect); |
| 1159 | |
| 1160 | for(Point2f& point: user_points) |
| 1161 | point -= user_face_info.origion; |
| 1162 | for(Point2f& point: model_points) |
| 1163 | point -= model_face_info.origion; |
| 1164 | TIME_STOP("cloneFace > cropFace"); |
| 1165 | |
| 1166 | user_face.convertTo(user_face, CV_32FC3, 1/255.0); |
| 1167 | model_face.convertTo(model_face, CV_32FC3, 1/255.0); |
| 1168 | stretchImage(model_face, user_face, model_points, user_points, Extractor::triangle_indices); |
| 1169 | user_face.convertTo(user_face, CV_8UC3, 255.0); |
| 1170 | TIME_STOP("cloneFace > convert image from CV_8UC3 to CV_32FC3, stretchImage"); |
| 1171 | |
| 1172 | cv::seamlessClone(user_face, user, user_face_info.mask, user_face_info.pivot, user, MIXED_CLONE); |
| 1173 | TIME_STOP("cloneFace > seamlessClone"); |
| 1174 | return user; |
| 1175 | } |
| 1176 | |
| 1177 | Mat& blendColor(Mat& src, const Mat& mask, uint32_t color, float alpha) |
| 1178 | { |
no test coverage detected