You need to enable JavaScript to run this app.
导航

iOS

最近更新时间2022.02.28 19:42:09

首次发布时间2022.02.25 17:16:51

项目中加入 SDK
  1. 项目中已使用 cocoapods,下一步参考 3,否则参考 2
  2. 在项目根目录,执行 pod init && pod install,可得到 Podfile 文件
  3. 打开 iossample 文件夹,拷贝 BytedEffectSDK.podspec、libeffect-SDK.a、include 到自己项目根目录(Podfile 同级目录)
  4. 打开 Podfile 文件,增加一行 pod 'BytedEffectSDK', :path => './'
  5. 执行 pod install,并打开 项目名.xcworkspace,可以看到在 Pods/Development Pods 目录下已有 BytedEffectSDK
  6. 添加素材,将提供的素材包(一般是 resource 文件夹)添加到工程中
代码中集成 SDK

以下指南针对使用 sample 中封装的 Objective-C 代码进行集成,如果直接在项目中使用 CV SDK 提供的 C 接口集成,参见 接口说明-特效接口说明-算法。。

准备阶段

  1. 拷贝 iossample 项目中的 BEMacro.h、BELog.h、Record/SDK 目录下的文件到自己项目中
  2. 如果需要使用 sample 中提供的视频采集、绘制接口(如果项目中已接入推流或有自己的图像处理,一般不需要这一步),同时拷贝Record/Utils/BEVideoCapture Record/ui/home/view/BEGLView 文件到自己项目中,使用参见 使用 Sample 中的视频采集接口

以上为主要接口,以上代码可能会对 sample 中的其他代码有依赖,可将这些也拷贝到自己项目中。

使用阶段

SDK 的统一封装接口为 BEFrameProcessor,SDK 的使用可以分为三个阶段:

  1. 初始化 SDK
  2. 使用 SDK 进行图像处理
  3. SDK 参数设置,如设置美颜、贴纸、滤镜等

1.初始化 SDK

初始化 SDK 对应的方法为:

- (instancetype)initWithContext:(EAGLContext *)context;

CV SDK 的使用依赖于 openGL 环境,如果项目中已有 EAGLContext,可以将其传递给 initWithContext,如果没有,可以使用如下代码创建:

EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

2.使用 SDK 进行图像处理

支持的输入数据类型

支持的数据类型支持的数据格式
CVPixelBufferRefkCVPixelFormatType_32BGRA,kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
bufferRGBA,BGRA
texture2D

SDK 的处理方法主要为 BEFrameProcessor#process,它有几种不同的实现,可以接收不同的参数。它们都需要一个共同的参数 timeStamp,即当前帧的时间,获取方法参见 timestamp-获取

处理 CVPixelBuffer

/// 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);

处理 buffer

/// 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;

处理 texture

/// 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 的输入输出,排查可能遇到的问题。

3.SDK 参数设置,如设置美颜、贴纸、滤镜等

注意,SDK 参数设置需要在初始化之后调用,请尽量与 SDK图像处理 处于同一线程使用,以避免可能出现的问题。

(1)设置美颜、美型、美妆

美颜、美型、美妆的设置使用的是同一个接口,一般来说使一个美颜生效需要两步:

  1. 设置素材对应的路径
  2. 设置素材中,特效的强度(一般强度默认为 0,所以这一步不执行会没有效果)

设置素材路径接口

/// 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对应说明

(2)设置贴纸

设置贴纸接口

/// set sticker path
/// @param path relative path
- (void)setStickerPath:(NSString*) path;

// 示例
[_processor setStickerPath:@"\baibianfaxing"];

此处的贴纸路径为素材包中 StickerResource.bundle/stickers 中的相对路径。

(3)设置滤镜

设置滤镜的接口

/// 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 中的相对路径。

4.SDK 算法功能使用

开启算法

对应接口:

/// 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 中的视频采集、绘制接口

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;
附录:timeStamp 获取

如果是使用 SDK 处理相机输出的 CMSampleBufferRef,可通过如下方式获取:

CMTime sampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
double timeStamp = (double)sampleTime.value/sampleTime.timescale;

否则通过如下方式获取:

double timeStamp = [[NSDate date] timeIntervalSince1970]];
附录:算法key与回调函数一览
算法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;(人脸属性)
AnimojiBEAnimojiAlgorithmTask.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;
附录:BEFrameProcessor 功能说明

是否采用并行渲染

@property (nonatomic, assign) BOOL usePipeline;

默认开启,开启之后会延迟一帧,但会提升性能。

SDK 版本获取

@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;

获取 SDK 中人脸结果

/// get face info
- (bef_ai_face_info *)getFaceInfo;

获取 SDK 中手势结果

/// get hand info
- (bef_ai_hand_info *)getHandInfo;

获取 SDK 中人体结果

/// get skeleton info
- (bef_ai_skeleton_result *)getSkeletonInfo;

获取 SDK 中人脸 MASK 结果

/// get mouth mask info
- (bef_ai_mouth_mask_info *)getMouthMaskInfo;

获取 SDK 中嘴唇 MASK 结果

/// get teeth mask info
- (bef_ai_teeth_mask_info *)getTeethMaskInfo;

获取 SDK 中牙齿 MASK 结果

/// get face mask info
- (bef_ai_face_mask_info *)getFaceMaskInfo;