InspireFaceInspireFace1.2.4.d3
Home
Get started
Get and build the SDK
Examples
  • English
  • 简体中文
GitHub
Home
Get started
Get and build the SDK
Examples
  • English
  • 简体中文
GitHub
  • Introduction
  • Get started
  • Features
  • Guides

    • Architecture and lifetime
    • Model packs
    • Image inputs and coordinates
    • Sessions and tracking
    • Face analysis
    • Recognition and FeatureHub
    • Facial landmarks
    • Liveness detection
    • Face capture
    • More API recipes
  • Language and platform

    • C API
    • C++
    • Python
    • Android
    • Apple
    • iOS
    • macOS
    • HarmonyOS
  • Get and build the SDK

    • Overview and downloads
    • Source and common options
    • Linux
    • macOS
    • Android
    • iOS
    • HarmonyOS
    • NVIDIA TensorRT
    • Rockchip NPU
    • Python packaging
  • Hardware deployment

    • ARM
    • NVIDIA TensorRT
    • Rockchip NPU
    • Python on Rockchip
  • InspireCV
  • Complete examples
  • API coverage
  • Performance
  • Image processing benchmarks
  • Troubleshooting

Face analysis

Quality, mask, attributes and expression are optional models. Enable only the outputs your application needs, then run the pipeline on detected faces from the same image. Read pose directly from the detection result.

Choose the outputs

OutputSession optionHow to use it
QualityHF_ENABLE_QUALITYRank candidate face images; combine with face size, pose and stability for capture.
MaskHF_ENABLE_MASK_DETECTRead a mask confidence score for each face.
AttributesHF_ENABLE_FACE_ATTRIBUTERead ageBracket, gender and race category indices.
ExpressionHF_ENABLE_FACE_EMOTIONRead the emotion category index.
PoseHF_ENABLE_FACE_POSERead roll, yaw and pitch from detection results.
RGB livenessHF_ENABLE_LIVENESSUse the liveness guide for scores and threshold evaluation.
Eye state / actionsHF_ENABLE_INTERACTIONUse the action example for consecutive frames and challenge state.

Use quality scores to rank images, and map attribute and expression indices to their labels. Expression describes the visible facial expression in the input image. Keep the label order matched to the model and wrapper version.

Start with one output

First enable quality alone and inspect a few clear and blurred inputs. Add the other models when their outputs are used by the application. Loading every option increases setup and per-frame work.

Conceptual overview of mask, expression, quality, pose and embedding outputs
Combine the selected outputs for one detected face. Quality returns a score; attributes and expression return category indices. Extract recognition embeddings with the feature-extraction API.

Read analysis results

Select an API below. These helpers process one still image using a newly created session, so they can be called from the platform's basic detection example. Launch the SDK and prepare the input first; C, C++, Apple, Android, HarmonyOS and Python cover that setup. In a video application, move session creation outside the frame loop.

C API

Pass a valid HFImageStream. The helper returns 1 for success, including zero faces, and 0 for an SDK or result-count failure. It releases its own session, leaving the caller's stream open.

C API — Complete analysis example
#include <stdio.h>
#include <inspireface.h>

/* Runtime is launched; the caller owns stream. Returns 1 on success. */
int analyze_frame(HFImageStream stream) {
    const HInt32 pipeline = HF_ENABLE_QUALITY | HF_ENABLE_MASK_DETECT |
                           HF_ENABLE_FACE_ATTRIBUTE | HF_ENABLE_FACE_EMOTION;
    HFSession session = NULL;
    HFMultipleFaceData faces = {0};
    HFFaceQualityConfidence quality = {0};
    HFFaceMaskConfidence masks = {0};
    HFFaceAttributeResult attributes = {0};
    HFFaceEmotionResult expressions = {0};
    int ok = 0;
    if (HFCreateInspireFaceSessionOptional(
            pipeline | HF_ENABLE_FACE_POSE, HF_DETECT_MODE_ALWAYS_DETECT,
            10, 320, -1, &session) != HSUCCEED) return 0;
    if (HFExecuteFaceTrack(session, stream, &faces) != HSUCCEED) goto done;
    if (faces.detectedNum == 0) { ok = 1; goto done; }
    if (HFMultipleFacePipelineProcessOptional(session, stream, &faces, pipeline)
            != HSUCCEED) goto done;
    if (HFGetFaceQualityConfidence(session, &quality) != HSUCCEED ||
        HFGetFaceMaskConfidence(session, &masks) != HSUCCEED ||
        HFGetFaceAttributeResult(session, &attributes) != HSUCCEED ||
        HFGetFaceEmotionResult(session, &expressions) != HSUCCEED) goto done;
    if (quality.num != faces.detectedNum || masks.num != faces.detectedNum ||
        attributes.num != faces.detectedNum || expressions.num != faces.detectedNum)
        goto done;
    for (HInt32 i = 0; i < faces.detectedNum; ++i) {
        printf("face=%d quality=%.3f mask=%.3f age=%d gender=%d race=%d emotion=%d\n",
               (int)i, quality.confidence[i], masks.confidence[i],
               (int)attributes.ageBracket[i], (int)attributes.gender[i],
               (int)attributes.race[i], (int)expressions.emotion[i]);
        printf("roll=%.2f yaw=%.2f pitch=%.2f\n",
               faces.angles.roll[i], faces.angles.yaw[i], faces.angles.pitch[i]);
    }
    ok = 1;
done:
    HFReleaseInspireFaceSession(session);
    return ok;
}
C++

