以下指南针对使用 sample 中封装的 Objective-C 代码进行集成,如果直接在项目中使用 CV SDK 提供的 C 接口集成,参见 接口说明-特效及接口说明-算法。。
以上为主要接口,以上代码可能会对 sample 中的其他代码有依赖,可将这些也拷贝到自己项目中。
SDK 的统一封装接口为 BEFrameProcessor,SDK 的使用可以分为三个阶段:
初始化 SDK 对应的方法为:
- (instancetype)initWithContext:(EAGLContext *)context;
CV SDK 的使用依赖于 openGL 环境,如果项目中已有 EAGLContext,可以将其传递给 initWithContext,如果没有,可以使用如下代码创建:
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
支持的输入数据类型
支持的数据类型 | 支持的数据格式 |
---|---|
CVPixelBufferRef | kCVPixelFormatType_32BGRA,kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange |
buffer | RGBA,BGRA |
texture | 2D |
SDK 的处理方法主要为 BEFrameProcessor#process,它有几种不同的实现,可以接收不同的参数。它们都需要一个共同的参数 timeStamp,即当前帧的时间,获取方法参见 timestamp-获取。
/// process CVPixelBuffer /// @param pixelBuffer original pixelBuffer /// @param timeStamp current time - (BEProcessResult *)process:(CVPixelBufferRef)pixelBuffer timeStamp:(double)timeStamp; /// process CVPixelBuffer /// @param pixelBuffer original pixelBuffer /// @param timeStamp current time /// @param rotation rotation of pixelbuffer, example: 0,90,180,270 - (BEProcessResult *)process:(CVPixelBufferRef)pixelBuffer timeStamp:(double)timeStamp rotation:(int)rotation;
目前可处理的 CVPixelBuffer 类型有 kCVPixelFormatType_32BGRA、kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 和 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,如不确定 CVPixelBuffer 类型,可通过以下方式获取:
OSType type = CVPixelBufferGetPixelFormatType(pixelBuffer);
/// process buffer /// @param buffer original buffer /// @param width with of buffer /// @param height height of buffer /// @param bytesPerRow bytesPerRow of buffer /// @param timeStamp current time /// @param format pixel format, see BEFormatType - (BEProcessResult *)process:(unsigned char *)buffer width:(int)width height:(int)height bytesPerRow:(int)bytesPerRow timeStamp:(double)timeStamp format:(BEFormatType)format;
/// process texture /// @param texture original texture /// @param width width of texture /// @param height height of texture /// @param timeStamp current time - (BEProcessResult *)process:(GLuint)texture width:(int)width height:(int)height timeStamp:(double)timeStamp;
BEFrameProcessor#process 方法的处理结果都为 BEProcessResult,它内含了所有的处理结果:
/// output of (BEProcessResult *)process:(CVPixelBufferRef)pixelBuffer timeStamp:(double)timeStamp and (BEProcessResult *)process:(unsigned char *)buffer width:(int)width height:(int)height bytesPerRow:(int)bytesPerRow timeStamp:(double)timeStamp @interface BEProcessResult : NSObject /// always set @property (nonatomic, assign) GLuint texture; /// avaliable when set BERawData/BECVPixelBuffer/BEImage to BEFrameProcessor's processorResult @property (nonatomic, strong) BEProcessResultBuffer *buffer; /// available when set BECVPixelBuffer to BEFrameProcessor's processorResult @property (nonatomic, assign) CVPixelBufferRef pixelBuffer; /// available when set BEImage to BEFrameProcessor's processResult @property (nonatomic, assign) UIImage *image; /// size of result @property (nonatomic, assign) CGSize size; @end
以上结果中默认只有 texture 是有效的,如果需要返回有效的 buffer 或 CVPixelBuffer,需要修改 BEFrameProcessor#processorResult 的值,例如:
// 设置 CVPixelBuffer 生效 _processor.processorResult = BETexture | BECVPixelBuffer; // 设置 buffer 生效 _processor.processorResult = BETexture | BERawData; // 设置 CVPixelBuffer 和 UIImage 生效 _processor.processorResult = BETexture | BECVPixelBuffer | BEImage;
注意,请尽量只使自己需要用的数据有效,以上需要生效的部分越多,SDK 的耗时就会越多。
在接入测试时建议将 BECVPixelBuffer 打开,可以方便地观察 SDK 的输入输出,排查可能遇到的问题。
注意,SDK 参数设置需要在初始化之后调用,请尽量与 SDK图像处理 处于同一线程使用,以避免可能出现的问题。
美颜、美型、美妆的设置使用的是同一个接口,一般来说使一个美颜生效需要两步:
设置素材路径接口
/// update composer nodes /// @param nodes relative path - (void)updateComposerNodes:(NSArray<NSString *> *)nodes; // 示例 [_processor updateComposerNodes:[NSArray arrayWithObject:@"\beauty_IOS_live"]];
此处的素材路径,是相对于 ComposeMakeup.bundle/ComposeMakeup 的路径,素材包结构参见 素材包结构说明。
注意,SDK 内部不会保存已设置的素材,所以此方法每次调用都需要将所有需要生效的素材路径加上。
设置素材中,特效强度接口
/// update composer node intensity /// @param node relative path /// @param key key of feature, such as smooth,white... /// @param intensity 0-1 - (void)updateComposerNodeIntensity:(NSString *)node key:(NSString *)key intensity:(float)intensity; // 示例 [_processor updateComposerNodeIntensity:@"\beauty_IOS_live" key:@"whiten" intensity:0.8];
以美颜素材为例,需要通过 key 来控制我们要修改的是美白、磨皮还是锐化的强度,素材中 key 与功能的对应关系参见 素材key对应说明。
设置贴纸接口
/// set sticker path /// @param path relative path - (void)setStickerPath:(NSString*) path; // 示例 [_processor setStickerPath:@"\baibianfaxing"];
此处的贴纸路径为素材包中 StickerResource.bundle/stickers 中的相对路径。
设置滤镜的接口
/// set filter path /// @param path relative path - (void)setFilterPath:(NSString*) path; /// set filter intensity /// @param intensity 0-1 - (void)setFilterIntensity:(float)intensity; // 示例 [_processor setFilterPath:@"\Filter_01_38"]; [_processor setFilterIntensity:0.8];
此处的滤镜路径为素材包中 FilterResource.bundle/Filter 中的相对路径。
对应接口:
/// add/remove algorithm task /// @param key key of algorithm /// @param flag add the task if true, or remove if false - (void)addAlgorithmTask:(BETaskKey *)key flag:(BOOL)flag; // 示例,打开人脸 106 检测算法 [_processor addAlgorithmTask:BEFaceAlgorithmTask.FACE_106 flag:YES];
更多算法 key 对应关系参见 算法key与回调函数一览。
通过给 BEFrameProcessor 设置算法回调 delegate 来接收算法结果,对应接口:
@property (nonatomic, weak) id<BEAlgorithmDelegate> algrorithmDelegate; // 示例 _processor.algrorithmDelegate = self;
BEAlgorithmDelegate 中包含了所有算法的回调函数,对应关系参见 算法key与回调函数一览 。
sample 中提供了 BEVideoCapture 文件,可用于实现相机数据的采集或图片、视频的图像流输出,每一种模式都有一个单独的类。BEVideoCapture 的回调代理为 BEVideoCaptureDelegate,不同模式下的回调方法不同,会在下面说明。
相机预览模式对应的为 BEVideoCapture,其内部通过系统的 AVFoundation 功能进行相机数据采集。
初始化示例:
_capture = [[BEVideoCapture alloc] init]; _capture.delegate = self;
使用相机预览模式,需要实现的代理方法为:
- (void)videoCapture:(id<BEVideoCaptureProtocol>)camera didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer;
图片处理模式对应的类为 BEImageCapture,其内部将图片的 buffer 通过 NSTimer 模拟成一个视频流进行输出。
初始化示例:
_capture = [[BEImageCapture alloc] initWithImage:self.image]; _capture.delegate = self;
使用图片模式,需要实现的代理方法为:
- (void)videoCapture:(id<BEVideoCaptureProtocol>)camera didOutputBuffer:(unsigned char *)buffer width:(int)width height:(int)height bytesPerRow:(int)bytesPerRow timeStamp:(double)timeStamp;
视频处理模式对应的类为 BELocalVideoCapture,其内部通过 AVAssetReader 将本地视频解码为 CMSampleBuffer 输出。
初始化示例:
_capture = [[BELocalVideoCapture alloc] initWithAsset:self.asset]; _capture.delegate = self;
使用视频模式,需要实现的代理方法为:
- (void)videoCapture:(id<BEVideoCaptureProtocol>)camera didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer withRotation:(int)rotation;
Sample 中使用 BEGLView 继承 GLKView,在内部通过 openGL 对纹理进行绘制,如果自己项目中暂时没有将 CV SDK 处理后的图像绘制到屏幕上的方法,可以使用这个类。然后通过下面的方法绘制纹理:
- (void)renderWithTexture:(unsigned int)name size:(CGSize)size flipped:(BOOL)flipped applyingOrientation:(int)orientation fitType:(int)fitType;
如果是使用 SDK 处理相机输出的 CMSampleBufferRef,可通过如下方式获取:
CMTime sampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer); double timeStamp = (double)sampleTime.value/sampleTime.timescale;
否则通过如下方式获取:
double timeStamp = [[NSDate date] timeIntervalSince1970]];
算法 | key | 回调函数 |
---|---|---|
人脸检测 | BEFaceAlgorithmTask.FACE_106(106 点) BEFaceAlgorithmTask.FACE_280(280 点) BEFaceAlgorithmTask.FACE_ATTR(人脸属性) BEFaceAlgorithmTask.FACE_MASK(人脸 mask) BEFaceAlgorithmTask.MOUTH_MASK(嘴唇 mask) BEFaceAlgorithmTask.TEETH_MASK(牙齿 mask) | - (void)didDetectFaceInfo:(bef_ai_face_info)faceInfo;(人脸信息) - (void)didDetectExtraFaceInfo:(bef_ai_face_attribute_result)faceInfo;(人脸属性) |
Animoji | BEAnimojiAlgorithmTask.ANIMOJI | - (void)didDetectAnimoji:(bef_ai_animoji_info)info; |
C1 场景分类 | BEC1AlgorithmTask.C1 | - (void)didDetectC1:(bef_ai_c1_output)c1Info; |
C2 场景分类 | BEC2AlgorithmTask.C2 | - (void)didDetectC2:(bef_ai_c2_ret)c2Info; |
车辆检测 | BECarDetectTask.CAR_DETECT BECarDetectTask.CAR_DETECT(车辆检测) BECarDetectTask.CAR_BRAND_DETECT(车牌检测) | - (void)didDetectCar:(bef_ai_car_ret *)carInfo; |
专注度检测 | BEConcentrationTask.CONCENTRATION | - (void)didDetectConcentration:(float)proportion; |
视线估计 | BEGazeEstimationTask.GAZE_ESTIMATION | - (void)didDetectGaze:(bef_ai_gaze_estimation_info)gazeInfo; |
头发分割 | BEHairParserAlgorithmTask.HAIR_PARSER | |
手势检测 | BEHandAlgorithmTask.HAND | - (void)didDetectHandInfo:(bef_ai_hand_info)handInfo; |
人头分割 | BEHeadSegmentAlgorithmTask.HEAD_SEGMENT | |
距离估计 | BEHumanDistanceAlgorithmTask.HUMAN_DISTANCE | - (void)didDetectFace:(bef_ai_face_info)faceInfo distance:(bef_ai_human_distance_result) distance; |
光线分类 | BELightClsAlgorithmTask.LIGHT_CLS | - (void)didDetectLightCls:(bef_ai_light_cls_result)lightInfo; |
宠物脸检测 | BEPetFaceAlgorithmTask.PET_FACE | - (void)didDetectPetFace:(bef_ai_pet_face_result)petFectInfo; |
人体分割 | BEPortraitMattingAlgorithmTask.PORTRAIT_MATTING | |
骨骼检测 | BESkeletonAlgorithmTask.SKELETON | |
天空分割 | BESkySegAlgorithmTask.SKY_SEG | |
视频分类 | BEVideoClsAlgorithmTask.VIDEO_CLS | - (void)didDetectVideoCls:(bef_ai_video_cls_ret)videoInfo; |
@property (nonatomic, assign) BOOL usePipeline;
默认开启,开启之后会延迟一帧,但会提升性能。
@property (nonatomic, readonly) NSString *sdkVersion;
/// set filter path /// @param path relative path - (void)setFilterPath:(NSString*) path;
/// set filter intensity /// @param intensity 0-1 - (void)setFilterIntensity:(float)intensity;
/// set sticker path /// @param path relative path - (void)setStickerPath:(NSString*) path;
/// update composer nodes /// @param nodes relative path - (void)updateComposerNodes:(NSArray<NSString *> *)nodes;
/// update composer node intensity /// @param node relative path /// @param key key of feature, such as smooth,white... /// @param intensity 0-1 - (void)updateComposerNodeIntensity:(NSString *)node key:(NSString *)key intensity:(float)intensity;
/// get face info - (bef_ai_face_info *)getFaceInfo;
/// get hand info - (bef_ai_hand_info *)getHandInfo;
/// get skeleton info - (bef_ai_skeleton_result *)getSkeletonInfo;
/// get mouth mask info - (bef_ai_mouth_mask_info *)getMouthMaskInfo;
/// get teeth mask info - (bef_ai_teeth_mask_info *)getTeethMaskInfo;
/// get face mask info - (bef_ai_face_mask_info *)getFaceMaskInfo;