InspireFaceInspireFace1.2.4.d3
首页
快速开始
获取和编译
完整示例
  • English
  • 简体中文
GitHub
首页
快速开始
获取和编译
完整示例
  • English
  • 简体中文
GitHub
  • 介绍
  • 快速开始
  • 功能概览
  • 使用指南

    • 架构与生命周期
    • 模型资源包
    • 图像输入与坐标
    • 会话与跟踪
    • 人脸分析
    • 识别与特征库
    • 人脸关键点
    • 活体检测
    • 人脸抓拍
    • 补充 API 示例
  • 语言与平台

    • C API
    • C++
    • Python
    • Android
    • Apple
    • iOS
    • macOS
    • HarmonyOS
  • 获取和编译

    • 概述与下载
    • 源码准备与通用选项
    • Linux
    • macOS
    • Android
    • iOS
    • HarmonyOS
    • NVIDIA TensorRT
    • Rockchip NPU
    • Python 打包
  • 硬件部署

    • ARM
    • NVIDIA TensorRT
    • Rockchip NPU
    • Rockchip 上的 Python
  • InspireCV
  • 完整示例
  • API 功能索引
  • 性能测量
  • 图像处理性能
  • 常见问题

Objective-C 与 Swift

iOS 和 macOS 使用同一套 Apple 接口。Objective-C 类负责持有原生句柄,Swift 在此基础上提供 throws、功能选项,以及限定作用域的结果访问方式。需要直接处理缓冲区时,仍可使用 C 结构体。

先按 iOS 或 macOS 页面配置工程。这些接口属于当前开发版 SDK,较早的预编译包可能只有 C/C++ 库。下载源和源码构建入口见获取和编译。

模块与类型

LanguageImportLibraries
Objective-C / Objective-C++#import <InspireFace/InspireFaceApple.h>InspireFace
Swiftimport InspireFaceSwiftInspireFace 和 InspireFaceSwift
C / C++#include <InspireFace/inspireface.h>InspireFace

Framework 带有 Clang module,Swift 库带有模块接口文件。通过模块接入时,无需自己添加 bridging header。Objective-C 文件启用 ARC;只有同一文件还包含 C++ 代码时,才需要使用 .mm。

Objective-CSwift用途
IFRuntimeInspireFaceRuntime加载模型包,设置进程级运行环境。
IFSessionFaceSession检测、跟踪、特征提取及可选分析。
IFImageStreamImageStream描述输入图像,借用像素或持有符合要求的像素缓冲区。
IFImageBitmapImageBitmap持有像素,读取文件,绘制和保存图像。
IFFaceSnapshotFaceSnapshot持有一帧检测结果的独立副本。
IFFeatureBufferFaceFeatureBuffer持有特征缓冲区,比较特征。
IFFeatureHubFeatureHub管理进程级人脸数据库。
IFCaptureSessionFaceCaptureSession从连续帧中筛选抓拍候选。
IFFaceTokenFaceTokenUtilities复制 token,读取关键点。
IFDiagnosticsInspireFaceDiagnostics查询版本、错误信息和资源状态。

检测一张图片

下面的完整函数会启动 SDK、检测图片,并在成功或失败时释放资源。传入模型资源文件(如 Pikachu)和 JPEG、PNG 图片的实际路径即可。调用成功且返回 0,表示没有检测到人脸。

这段代码适合首次检查接入是否正确。实际应用中,运行环境与会话应跨帧复用:在工作队列的初始化阶段创建,在退出时统一释放。

展开完整的文件检测示例
Objective-C
#import <InspireFace/InspireFaceApple.h>

