今天周六,抽个时间给大家闲聊一下人脸融合技术。
说到这个技术,很多人可能很陌生,但是当提到 AI 人脸识别,AI 换脸,AI 算命,人脸美化等技术,相信都不陌生了。
况且这个技术目前 BAT 等巨头都有涉猎,国内的人工智能巨头新秀也不例外。可以说谁先占领了 AI,谁就在下一代浪潮中立身于不败之地。
说回技术本身,我也只是略懂皮毛。下面说一下,具体的实现思路。
如上图所示,在图片上的人脸中,找出这些特征点(一般,找 68、72 个就可以了)。
如果脸型相同或相近,那么就可以换脸,进行融合了。
说起来简单,但是实现起来就涉及到很多算法了。
目前市面上多数的 APP 都是借助 Face++,BAT 等提供的 sdk api 实现的。这方面的 API 调用费用还挺贵的!
我的实现也很简单,借助开源类库,加上巨头提供的 API,基于 Java 实现人脸融合。
首先,利用 opencv 获得关键特征点。
public static void main(String[] args) throws FileNotFoundException {
String path1 = ResourceUtils.getFile("classpath:img/3m.jpg").getAbsolutePath();
String path2 = ResourceUtils.getFile("classpath:img/2m.jpg").getAbsolutePath();
String savePath = "/User/业余草/face";//图片存放位置
// 参数说明
// type :opencv和baidu 两种获取人脸标记的位置点
// true 使用全部点位进行分割,false使用外部轮廓的点位进行融合
OpenCVFaceSwap.faceMerge(path1,path2,savePath,"opencv",true);
}
然后,进行第三方 API 调用。
//人脸检测
ImageInfo imageInfo = getRGBData(path1);
List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
System.out.println(faceInfoList);
//特征提取
FaceFeature faceFeature = new FaceFeature();
errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature);
System.out.println("特征值大小:" + faceFeature.getFeatureData().length);
//人脸检测2
ImageInfo imageInfo2 = getRGBData(path2);
List<FaceInfo> faceInfoList2 = new ArrayList<FaceInfo>();
errorCode = faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(),imageInfo.getImageFormat(), faceInfoList2);
System.out.println(faceInfoList);
//特征提取2
FaceFeature faceFeature2 = new FaceFeature();
errorCode = faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo.getImageFormat(), faceInfoList2.get(0), faceFeature2);
System.out.println("特征值大小:" + faceFeature.getFeatureData().length);
//特征比对
FaceFeature targetFaceFeature = new FaceFeature();
targetFaceFeature.setFeatureData(faceFeature.getFeatureData());
FaceFeature sourceFaceFeature = new FaceFeature();
sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());
FaceSimilar faceSimilar = new FaceSimilar();
errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
System.out.println("相似度:" + faceSimilar.getScore());
//引擎卸载
errorCode = faceEngine.unInit();
上面就是比较核心的代码。
public static Mat flow(Mat mat) {
// 灰度
mat = OpencvUtil.gray(mat);
// 二值化 此处绝定图片的清晰度
mat = OpencvUtil.binary(mat);
// 腐蚀 去除背景图片
mat = OpencvUtil.erode(mat, 1);
return mat;
}
/**
* 灰化处理
*
* @return
*/
public static Mat gray(Mat mat) {
Mat gray = new Mat();
opencv_imgproc.cvtColor(mat, gray, opencv_imgproc.COLOR_BGR2GRAY, 1);
return gray;
}
/**
* 增强对比
* @param mat
* @return
*/
public static Mat splitBGR(Mat mat) {
MatVector splitBGR = new MatVector();
opencv_core.split(mat, splitBGR);
for (int i = 0; i<mat.channels(); i++){
opencv_imgproc.equalizeHist(splitBGR.get(i), splitBGR.get(i));
}
opencv_core.merge(splitBGR, mat);
return mat;
}
另外还涉及到一些图片的特殊处理,利用的也是 Opencv。
说白了,我不具有核心技术,我就是一个 API 调用工程师。核心算法我一概不懂,专业造轮子。
做的牛逼一点的,可以从视频中提取图片,再进行融合。