repositories { flatDir { dirs 'libs' } }
implementation(name: 'effect-sdkXXX', ext: 'aar')
以下指南针对使用 sample 中封装的 Java 代码进行集成,如果直接在项目中使用 CV SDK 提供的 C 接口集成,参见 接口说明-特效及接口说明-算法。
以上为主要接口,以上代码可能会对 sample 中的其他代码有依赖,可将这些也拷贝到自己项目中。
以特效SDK为例,特效SDK 的统一封装接口为 EffectManager,SDK 的使用可以分为三个阶段:
注意,SDK 的所有操作都应该在 openGL 线程中执行。如果是在推流 SDK 中集成,一般直接在推流 SDK 提供的自定义美颜接口中进行即可,如果是本地环境,一般与 GLSurfaceView 一起使用,并在它提供的 openGL 环境中使用 CV SDK。
初始化的调用时机一般在 openGL 环境初始化完成后,如在 onSurfaceCreated 中(如使用推流 SDK,一般在推流 SDK 提供的初始化自定义美颜的接口)执行,需要调用的函数为:
mEffectManager = new EffectManager(this, new EffectResourceHelper(this)); mEffectManager.setOnEffectListener(this); int ret = mEffectManager.init();
支持的输入数据类型
支持的数据类型 | 支持的数据格式 |
---|---|
texture | OES,2D |
图像处理的调用,在 onDrawFrame 中执行(如果使用推流 SDK,可在推流 SDK 提供的接口中调用),对应的函数为:
// 将输入纹理转换出人脸为正的2D纹理 ProcessInput input = transToPortrait(); // 准备帧缓冲区纹理对象 int dstTexture = mImageUtil.prepareTexture(input.getWidth(), input.getHeight()); // 执行特效处理,输出的纹理是人脸为正的2D纹理 boolean ret = mEffectManager.process(input.getTexture(),dstTexture, input.getWidth(),input.getHeight(),input.getSensorRotation(), mImageSourceProvider.getTimestamp());
补充说明:
如果推流SDK默认接收的输入纹理是原始带有旋转角度的纹理,为了适配推流SDK,可以参考调用如下代码,将特效SDK输出的纹理转回原始的角度。
ImageUtil.Transition transition = new ImageUtil.Transition().rotate(mImageSourceProvider.getOrientation()).flip(false, mImageSourceProvider.isFront()).reverse(); int texture = mImageUtil.transferTextureToTexture(dstTexture,BytedEffectConstants.TextureFormat.Texure2D, input.getWidth(), input.getHeight(),transition);
process接口参数说明:
参数名 | 含义 |
---|---|
srcTexture | 输入纹理ID,需要确保该纹理是一张人脸为正的图像,如果是前置摄像头,需要同时完成镜像处理 |
dstTexture | 输出纹理ID |
width | 输入纹理宽度 |
height | 输入纹理高度 |
sensorRotation | 手机角度,通过手机传感器取得 |
timeStamp | 当前时间,参见 timeStamp获取 |
处理结果:
process 方法的输出为渲染后的 2D 纹理。
注意,不推荐使用 SDK 直接处理 buffer,SDK 最终需要接收的是待处理纹理,如需要处理 buffer,建议先将 buffer 转成纹理使用,但这会造成耗时增加。
注意,SDK 参数设置需要在初始化之后调用,请尽量与 SDK图像处理 处于同一线程使用,以避免可能出现的问题。
美颜、美型、美妆的设置使用的是同一个接口,一般来说使一个美颜生效需要两步:
第一步:设置素材对应的路径
第二步:设置素材中,特效的强度(一般强度默认为 0,所以这一步不执行会没有效果)
设置素材路径接口
/** * 设置特效组合,目前支持美颜、美形、美体、 美妆特效的任意叠加 */ boolean setComposeNodes(String[] nodes); // 示例 mEffectManager.setComposeNodes(new String[]{"beauty_Android_live"});
此处的素材路径,是相对于 ComposeMakeup.bundle/ComposeMakeup 的路径,素材包结构参见 素材包结构说明
注意,SDK 内部不会保存已设置的素材,所以此方法每次调用都需要将所有需要生效的素材路径加上。
设置素材中,特效强度接口
/** * 更新组合特效(美颜、美形、美体、 美妆)中某个节点的强度 */ boolean updateComposerNodeIntensity(String node, String key, float intensity); // 示例 mEffectManager.updateComposerNodeIntensity("beauty_Android_live", "whiten", 0.8f);
以美颜素材为例,需要通过 key 来控制我们要修改的是美白、磨皮还是锐化的强度,素材中 key 与功能的对应关系参见 素材key对应说明。
设置贴纸接口
/** * 开启或者关闭贴纸 如果path为空 关闭贴纸 * @param path 贴纸素材的文件路径 */ boolean setSticker(String path); // 示例 mEffectManager.setSticker("baibianfaxing");
此处的贴纸路径为素材包中 StickerResource.bundle/stickers 中的相对路径。
/** * 开启或者关闭滤镜 如果path为空 关闭滤镜 * * @param path path of filter file 滤镜资源文件路径 */ boolean setFilter(String path); /** * 设置滤镜强度 * * @param intensity intensity 参数值 */ boolean updateFilterIntensity(float intensity); // 示例 mEffectManager.setFilter("Filter_01_38"); mEffectManager.updateFilterIntensity(0.8f);
此处的滤镜路径为素材包中 FilterResource.bundle/Filter 中的相对路径。
以人脸算法为例:
人脸算法的调用封装在FaceAlgorithmTask中
1.算法初始化
public int initTask()
返回值表示初始化结果。
2.算法检测
public BefFaceInfo process(ByteBuffer buffer, int width, int height, int stride, BytedEffectConstants.PixlFormat pixlFormat, BytedEffectConstants.Rotation rotation)
3.算法参数设置
算法参数设置的函数定义为:
public void setConfig(AlgorithmTaskKey key, Object p)
其中 key表示参数的类型,p 为参数值,每一个算法的参数类型可以在算法的定义中看到,如key可以使用 FACE_280、FACE_ATTR 这几种。
启用FaceAlgorithmTask则需在AlgorithmTaskFactory进行注册。
AlgorithmTaskFactory.register(FaceAlgorithmTask.FACE, new AlgorithmTaskFactory.AlgorithmTaskGenerator<FaceAlgorithmTask.FaceResourceProvider>() { @Override public AlgorithmTask<FaceAlgorithmTask.FaceResourceProvider, ?> create(Context context, FaceAlgorithmTask.FaceResourceProvider provider) { return new FaceAlgorithmTask(context, provider); } });
android 中内置素材时是把素材放到 asset 中,这里面的文件内容无法通过路径获取,所以 sample 中的做法是在初次启动 app 时将其拷贝到应用私有目录中,通过 com.bytedance.labcv.demo.task.UnzipTask 完成,如果需要拷贝的素材过多,可能会导致启动时间太长,对此有以下参考方法:
如果是使用相机采集数据,并使用了 SurfaceTexture 作为输出数据容器,可以直接调用它的 getTimestamp 方法:
long timeStamp = surfaceTexture.getTimestamp();
否则使用系统方法:
long timeStamp System.currentTimeMillis();
三种不同的类型主要在与对于输入纹理的处理和绘制上的区别,具体看下面。
类型 | 区别 | 输出纹理 |
---|---|---|
TYPE_CAMERA | 会根据传进来的 srcTextureFormat、 cameraRotation 和 sensorRotation 对纹理做旋转,更容易保证效果正确,但由于需要两次旋转,性能较差 | 输出纹理与输入纹理方向相同 |
TYPE_VIDEO | 会根据传进来的 srcTextureFormat 和 videoRotation 对纹理做旋转,需要做一次旋转 | 输出纹理保持为正向,不一定与输入纹理同方向 |
TYPE_IMAGE | 不对纹理做预处理,需要保证传进来的纹理是 2D 且人脸是正的方向,相对的性能也更好 | 输出与输入同向,未做任何旋转 |
算法 | key | 返回结果 |
---|---|---|
人脸检测 | FaceAlgorithmTask.FACE FaceAlgorithmTask.FACE_280(280 点) FaceAlgorithmTask.FACE_ATTR(人脸属性) FaceAlgorithmTask.FACE_MASK(人脸 mask) FaceAlgorithmTask.MOUTH_MASK(嘴唇 mask) FaceAlgorithmTask.TEETH_MASK(牙齿 mask) | com.bytedance.labcv.effectsdk.BefFaceInfo |
人脸比对 | FaceVerifyAlgorithmTask.FACE_VERIFY | com.bytedance.labcv.core.algorithm.FaceVerifyAlgorithmTask.FaceVerifyCaptureResult |
Animoji | AnimojiAlgorithmTask.ANIMOJI | com.bytedance.labcv.effectsdk.BefAnimojiInfo |
C1 场景分类 | C1AlgorithmTask.C1 | com.bytedance.labcv.effectsdk.BefC1Info |
C2 场景分类 | C2AlgorithmTask.C2 | com.bytedance.labcv.effectsdk.BefC2Info |
车辆检测 | CarAlgorithmTask.CAR_ALGO CarAlgorithmTask.CAR_RECOG(车辆检测) CarAlgorithmTask.BRAND_RECOG(车牌检测) | com.bytedance.labcv.effectsdk.BefCarDetectInfo |
专注度检测 | ConcentrateAlgorithmTask.CONCENTRATION | com.bytedance.labcv.core.algorithm.ConcentrateAlgorithmTask.BefConcentrationInfo |
视线估计 | GazeEstimationAlgorithmTask.GAZE_ESTIMATION | com.bytedance.labcv.effectsdk.BefGazeEstimationInfo |
头发分割 | HairParserAlgorithmTask.HAIR_PARSER | com.bytedance.labcv.effectsdk.HairParser.HairMask |
手势检测 | HandAlgorithmTask.HAND | com.bytedance.labcv.effectsdk.BefHandInfo |
人头分割 | HeadSegAlgorithmTask.HEAD_SEGMENT | com.bytedance.labcv.effectsdk.BefHeadSegInfo |
距离估计 | HumanDistanceAlgorithmTask.HUMAN_DISTANCE | com.bytedance.labcv.effectsdk.BefDistanceInfo |
光线分类 | LightClsAlgorithmTask.LIGHT_CLS | com.bytedance.labcv.effectsdk.BefLightclsInfo |
宠物脸检测 | PetFaceAlgorithmTask.PET_FACE | com.bytedance.labcv.effectsdk.BefPetFaceInfo |
人体分割 | PortraitMattingAlgorithmTask.PORTRAIT_MATTING | com.bytedance.labcv.effectsdk.PortraitMatting.MattingMask |
骨骼检测 | SkeletonAlgorithmTask.SKELETON | com.bytedance.labcv.effectsdk.BefSkeletonInfo |
天空分割 | SkySegAlgorithmTask.SKY_SEGMENT | com.bytedance.labcv.effectsdk.BefSkyInfo |
视频分类 | VideoClsAlgorithmTask.VIDEO_CLS | com.bytedance.labcv.effectsdk.BefVideoClsInfo |
运动分类 | ActionRecognitionAlgorithmTask.ACTION_RECOGNITION | com.bytedance.labcv.effectsdk.BefActionRecognitionInfo |