Pass a FrameProcess whose source pixels remain valid. Result vectors follow the order of faces; the session is released automatically when the helper returns.

C++ — Complete analysis example
#include <iostream>
#include <vector>
#include <inspireface/inspireface.hpp>

// Runtime is launched; frame borrows the caller's image pixels.
bool AnalyzeFrame(inspirecv::FrameProcess& frame) {
    inspire::CustomPipelineParameter options;
    options.enable_face_quality = true;
    options.enable_mask_detect = true;
    options.enable_face_attribute = true;
    options.enable_face_emotion = true;
    options.enable_face_pose = true;
    auto session = inspire::Session::Create(
        inspire::DETECT_MODE_ALWAYS_DETECT, 10, options, 320);
    std::vector<inspire::FaceTrackWrap> faces;
    if (session.FaceDetectAndTrack(frame, faces) != 0) return false;
    if (faces.empty()) return true;
    if (session.MultipleFacePipelineProcess(frame, options, faces) != 0) return false;
    auto quality = session.GetFaceQualityConfidence();
    auto masks = session.GetFaceMaskConfidence();
    auto attributes = session.GetFaceAttributeResult();
    auto expressions = session.GetFaceEmotionResult();
    if (quality.size() != faces.size() || masks.size() != faces.size() ||
        attributes.size() != faces.size() || expressions.size() != faces.size())
        return false;
    for (size_t i = 0; i < faces.size(); ++i) {
        const auto& pose = faces[i].face3DAngle;
        std::cout << "quality=" << quality[i] << " mask=" << masks[i]
                  << " age=" << attributes[i].ageBracket
                  << " gender=" << attributes[i].gender
                  << " race=" << attributes[i].race
                  << " emotion=" << expressions[i].emotion
                  << " roll=" << pose.roll << " yaw=" << pose.yaw
                  << " pitch=" << pose.pitch << '\n';
    }
    return true;  // Session releases its resources when leaving scope.
}
Objective-C

After runtime launch, pass the still image as an open IFImageStream. This helper creates and closes its own session. BOOL/NSError report failures. Getters borrow session arrays; copy any scores or labels needed by a later UI callback before this function returns.

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

static BOOL AnalyzeFrame(IFImageStream *stream, NSError **error) {
    HInt32 pipeline = HF_ENABLE_QUALITY | HF_ENABLE_MASK_DETECT |
        HF_ENABLE_FACE_ATTRIBUTE | HF_ENABLE_FACE_EMOTION;
    IFSession *session = [[IFSession alloc] initWithOptions:pipeline | HF_ENABLE_FACE_POSE
        mode:HF_DETECT_MODE_ALWAYS_DETECT maximumFaces:10 pixelLevel:320
        framesPerSecond:-1 error:error];
    if (session == nil) return NO;
    @try {
        HFMultipleFaceData faces = {0};
        if (![session trackStream:stream borrowedResult:&faces error:error]) return NO;
        if (faces.detectedNum == 0) return YES;
        if (![session processStream:stream faces:&faces options:pipeline error:error]) return NO;
        HFFaceQualityConfidence quality = {0};
        HFFaceMaskConfidence masks = {0};
        HFFaceAttributeResult attributes = {0};
        HFFaceEmotionResult expressions = {0};
        if (![session getBorrowedQualityConfidence:&quality error:error] ||
            ![session getBorrowedMaskConfidence:&masks error:error] ||
            ![session getBorrowedAttributes:&attributes error:error] ||
            ![session getBorrowedEmotions:&expressions error:error]) return NO;
        if (quality.num != faces.detectedNum || masks.num != faces.detectedNum ||
            attributes.num != faces.detectedNum || expressions.num != faces.detectedNum)
            return IFCheck(HERR_INVALID_PARAM, error);
        for (HInt32 i = 0; i < faces.detectedNum; ++i) {
            NSLog(@"quality=%.3f mask=%.3f age=%d gender=%d race=%d emotion=%d",
                quality.confidence[i], masks.confidence[i], attributes.ageBracket[i],
                attributes.gender[i], attributes.race[i], expressions.emotion[i]);
            NSLog(@"roll=%.2f yaw=%.2f pitch=%.2f", faces.angles.roll[i],
                faces.angles.yaw[i], faces.angles.pitch[i]);
        }
        return YES;
    } @finally {
        [session closeWithError:NULL];
    }
}
Swift