BOOL DetectFile(NSString *modelPath, NSString *imagePath,
                HInt32 *faceCount, NSError **error) {
    *faceCount = 0;
    if (![IFRuntime launchAtPath:modelPath error:error]) return NO;
    IFSession *session = nil;
    IFImageBitmap *bitmap = nil;
    IFImageStream *stream = nil;
    BOOL success = NO;
    do {
        session = [[IFSession alloc] initWithOptions:0
                                               mode:HF_DETECT_MODE_ALWAYS_DETECT
                                       maximumFaces:10
                                         pixelLevel:320
                                    framesPerSecond:-1
                                              error:error];
        if (!session) break;
        bitmap = [[IFImageBitmap alloc] initWithContentsOfFile:imagePath
                                                     channels:3 error:error];
        if (!bitmap) break;
        HFImageBitmapData pixels = {0};
        if (![bitmap getBorrowedData:&pixels error:error]) break;
        HFImageData input = {pixels.data, pixels.width, pixels.height,
                             HF_STREAM_BGR, HF_CAMERA_ROTATION_0};
        stream = [[IFImageStream alloc] initWithBorrowedData:input error:error];
        if (!stream) break;
        HFMultipleFaceData faces = {0};
        if (![session trackStream:stream borrowedResult:&faces error:error]) break;
        for (HInt32 i = 0; i < faces.detectedNum; ++i) {
            HFaceRect rect = faces.rects[i];
            NSLog(@"face %d: x=%d y=%d width=%d height=%d", i,
                  rect.x, rect.y, rect.width, rect.height);
        }
        *faceCount = faces.detectedNum;
        success = YES;
    } while (NO);
    [stream closeWithError:NULL];
    [bitmap closeWithError:NULL];
    [session closeWithError:NULL];
    [IFRuntime terminateWithError:NULL];
    return success;
}
Swift
import Foundation
import InspireFaceSwift

func detectFile(modelPath: String, imagePath: String) throws -> Int {
    try InspireFaceRuntime.launch(path: modelPath)
    defer { try? InspireFaceRuntime.terminate() }
    let session = try FaceSession(configuration: SessionConfiguration(
        detectionMode: .alwaysDetect, maximumFaces: 10, pixelLevel: 320))
    defer { try? session.close() }
    let bitmap = try ImageBitmap(contentsOfFile: imagePath, channels: 3)
    defer { try? bitmap.close() }
    return try bitmap.withUnsafeMutablePixels { bytes, pixels in
        try ImageStream.withBorrowedBytes(
            bytes, width: pixels.width, height: pixels.height, format: .bgr
        ) { stream in
            try session.withUnsafeFaces(in: stream) { faces in
                for (index, rect) in faces.rectangles.enumerated() {
                    print("face \(index): x=\(rect.x) y=\(rect.y) " +
                          "width=\(rect.width) height=\(rect.height)")
                }
                return faces.count
            }
        }
    }
}

使用 channels: 3 读取文件后,位图像素按 BGR 排列。示例直接借用位图存储,并在下一次跟踪前读完所有人脸结果,创建图像流时无需再复制一份像素。

模型路径与错误处理

将模型作为资源文件加入 App,再取得实际路径。如果模型由应用下载,先完成文件写入,再从应用自己的存储目录加载。模型与 Framework 分开提供;添加库文件不会同时安装模型。

Objective-C 方法失败时返回 NO 或 nil,可通过 NSError 获取原因;Swift 对应方法使用 throws。SDK 错误的 domain 为 IFErrorDomain,NSError.code 保留原生 HResult。判断本次调用是否成功应看返回值,不要依赖旧的 error 变量。

Objective-C
NSError *error = nil;
HInt32 count = 0;
if (!DetectFile(modelPath, imagePath, &count, &error)) {
    NSLog(@"%@ (%ld): %@", error.domain, (long)error.code, error.localizedDescription);
} else {
    NSLog(@"Detected %d faces", count);
}
Swift
do {
    let count = try detectFile(modelPath: modelPath, imagePath: imagePath)
    print("Detected \(count) faces")
} catch {
    let failure = error as NSError
    print("\(failure.domain) (\(failure.code)): \(failure.localizedDescription)")
}

像素缓冲区与借用输入

CVPixelBuffer 构造方法会保留并锁定缓冲区,直到图像流关闭或更换存储。它不会复制像素,也不会自动去掉行填充。

Pixel format直接输入的条件
BGRA / RGBA单平面,每行恰好 width × 4 字节。
8-bit gray单平面,每行恰好 width 字节。
NV12,full / video range宽高为偶数;Y、UV 每行均为 width 字节;UV 紧接在 width × height 个 Y 字节之后。

行末存在填充、NV12 平面不连续或格式不支持时,返回 HERR_INVALID_IMAGE_STREAM_PARAM。iOS 摄像头示例给出了带行填充 BGRA 的完整复制方法,macOS 也可以使用。

Objective-C
#import <InspireFace/InspireFaceApple.h>