Pass an open stream after runtime launch. The helper owns its temporary session; the caller owns the stream. It enables pose at session creation, runs only the requested pipeline models and reads every output before closing the session. Failures throw.

Swift — Complete example
import InspireFaceSwift

func analyzeFrame(stream: ImageStream) throws {
    let pipeline: FaceFeatures = [.quality, .mask, .attributes, .emotion]
    let session = try FaceSession(configuration: SessionConfiguration(
        features: pipeline.union(.pose), maximumFaces: 10, pixelLevel: 320))
    defer { try? session.close() }
    try session.withUnsafeFaces(in: stream) { borrowed in
        guard borrowed.count > 0 else { return }
        var faces = borrowed.cValue
        try session.process(stream, faces: &faces, options: Int32(pipeline.rawValue))
        var quality = HFFaceQualityConfidence()
        var masks = HFFaceMaskConfidence()
        var attributes = HFFaceAttributeResult()
        var expressions = HFFaceEmotionResult()
        try session.getBorrowedQualityConfidence(&quality)
        try session.getBorrowedMaskConfidence(&masks)
        try session.getBorrowedAttributes(&attributes)
        try session.getBorrowedEmotions(&expressions)
        guard quality.num == faces.detectedNum, masks.num == faces.detectedNum,
              attributes.num == faces.detectedNum, expressions.num == faces.detectedNum else {
            throw NSError(domain: IFErrorDomain, code: Int(HERR_INVALID_PARAM))
        }
        for i in 0..<borrowed.count {
            print("quality=\(quality.confidence[i]) mask=\(masks.confidence[i])")
            print("age=\(attributes.ageBracket[i]) gender=\(attributes.gender[i]) race=\(attributes.race[i])")
            print("emotion=\(expressions.emotion[i])")
            print("roll=\(borrowed.roll[i]) yaw=\(borrowed.yaw[i]) pitch=\(borrowed.pitch[i])")
        }
    }
}
Android

This example uses the 1.2.0 Java package for quality, mask and attributes. With that package and its matching native library, enabling quality also loads the pose model. Read pose from faces.angles[0]: this version provides a usable pose result for the first face only. Use the same Java/native pair when following this example.

Android — Complete analysis example
import com.insightface.sdk.inspireface.InspireFace;
import com.insightface.sdk.inspireface.base.*;

public final class AnalysisExample {
    // GlobalLaunch has succeeded; the caller keeps stream alive.
    public static void analyze(ImageStream stream) {
        CustomParameter options = InspireFace.CreateCustomParameter()
                .enableFaceQuality(true)
                .enableMaskDetect(true)
                .enableFaceAttribute(true);
        Session session = InspireFace.CreateSession(
                options, InspireFace.DETECT_MODE_ALWAYS_DETECT, 10, 320, -1);
        if (session == null || session.handle == 0L)
            throw new IllegalStateException("Cannot create session");
        try {
            MultipleFaceData faces = InspireFace.ExecuteFaceTrack(session, stream);
            if (faces == null) throw new IllegalStateException("Detection failed");
            if (faces.detectedNum == 0) return;
            if (!InspireFace.MultipleFacePipelineProcess(session, stream, faces, options))
                throw new IllegalStateException("Pipeline failed");
            FaceQualityConfidence quality = InspireFace.GetFaceQualityConfidence(session);
            FaceMaskConfidence masks = InspireFace.GetFaceMaskConfidence(session);
            FaceAttributeResult attributes = InspireFace.GetFaceAttributeResult(session);
            if (quality == null || masks == null || attributes == null ||
                    quality.num != faces.detectedNum || masks.num != faces.detectedNum ||
                    attributes.num != faces.detectedNum)
                throw new IllegalStateException("Incomplete pipeline result");
            for (int i = 0; i < faces.detectedNum; ++i) {
                System.out.println("quality=" + quality.confidence[i]
                        + " mask=" + masks.confidence[i]
                        + " age=" + attributes.ageBracket[i]
                        + " gender=" + attributes.gender[i]
                        + " race=" + attributes.race[i]);
                // The 1.2.0 JNI has a multi-face pose-copy bug; only read face 0.
                if (i == 0 && faces.angles != null && faces.angles.length > 0 && faces.angles[0] != null) {
                    FaceEulerAngle pose = faces.angles[i];
                    System.out.println("roll=" + pose.roll + " yaw=" + pose.yaw
                            + " pitch=" + pose.pitch);
                }
            }
        } finally {
            InspireFace.ReleaseSession(session);
        }
    }
}
HarmonyOS

Launch the SDK first, then pass an open ImageStream. The helper creates and closes its session; the caller closes the stream after use. Pipeline arrays follow faces.faces order, and pose is read from each tracked face.

HarmonyOS — Complete analysis example
import { DetectMode, Feature, ImageStream, Session }
  from '@hyperinspire/inspireface';

function analyzeFrame(stream: ImageStream): void {
  const pipeline = Feature.QUALITY | Feature.MASK_DETECT |
    Feature.FACE_ATTRIBUTE | Feature.FACE_EMOTION;
  const session = new Session({
    featureMask: pipeline | Feature.FACE_POSE,
    detectMode: DetectMode.ALWAYS_DETECT,
    maxFaces: 10,
    detectPixelLevel: 320
  });
  try {
    const faces = session.track(stream);
    try {
      if (faces.detectedNum === 0) return;
      const result = session.processPipeline(stream, faces, pipeline);
      for (let i = 0; i < faces.detectedNum; ++i) {
        const face = faces.faces[i];
        console.info(`quality=${result.qualityConfidence[i]} mask=${result.maskConfidence[i]}`);
        console.info(`age=${result.ageBracket[i]} gender=${result.gender[i]} race=${result.race[i]}`);
        console.info(`emotion=${result.emotion[i]}`);
        console.info(`roll=${face.roll} yaw=${face.yaw} pitch=${face.pitch}`);
      }
    } finally {
      session.releaseFaceResult(faces);
    }
  } finally {
    session.close();
  }
}
Python

Use the 1.2.4 source wrapper with its matching native library for the context manager and auto_launch=False. Supply a BGR uint8 array. Native failures raise an exception; an image with no faces returns an empty list.

Python — Complete analysis example
import inspireface as isf


def analyze_frame(image):
    # launch(resource_path=...) has succeeded; image is a BGR uint8 array.
    pipeline = (isf.HF_ENABLE_QUALITY | isf.HF_ENABLE_MASK_DETECT |
                isf.HF_ENABLE_FACE_ATTRIBUTE | isf.HF_ENABLE_FACE_EMOTION)
    with isf.InspireFaceSession(
        pipeline | isf.HF_ENABLE_FACE_POSE,
        isf.HF_DETECT_MODE_ALWAYS_DETECT,
        max_detect_num=10, detect_pixel_level=320, auto_launch=False,
    ) as session:
        faces = session.face_detection(image)
        results = session.face_pipeline(image, faces, pipeline) if faces else []
        if len(results) != len(faces):
            raise RuntimeError("Incomplete pipeline result")
        for face, result in zip(faces, results):
            print("quality=", result.quality_confidence,
                  "mask=", result.mask_confidence,
                  "age=", result.age_bracket,
                  "gender=", result.gender,
                  "race=", result.race,
                  "emotion=", result.emotion)
            print("roll=", face.roll, "yaw=", face.yaw, "pitch=", face.pitch)
        return results

Interpret the outputs

OutputMeaning and checks
QualityHigher scores favor a usable face image. Evaluate your input conditions before choosing a cutoff; size, sharpness, brightness and pose remain separate checks.
MaskA score for mask presence. Compare the score with a threshold evaluated on your intended cameras.
AttributesInteger category indices. Check the index range, then map each index to its label.
ExpressionIndex order: Neutral, Happy, Sad, Surprise, Fear, Disgust, Anger.
PoseRoll, yaw and pitch angles. In C/C++/Python, enable HF_ENABLE_FACE_POSE or its C++ option before reading these angles. Objective-C also uses HF_ENABLE_FACE_POSE; Swift uses .pose in FaceFeatures. HarmonyOS uses Feature.FACE_POSE.

The complete attribute label arrays are shown in the Python analysis reference. Keep the input pixels unchanged until the pipeline finishes, then draw or reuse the buffer. C, Objective-C and Swift getter arrays are borrowed from the session; copy values you need after the next pipeline call or after closing the session. C++ vectors and Python results have their own storage.

When upgrading Android, update the Java package and its matching JNI/native library together. The API index lists the analysis outputs available in each interface.

Use analysis in a capture flow

For enrollment, first require one intended face, then check size and position, followed by quality and pose. Use face capture when these checks should hold over time and the application needs a selected frame. Copy or retain that frame before extracting its embedding.

For a preview UI, copy the scores and geometry you need, then release frame resources. Convert the geometry with the preview's crop, scale and mirror transform; see image coordinates.

Edit this page
Last Updated:: 9/28/26, 8:17 PM
Contributors: Jingyu
Prev
Sessions and tracking
Next
Recognition and FeatureHub