BOOL CountPixelBuffer(IFSession *session, CVPixelBufferRef pixelBuffer,
                      HFRotation rotation, HInt32 *faceCount, NSError **error) {
    *faceCount = 0;
    IFImageStream *stream = [[IFImageStream alloc] initWithPixelBuffer:pixelBuffer
                                                               rotation:rotation
                                                                  error:error];
    if (!stream) return NO;
    HFMultipleFaceData faces = {0};
    BOOL success = [session trackStream:stream borrowedResult:&faces error:error];
    if (success) *faceCount = faces.detectedNum;
    [stream closeWithError:NULL];
    return success;
}
Swift
import CoreVideo
import InspireFaceSwift

func countPixelBuffer(session: FaceSession, pixelBuffer: CVPixelBuffer,
                      rotation: ImageRotation) throws -> Int {
    let stream = try ImageStream(pixelBuffer: pixelBuffer, rotation: rotation)
    defer { try? stream.close() }
    return try session.withUnsafeFaces(in: stream) { faces in
        faces.count
    }
}

initWithBorrowedData: / ImageStream(borrowing:) 只保存指针,不会持有分配这段内存的对象。在流关闭前保留原始存储,处理期间不要修改它。Swift 的 ImageStream.withBorrowedBytes 会在离开闭包前关闭图像流;跟踪及后续处理都应在闭包中完成。

结果有效期与释放

Result or resource有效期
Borrowed faces / tokens会话下一次跟踪、重置或关闭之前。
Borrowed embedding下一次特征提取或会话关闭之前。
Pipeline result pointers对应结果缓存更新或会话关闭之前。
Snapshot dataSnapshot 关闭之前,不受会话后续跟踪影响。
nativeHandle从包装对象借用,不能再通过 C API 单独释放。

Snapshot 的拷贝开销

Snapshot 更便于跨帧安全地保存结果,但复制会增加延时。单路摄像头顺序处理时,可以在下一帧开始前直接读完会话中的结果;需要跨越这个处理阶段保留结果时,再使用 Snapshot。

ARC 会在包装对象销毁时释放其持有的原生资源。需要及时归还摄像头缓冲区等场景,可显式调用 close。重复 close 会报无效句柄错误,并不是可反复调用的操作。先关闭抓拍对象,再关闭其父会话;所有会话释放后,再终止进程级运行环境。

队列与帧顺序

SDK 调用都是同步的。每个会话使用一个串行工作队列,跟踪、pipeline 和特征提取均在这个队列完成。Swift 的 unsafe-access 闭包限定结果的使用范围,但不会让会话支持并发访问。通过 nativeHandle 直接调用 C API,同样可能使已有指针失效。

摄像头每帧按 track → pipeline / 特征提取 → 复制 UI 所需数据 → 关闭流 的顺序处理完,再开始下一帧。只向主队列传递已复制的矩形、分数等值。运行环境和 FeatureHub 的全局变更也要串行处理,不要在其他工作队列推理时重载模型。

CoreML 运行模式

使用 CoreML 构建和 Apple 模型包,在创建会话前选择模式。这个设置不会为 CPU-only 构建开启 CoreML,也不会转换其中的模型。

Objective-C / C modeSwiftCoreML compute units
HF_APPLE_COREML_INFERENCE_MODE_CPU.cpu仅 CPU。
HF_APPLE_COREML_INFERENCE_MODE_GPU.gpuCPU 和 GPU。
HF_APPLE_COREML_INFERENCE_MODE_ANE.neuralEngine所有可用单元,由 CoreML 选择 Neural Engine、GPU 或 CPU。
Objective-C
#import <InspireFace/InspireFaceApple.h>

BOOL ConfigureCoreML(NSError **error) {
    return [IFRuntime setCoreMLInferenceMode:HF_APPLE_COREML_INFERENCE_MODE_ANE
                                      error:error];
}
Swift
import InspireFaceSwift

func configureCoreML() throws {
    try InspireFaceRuntime.setCoreMLInferenceMode(.neuralEngine)
}

.neuralEngine 并不强制每一步都在 Neural Engine 上执行,实际选择还取决于硬件和模型支持情况。与运行环境初始化放在同一个工作队列设置;改变影响模型的配置后,重新创建会话。对应的库见 iOS 构建和 macOS 构建。

继续使用其他功能

会话与跟踪、人脸识别、关键点、活体检测、可选分析、FeatureHub 和抓拍均提供 Objective-C、Swift 标签页。一帧中的后续操作应使用同一个图像流及本次检测得到的 token。

编辑此页
最近更新: 2026/9/28 20:17
贡献者: Jingyu
上一页
Android
下一页
iOS