JCV AR SDK iOS 統合ドキュメント

目次

1.統合の準備

1.1 ライブラリファイルのインポート

1.2 リンクライブラリの追加

1.3 ビットコードの無効化

1.4 ヘッダーファイルのインポート

2.SDK のアクティベーション

2.1 ライセンス認証

2.2 アクティベーションコードの認証

3.SDK API の使用

3.1 SDK ハンドルの初期化

3.2 テクスチャの取得

3.3 テクスチャの前処理

3.4 フレーム処理フロー

3.5 SDK ハンドルの解放

4.お客様によるカスタマイズ

4.1 顔検知

4.2 美化

4.3 スタンプ

5.統合に関する考慮事項

6.検知のレンダリングの最適化

※一部コードが資料の都合上途切れている部分があります。サンプルコードと同じ内容が記載されておりますので、該当のサンプルコードにてご確認お願い致します。

1 統合の準備

1.1 ライブラリファイルのインポート

JCV AR iOS SDK のヘッダーファイル、静的ライブラリファイル (.a)、ライセンスファイル (.lic)、およびモデルファイル (.model) をインポートします (下図を参照)。

1.2 リンクライブラリの追加

SDK の stdc ++ を使用します。[ターゲット]、[ビルド設定]、[リンク]、[その他のリンカーフラグ] の順にクリックして、-lstdc ++ を追加します。

1.3 ビットコードの無効化

SDK はビットコードをサポートしていません。[ターゲット]、[ビルド設定]、[ビルドオプション] の順にクリックし、[ビットコインの有効化] を [いいえ] に設定します。

1.4 ヘッダーファイルのインポート

必要に応じて、必要なヘッダーファイルをインポートします。

#import "st_mobile_human_action.h" //顔、眼球、ジェスチャ、ボディ、前景と背景などの検知
#import "st_mobile_beautify.h" //美化
#import "st_mobile_filter.h" //フィルター
#import "st_mobile_common.h" //SDK の共通パラメーター定義
#import "st_mobile_face_attribute.h" //顔属性の検知
#import "st_mobile_license.h" //ライセンスアクティベーション
#import "st_mobile_object.h" //一般的なオブジェクトトラッキング
#import "st_mobile_sticker.h" //スタンプ
#import "st_mobile_sticker_module.h" //スタンプモジュール関連
#import "st_mobile_sticker_transition.h"//スタンプ遷移関連

2 SDK のアクティベーション

2.1 ライセンス認証

1.SDK は、ライセンスファイルに従って、アルゴリズムライブラリの権限をチェックします。通常、アクティベーション完了後にのみ、SDK の機能を使用できます。

2.認証方法には、オンライン認証とオフライン認証があります。オンライン認証では、サーバーにホストされているライセンス情報を取得する必要があり、オフライン認証では、ローカルライセンスを使用して検出することができます。 ※基本的にオフライン認証の提供になりますため、オンライン認証が必要な場合は別途ご連絡ください。

2.2 アクティベーションコードの認証

(1)ライセンスファイルのコンテンツを読み込みます。

(2)ローカルコンピューターに保存されたアクティベーションコードを取得します。

(3)利用可能なアクティベーションコードがない場合は、生成します。

(4)checkActiveCode * コマンドを直接実行して、アクティベーションコードが有効であるかどうか確認します。

(5)確認に失敗した場合は、別のアクティベーションコードを生成します。

(6)生成に失敗した場合は、エラーメッセージが表示されます。成功すると、新しいアクティベーションコードが保存され、成功したことを示すメッセージが表示されます。

// SenseME.lic ファイルコンテンツを確認します
NSString *strLicensePath = [[NSBundle mainBundle] 
    pathForResource:@"SENSEME" ofType:@"lic"];
NSData *dataLicense = [NSData dataWithContentsOfFile:strLicensePath];
NSString *strKeySHA1 = @"SENSEME";
NSString *strKeyActiveCode = @"ACTIVE_CODE";
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *strStoredSHA1 = [userDefaults objectForKey:strKeySHA1];
NSString *strLicenseSHA1 = [self getSHA1StringWithData:dataLicense];
... ...

// 既存のアクティベーションコードを使用できるか確認します (2 種類の方法があります)
// ファイルを使用
iRet = st_mobile_check_activecode(
    strLicensePath.UTF8String,
    (const char *)[activeCodeData bytes]
);
//バッファーを使用
NSData *licenseData = [NSData dataWithContentsOfFile:strLicensePath];
iRet = st_mobile_check_activecode_from_buffer(
    [licenseData bytes],
    (int) [licenseData length],
    [activeCodeData bytes]
);

// 確認に失敗した場合は、新しいコードを生成してローカルのアクティベーションコードを更
// 新します。同様に、2 種類の方法を提供します。
// ファイルを使用
iRet = st_mobile_generate_activecode(
    strLicensePath.UTF8String,
    active_code,
    &active_code_len
);
//バッファーを使用
NSData *licenseData = [NSData dataWithContentsOfFile:strLicensePath];
iRet = st_mobile_generate_activecode_from_buffer(
    [licenseData bytes],
    (int)[licenseData length],
    active_code,
    &active_code_len
);
//ローカルに保存されたアクティベーションコードを更新します
NSData *activeCodeData = [NSData dataWithBytes:active_code
    length:active_code_len];
[userDefaults setObject:activeCodeData forKey:strKeyActiveCode];
[userDefaults setObject:strLicenseSHA1 forKey:strKeySHA1];
[userDefaults synchronize];

3 SDK API の使用

3.1 SDK ハンドルの初期化

1.HumanAction の初期化

//HumanAction ハンドルを初期化します
//モデルのパスを取得します
NSString *strModelPath = [[NSBundle mainBundle] 
    pathForResource:@"M_SenseME_Action" ofType:@"model"];
//HumanAction ハンドルを作成します
//注記: 本 SDK の API では、2 種類の HumanAction ハンドル作成方法を提供します。
//検知対象がビデオである場合は ST_MOBILE_HUMAN_ACTION_DEFAULT_CONFIG_CREATE 
//に設定し、画像である場合は ST_MOBILE_HUMAN_ACTION_DEFAULT_CONFIG_IMAGE に
//設定します。詳細については、st_mobile_human_action.h ファイルをご参照ください。
//ハンドル作成用の config コマンドと、人間の動作を検知するための config コマンドを
//区別するように注意してください。動作を検知するための config コマンドは、config 
//コマンドを使用してハンドルを作成できる場合にのみ有効になります。
iRet = st_mobile_human_action_create(
    strModelPath.UTF8String, 
    ST_MOBILE_HUMAN_ACTION_DEFAULT_CONFIG_VIDEO, 
    &_hDetector
);

//他のモデルをロードして、st_mobile_human_action_add_sub_model を呼び出します
NSString *strEyeCenter = [[NSBundle mainBundle]
    pathForResource:@"xx" ofType:@"model"];
iRet = st_mobile_human_action_add_sub_model(
    _hDetector, 
    strEyeCenter.UTF8String
);

//アバタースタンプは、目の輪郭点モデルと専用のアバターモデル (avatar_core.model) 
// を一緒に読み込む必要があることに注意してください

//モデルを削除します。必要に応じて、動的にモデルを追加、または削除できます。
//詳細についてはサンプルをご参照ください。
iRet = st_mobile_human_action_remove_model_by_config(
    _hDetector, 
    ST_MOBILE_ENABLE_FACE_EXTRA_DETECT
);

//人間の動作用のパラメーターを設定します。2 フレームごとに 1 回ジェスチャを検知するよう
//に設定しています。必要に応じて設定できます。
//他のパラメーターに関しては、st_mobile_human_action.h ファイルをご参照ください。
iRet = st_mobile_human_action_setparam(
    _hDetector,
    ST_HUMAN_ACTION_PARAM_HAND_PROCESS_INTERVAL, 
    2
);

2.顔属性 API ハンドルの初期化

//顔属性ハンドルを初期化します
//顔属性モデルのパスを取得します
NSString *strAttriModelPath = [[NSBundle mainBundle] 
    pathForResource:@"face_attribute" ofType:@"model"];
//顔属性ハンドルを作成します
iRet = st_mobile_face_attribute_create(
    strAttriModelPath.UTF8String, 
    &_hAttribute
);

3.美化 API ハンドルの初期化

iRet = st_mobile_beautify_create(&_hBeautify);

//美化 API ハンドルを作成後、関連するパラメーターを設定できます
//美白の強度を設定します。値の範囲: [0, 1.0]、デフォルト値: 0.02
//美白を適用しない場合は 0.0。
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_WHITEN_STRENGTH, 
    self.fWhitenStrength
);
//デフォルトの赤みの強度を設定します。値の範囲: [0, 1.0]、デフォルト値: 0.36
//赤みなしの場合は 0.0。
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_REDDEN_STRENGTH, 
    self.fReddenStrength
);
//デフォルトの肌補正の強度を設定します。値の範囲: [0, 1.0]、デフォルト値: 0.74
//補正しない場合は 0.0。
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_SMOOTH_STRENGTH, 
    self.fSmoothStrength
);
//ハイライト除去の強度: [0, 1.0]、デフォルト値: 1、除去しない場合は 0.0。
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_DEHIGHLIGHT_STRENGTH, 
    self.fDehighlightStrength
);

//デフォルトの目の拡大強度を設定します。値の範囲: [0, 1.0]、デフォルト値: 0.13
//拡大しない場合は 0.0。
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_ENLARGE_EYE_RATIO, 
    self.fEnlargeEyeStrength
);
//顔の縮小強度を設定します。値の範囲: [0, 1.0]、デフォルト値: 0.11
//縮小しない場合は 0.0。
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_SHRINK_FACE_RATIO, 
    self.fShrinkFaceStrength
);
//顎の縮小強度を設定します。値の範囲: [0, 1.0]、デフォルト値: 0.10
//縮小しない場合は 0.0。
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_SHRINK_JAW_RATIO, 
    self.fShrinkJawStrength
);
//顔の幅を狭める割合を設定します。値の範囲: [0, 1.0]、デフォルト値: 0.0
//狭めない場合は 0.0。
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_NARROW_FACE_RATIO, 
    self.fShrinkJawStrength
);

///SDK の新しい 3D 美化機能パラメータの設定は以下のとおりです
///鼻を狭める割合: [0, 1.0]、デフォルト値: 0.0、狭めない場合は 0.0
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_NARROW_NOSE_RATIO, 
    self.fNarrowNoseStrength
);
///鼻の長さの割合: [-1, 1]、デフォルト値: 0.0
//短くする場合は [-1, 0] で長くする場合は [0, 1]
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_LENGTH_NOSE_RATIO, 
    self.fLongNoseStrength
);
///顎の長さの割合: [-1, 1]、デフォルト値: 0.0
//短くする場合は [-1, 0] で長くする場合は [0, 1]
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_LENGTH_CHIN_RATIO, 
    self.fChinStrength
);
///口の大きさの割合: [-1, 1]、デフォルト値: 0.0
//拡大する場合は [-1, 0] で縮小する場合は  [0, 1]
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_SIZE_MOUTH_RATIO, 
    self.fMouthStrength
);
///人中の長さの割合: [-1, 1]、デフォルト値: 0.0
//長くする場合は [-1, 0] で短くする場合は [0, 1]
st_mobile_beautify_setparam(
    _hBeautify,
    ST_BEAUTIFY_LENGTH_PHILTRUM_RATIO,
    self.fPhiltrumStrength
);
///生え際の高さの割合: [-1, 1]、デフォルト値: 0.0
//低くする場合は [-1, 0] で高くする場合は [0, 1]
st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_LOW_HAIRLINE_RATIO, 
    self.fHairLineStrength
);

//コントラストを設定します。値の範囲: [0, 1.0]、デフォルト値: 0.0。
iRet = st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_CONTRAST_STRENGTH, 
    self.fContrastStrength
);
//彩度を設定します。値の範囲: [0, 1.0]、デフォルト値: 0.0。
iRet = st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_SATURATION_STRENGTH, 
    self.fSaturationStrength
);
 //シャープネスパラメーター
iRet = st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_SHARPEN_STRENGTH, 
    self.fSharpenStrength
);

//SDK の美化機能パラメーターは以下のように設定できます
//ボディの美化パラメーターを設定します。値の範囲: [0, + ∞)
//デフォルト値: 1.0 (美化を行わない)。
iRet = st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_BODY_WHOLE_RATIO, 
    self.fBeautifyBodyRatio
);
//頭の美化パラメーターを設定します。値の範囲: [0, + ∞)
//デフォルト値: 1.0 (美化を行わない)。
iRet = st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_BODY_HEAD_RATIO, 
    self.fBeautifyHeadRatio
);
//肩の美化パラメーターを設定します。値の範囲: [0, + ∞)
//デフォルト値: 1.0 (美化を行わない)。
iRet = st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_BODY_SHOULDER_RATIO, 
    self.fBeautifyShouldersRatio
);
//ウエストの美化パラメーターを設定します。値の範囲: [0, + ∞)
//デフォルト値: 1.0 (美化を行わない)。
iRet = st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_BODY_WAIST_RATIO, 
    self.fBeautifyWaistRatio
);
//腰の美化パラメーターを設定します。値の範囲: [0, + ∞)
//デフォルト値: 1.0 (美化を行わない)。
iRet = st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_BODY_HIP_RATIO, 
    self.fBeautifyHipsRatio
);
//足の美化パラメーターを設定します。値の範囲: [0, + ∞)
//デフォルト値: 1.0 (美化を行わない)。
iRet = st_mobile_beautify_setparam(
    _hBeautify, 
    ST_BEAUTIFY_BODY_LEG_RATIO, 
    self.fBeautifyLegsRatio
);

4.スタンプ API ハンドルの初期化

//スタンプハンドルを初期化します
iRet = st_mobile_sticker_create(&_hSticker);

//素材の読み込みを待つかどうかを指定します。
//フレームや 3D ショートビデオなどのモデルが、
//読み込みおよびレンダリングされるのを待つ場合に使用します。
//初期化後、ハンドルを呼び出します。このメソッドは、
//サンプルの画像を処理するために使用されています。
iRet = st_mobile_sticker_set_param_bool(
    _hSticker, 
    -1, 
    ST_STICKER_PARAM_WAIT_MATERIAL_LOADED_BOOL, 
    true
);

//音楽スタンプを使用するには、コールバックを設定します
st_mobile_sticker_set_param_ptr(
    _hSticker, 
    -1, 
    ST_STICKER_PARAM_SOUND_LOAD_FUNC_PTR, 
    load_sound
);
st_mobile_sticker_set_param_ptr(
    _hSticker, 
    -1, 
    ST_STICKER_PARAM_SOUND_PLAY_FUNC_PTR, 
    play_sound
);
st_mobile_sticker_set_param_ptr(
    _hSticker, 
    -1, 
    ST_STICKER_PARAM_SOUND_STOP_FUNC_PTR, 
    stop_sound
);

//音楽を読み込みます
void load_sound(void* sound, const char* sound_name, int length) {
    if ([messageManager.delegate respondsToSelector:@selector(loadSound:name:)]) {
        NSData *soundData = [NSData dataWithBytes:sound length:length];
        NSString *strName = [NSString stringWithUTF8String:sound_name];
        [messageManager.delegate loadSound:soundData name:strName];
    }
}

//音楽を再生します
void play_sound(const char* sound_name, int loop) {
    if ([messageManager.delegate respondsToSelector:@selector(playSound:loop:)]) {
        NSString *strName = [NSString stringWithUTF8String:sound_name];
        [messageManager.delegate playSound:strName loop:loop];
    }
}

//再生を停止します
void stop_sound(const char* sound_name) {
    if ([messageManager.delegate respondsToSelector:@selector(stopSound:)]) {
        NSString *strName = [NSString stringWithUTF8String:sound_name];
        [messageManager.delegate stopSound:strName];
    }
}

5.フィルター API ハンドルの初期化

//フィルターハンドルを初期化します
iRet = st_mobile_gl_filter_create(&_hFilter);

6.一般的なオブジェクト API ハンドルの初期化

//スタンプハンドルを初期化します
st_result_t iRet = st_mobile_object_tracker_create(&_hTracker);

SDK ハンドルの初期化が終了しました。詳細については、公式のデモをご参照ください。 注記: 本 SDK は、オブジェクトの美化およびフィルター化の統一されたコンテキスト内にある必要があります。次のように設定します。

if ([EAGLContext currentContext] != self.glContext) {
    [EAGLContext setCurrentContext:self.glContext];
}

注記: コンテキストが異なると、エラーが発生する可能性があるため、OpenGL コンテキストが同じであることを確認してください。

3.2 テクスチャの取得

1.STCamera の使用

解像度や出力フォーマットなど、多数のパラメーターを簡単に設定できます。詳細については、STCamera.h ファイルをご参照ください。

self.stCamera = [[STCamera alloc] 
    initWithDevicePosition:AVCaptureDevicePositionFront //フロントまたはリアポジション
    sessionPresset:self.currentSessionPreset           //解像度
    fps:30                                             //フレームレート
    needYuvOutput:NO];                                 //出力データ形式
self.stCamera.delegate = self;                     //カメラデータのプロキシを設定します

2.STCamera からテクスチャを取得

//STCameraDelegate からフレームデータを取得し、テクスチャに変換します
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    //フレームごとに画像データを取得します
    CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
    //フレームのデータをロックします
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    //ビデオデータのアドレスを取得します
    unsigined char* pBGRAImageIn = (unsingned char *)CVPixelBufferGetBaseAddress(pixelBuffer);
    //ビデオデータの幅と高さを取得します
    int iBytesPerRow = (int)CVPixelBufferGetBytesPerRow(pixelBuffer);
    int iWidth = (int)CVPixelBufferGetWidth(pixelBuffer);
    int iHeight = (int)CVPixelBufferGetHeight(pixelBuffer);
    //pixelBuffer とテクスチャを関連付けます
    CVReturn cvRet = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
        _cvTextureCache,//テクスチャのキャッシュ
        pixelBuffer,//出力ビデオデータバッファーは NULL
        GL_TEXTURE_2D,//2D テクスチャ
        GL_RGBA,//色の形式
        self.imageWidth,//画像の幅
        self.imageHeight,//画像の高さ
        GL_BGRA,//iOS 形式
        GL_UNSIGNED_BYTE,
        0,
        &_cvTextureOrigin//出力するテクスチャ
    );

    if (!_cvTextureOrigin || kCVReturnSuccess != cvRet) {
        NSLog(@"CVOpenGLESTextureCacheCreateTextureFromImage %d" , cvRet);

        return NO;
    }

    //テクスチャを取得します
    _textureOriginInput = CVOpenGLESTextureGetName(_cvTextureOrigin);
    //テクスチャをバインドします
    glBindTexture(GL_TEXTURE_2D , _textureOriginInput);
    //テクスチャフィルター機能は、テクスチャ画像領域からフレームバッファー画像領域に画像をマッピングします (画像をマッピングするには、テクスチャ画像を再構築し、ポリゴンに適用された画像を変形します)。テクスチャピクセルをピクセルにマッピングする方法を指定するには、glTexParmeteri() 関数を有効にします。
    //GL_TEXTURE_2D: 2D テクスチャの処理
    //GL_TEXTURE_MIN_FILTER: 縮小およびフィルター
    //GL_TEXUTRE_MAG_FILTER: 拡大およびフィルター
    //GL_TEXTURE_WRAP_S: S 方向でのスタンプモード。テクスチャ座標は st、物理座標は xy。
    //GL_TEXTURE_WRAP_T: T 方向でのスタンプモード
    //GL_CLAMP_TO_EDGE: テクスチャ座標の値の範囲は [0,1] です。特定の方向の値が 0 未満の場合は、0 に設定します。値が 1 より大きい場合は、1 に設定します。
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//2D テクスチャを縮小およびフィルターし、真ん中のテクスチャに最も近い 4 つのテクスチャ要素の加重平均を返します。
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//2D テクスチャを拡大およびフィルターし、真ん中のテクスチャに最も近い 4 つのテクスチャ要素の加重平均を返します。
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);//2D テクスチャを S 方向でフィルターします。テクスチャ座標の値の範囲は [0,1] です。S 方向の値が 0 未満の場合は、0 に設定します。値が 1 より大きい場合は、1 に設定します。
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);//2D テクスチャを T 方向でフィルタリングします。テクスチャ座標の値の範囲は [0,1] です。T 方向の値が 0 未満の場合は、0 に設定します。値が 1 より大きい場合は、1 に設定します。
    glBindTexture(GL_TEXTURE_2D, 0);//デフォルトのテクスチャをバインドし、以前にバインドされたテクスチャを無効にします。
};

3.3 テクスチャの前処理

//テクスチャを初期化します
- (void)initResultTexture
{
    //美化のためのテクスチャを作成します
    [self setupTextureWithPixelBuffer:&_cvBeautifyBuffer w:self.imageWidth h:self.imageHeight glTexture:&_textureBeautifyOutput cvTexture:&_cvTextureBeautify];
    //スタンプテクスチャを作成します
    [self setupTextureWithPixelBuffer:&_cvStickerBuffer w:self.imageWidth h:self.imageHeight glTexture:&__textureStickerOutput cvTexture:&_cvTextureSticker];
    //フィルターテクスチャを作成します
    [self setupTextureWithPixelBuffer:&_cvFilterBuffer w:self.imageWidth h:self.imageHeight glTexture:&_textureFilterOutput cvTexture:&_cvTextureFilter];
}

- (BOOL)setupTextureWithPixelBuffer:(CVPixelBufferRef *)pixelBufferOut w:(int)iWidth h:(int)iHeight glTexture:(GLuint *)glTexture cvTexture:(CVOpenGLESTextureRef *)cvTexture
{
    //配列を作成します
    CFDictionaryRef empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBack, &kCFTypeDictionaryValueCallBacks);
    //動的配列を作成します
    CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks );
    //値を設定します
    CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
    //pixelBuffer を作成します
    CVReturn cvRet = CVPixelBufferCreate(kCFAllocatorDefault, iWidth, iHeight, kCVPixelFormatType_32BGRA, attrs, pixelBufferOut);
    if(kCVRetrunSuccess != cvRet){
        NSLog(@"CVPixelBufferCreate %d", cvRet);
    }
    //バッファーとテクスチャを関連付けます
    cvRet = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _cvTextureCache, *pixelBufferOut, NULL, GL_TEXTREU_2D, GL_RGBA, self.imageWidth, self.imageHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0, cvTexture);
    if(kCVReturnSuccess != cvRet){
        NSLog(@"CVOpenGLESTextureCacheCreateTextureFromImage %d", cvRet);
        returen NO;
    }
    //リソースを解放します
    CFRelease(attrs);
    CFRelease(empty);
    //テクスチャのポインターを取得します
    *glTexture = CVOpenGLESTextureGetName(*cvTexture);
    //テクスチャをバインドします
    glBindTexture(CVOpenGLESTextureGetTarget(*cvTexture), *glTexture);
    //テクスチャ属性を設定します
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WARP_T, GL_CLAMP_TO_EDGE);
    glBindTexture(GL_TEXTURE_2D, 0);
}

3.4 フレーム処理フロー

1.HumanAction API の使用

//cofig コマンドで設定された顔、顔の動き、表情、ジェスチャ、前景と背景のセグメンテーション、体、および体の動きの特徴点を検知します。
//config コマンドを利用可能な場合にのみ、データが検知結果に表示されます。
//検知結果の構造は、st_mobile_human_action.h ファイルで定義されています。詳細に関しては、サンプルをご参照ください。
iRet = st_mobile_human_action_detect(_hDetector,//顔検知ハンドル
    pBGRAImageIn,//出力データのアドレス
    ST_PIX_FMT_BGRA8888,//画像形式
    iWidth,//幅
    iHeight,//高さ
    iBytesPerRow,//iWidth * 4 (BGRA の 4 チャンネル)
    stMobileRotate,//回転角度
    iConfig,//動きの検知
    &detectResult//検知結果
);

回転角度: 写真を撮り、携帯電話に対して回転させて、顔を検知できる方向を確認します。これが顔を検知する際の角度です。詳細については、enum パラメーターをご参照ください。

typedef enum {
    ST_CLOCKWISE_ROTATE_0 = 0,  ///< 正面からの顔認証を維持するために、画像を回転させる必要はありません。
    ST_CLOCKWISE_ROTATE_90 = 1, ///< 正面からの顔認証を維持するために、画像を 90 度回転する必要があります。
    ST_CLOCKWISE_ROTATE_180 = 2,///< 正面からの顔認証を維持するために、画像を 180 度回転する必要があります。
    ST_CLOCKWISE_ROTATE_270 = 3 ///< 正面からの顔認証を維持するために、画像を 270 度回転する必要があります。
} st_rotate_type;

2.表情 API の使用

表情に関する API は、動作検知の関数の結果を必要とします。したがって、次のように 動作検知の関数の後に呼び出されます。

//表情の検知結果。各要素により示される表情は、ST_MOBILE_EXPRESSION 関数の列挙で定義されます。
bool expressionResult[128] = {0};
st_result_t iRet = st_mobile_get_expression(&detectResult, stMobileRotate, NO, expressionResult);

//表情のしきい値を設定します。デフォルトのしきい値を推奨します。手動で設定する必要はありません。
iRet = st_mobile_set_expression_threshold(ST_MOBILE_EXPRESSION_HEAD_NORMAL, 0.5);

3.顔属性 API の使用

FaceAttribute API は、HumanAction パラメーターからパラメーターを入力します。したがって、顔属性 API の実行前に、HumanAction パラメーターを設定する必要があります。

iRet = st_mobile_face_attribute_detect(_hAttribute,
    pBGRAImageIn,
    ST_PIX_FMT_BGRA8888,
    iWidth,
    iHeight,
    iBytesPerRow,
    _pFacesDetection,
    1, //デモ用に、最初に検知した 1 つの顔の属性を取得します。
    &pAttrArray);

4.美化 API の使用

同様に、目の拡大や顎の縮小などの美化 API の関数も、HumanAction に由来します。

//テクスチャを美化します
iRet = st_mobile_beautify_process_texture(_hBeautify,
                                          _textureOriginInput,
                                          iWidth,
                                          iHeight,
                                          &detectResult,
                                          _textureBeautifyOutput,
                                          &processedResult);

detectResult 項目は、人間の動作の検知結果用で、processedResult 項目は目の拡大や顎の縮小などの美化を行った後の顔特徴点用です (processResult 項目は、上位層で手動で割り当てられます。detectResult 項目と同じか、detectResult 項目から取り込まれたものです)。

美化パラメーターの設定:

//美化パラメーターを設定します
iRet = st_mobile_beautify_setparam(_hBeautify, ST_BEAUTIFY_REDDEN_STRENGTH, 0.36f);//赤みの強度、値の範囲: [0, 1.0]、赤みなしの場合は 0.0

5.スタンプ API の使用

スタンプには、主に 2D スタンプ、3D スタンプ、顔変形スタンプ、前面と背面の背景スタンプ、ジェスチャスタンプ、音楽スタンプ、メイクスタンプ、パーティクルアニメーションスタンプ、アバタースタンプ、スカイボックススタンプが含まれます。スタンプ機能を実装するには、顔情報が利用可能であることを確認し、事前に HumanAction を実行します。

スタンプのレンダリング

iRet = st_mobile_sticker_process_texture(_hSticker ,//スタンプのハンドル
                                         _textureOriginInput,//入力テクスチャ
                                         iWidth,//幅
                                         iHeight,//高さ
                                         stMobileRotate,//回転角度
                                         ST_CLOCKWISE_ROTATE_0,//前景スタンプの回転角度
                                         false,//ミラーリングするかどうか
                                         &detectResult,//動作の検知結果
                                         &inputEvent, //特定のハードウェアパラメーターおよびカスタムイベント                               
                                         _textureStickerOutput//処理された画像データ);

注記:

1.本 API は、前景スタンプの回転角度を追加します。必要に応じて使用できます。

2.スカイボックススタンプを使用するには、カメラのクォータニオンを入力してください。スカイボックスの inputEvent 項目が必要ない場合は、NULL を入力します。

st_mobile_input_params_t inputEvent;
memset(&inputEvent, 0, sizeof(st_mobile_input_params_t));
int type = ST_INPUT_PARAM_NONE;
iRet = st_mobile_sticker_get_needed_input_params(_hSticker, &type);
if (CHECK_FLAG(type, ST_INPUT_PARAM_CAMERA_QUATERNION)) {

    CMDeviceMotion *motion = self.motionManager.deviceMotion;
    inputEvent.camera_quaternion[0] = motion.attitude.quaternion.x;
    inputEvent.camera_quaternion[1] = motion.attitude.quaternion.y;
    inputEvent.camera_quaternion[2] = motion.attitude.quaternion.z;
    inputEvent.camera_quaternion[3] = motion.attitude.quaternion.w;
    if (self.stCamera.devicePosition == AVCaptureDevicePositionBack) {
        inputEvent.is_front_camera = false;
    } else {
        inputEvent.is_front_camera = true;
    }
} else {
    inputEvent.camera_quaternion[0] = 0;
    inputEvent.camera_quaternion[1] = 0;
    inputEvent.camera_quaternion[2] = 0;
    inputEvent.camera_quaternion[3] = 1;
}

詳細については、サンプルをご参照ください。

スタンプの変更:

st_result_t iRet = st_mobile_sticker_change_package(_hSticker, stickerPath, NULL);

アクションをトリガーするスタンプの取得: (st_mobile_sticker_change_package 関数を取得後にのみ、スタンプを取得します。アクションはヘッダーファイルで定義されています。)

st_result_t iRet = st_mobile_sticker_get_trigger_action(_hSticker, &action);

6.フィルター API の使用

//フィルタータイプを設定するには、OpenGL スレッドで呼び出す必要があります
st_result_t iRet = st_mobile_gl_filter_set_style(_hFilter, [model.strPath UTF8String]);
//フィルター強度を [0,1] の範囲で設定します。0 の場合はフィルターエフェクトなし、1 は最大の強度を示します。
iRet = st_mobile_gl_filter_set_param(_hFilter, ST_GL_FILTER_STRENGTH, self.fFilterStrength);
//フィルター用関数
iRet = st_mobile_gl_filter_process_texture(_hFilter, textureResult, iWidth, iHeight, _textureFilterOutput);

7.一般的なオブジェクト API の使用

//トラッキングする領域を一度だけ設定します。リセット後に、対象領域を再設定します。
st_result_t iRet =
    st_mobile_object_tracker_set_target(
        st_handle_t handle,             //初期化された、一般的なオブジェクトのトラッキングハンドル
        const unsigned char *image,     //検知対象の画像
        st_pixel_format pixel_format,   //検知用画像データのピクセル形式。一律にグレースケール画像に変換されます。
        int image_width,                //検知用画像の幅 (ピクセル単位)
        int image_height,               //検知用画像の高さ (ピクセル単位)
        int image_stride,              //検知用画像のスパン (ピクセル単位)。各行のバイト数のこと。
        st_rect_t* target_rect          //指定されたターゲットの顔枠を入力します。現在は、2 ^ n の正方形のみトラッキングできます。
    );

//リアルタイムで連続ビデオフレームのターゲットを高速トラッキングします
st_result_t iRet =
    st_mobile_object_tracker_track(
        st_handle_t handle,          ////初期化された、一般的なオブジェクトのトラッキングハンドル
        const unsigned char *image,  //検知対象の画像データ
        st_pixel_format pixel_format,//検知対象の画像データのピクセル形式
        int image_width,             //検知対象の画像の幅
        int image_height,            //検知対象の画像の高さ
        int image_stride,            //検知対象の画像スパン
        st_rect_t *result_rect       //トラッキングされた顔枠の新しい位置を出力
        float *result_score          //信頼係数。必要に応じて、トラッキンが失敗したかどうかを判断する場合は、値を (0, 1) に設定します。
);

//一般的なオブジェクトトラッキング API ハンドルをリセットします
st_mobile_object_tracker_reset(
    st_handle_t handle //一般的なオブジェクトトラッキングハンドル
);

3.5 SDK ハンドルの解放

1.GL リソースは、GL スレッドで解放する必要があります。

- (void)releaseResources
{
    if ([EAGLContext currentContext] != self.glContext) {
        [EAGLContext setCurrentContext:self.glContext];
    }
    //スタンプ API ハンドルを解放します
    if (_hSticker) {
        st_mobile_sticker_destroy(_hSticker);
        _hSticker = NULL;
    }
    //美化 API ハンドルを解放します
    if (_hBeautify) {
        st_mobile_beautify_destroy(_hBeautify);
        _hBeautify = NULL;
    }
    //顔検知ハンドルを解放します
    if (_hDetector) {
        st_mobile_human_action_destroy(_hDetector);
        _hDetector = NULL;
    }
    //顔属性ハンドルを解放します
    if (_hAttribute) {
        st_mobile_face_attribute_destroy(_hAttribute);
        _hAttribute = NULL;
    }
    //フィルターハンドルを解放します
    if (_hFilter) {
        st_mobile_gl_filter_destroy(_hFilter);
        _hFilter = NULL;
    }
    //一般的なオブジェクトハンドルを解放します
    if (_hTracker) {
        st_mobile_object_tracker_destroy(_hTracker);
        _hTracker = NULL;
    }

    //検知出力から顔配列を解放します
    if (_pFacesDetection) {
        free(_pFacesDetection);
        _pFacesDetection = NULL;
    }
    //美化出力から顔配列を解放します
    if (_pFacesBeautify) {
        free(_pFacesBeautify);
        _pFacesBeautify = NULL;
    }
    //テクスチャのリソースを解放します
    [self releaseResultTexture];
    //テクスチャのキャッシュを解放します
    if (_cvTextureCache) {
        CFRelease(_cvTextureCache);
        _cvTextureCache = NULL;
    }

    [EAGLContext setCurrentContext:nil];
}

まとめ: 第 3 章では、本 SDK の API の使用方法に関する概要を説明しました。デモのプレゼンテーションは、SDK のより迅速な統合を促進します。いくつかの考慮すべき点を以下に示します。

1.顔属性の検知、美化、スタンプを使用するには、事前に humanAction を検知する必要があります。

2.美化、スタンプ、フィルターは、OpenGL によりレンダリングされます。そのため、同じ EAGLContext 内にある必要があります。次のように実装します。

if ([EAGLContext currentContext] != self.glContext) {
    [EAGLContext setCurrentContext:self.glContext];
}

4 お客様によるカスタマイズ

美化機能とスタンプ機能が正常に動作するようにするために、後述の方法で SDK の顔検知機能を有効にします。

4.1 顔検知

//顔検知を有効にします
iRet = st_mobile_human_action_detect(_hDetector,//顔検知ハンドル
    pBGRAImageIn,//出力データのアドレス
    ST_PIX_FMT_BGRA8888,//画像形式
    iWidth,//幅
    iHeight,//高さ
    iBytesPerRow,//iWidth * 4 (BGRA の 4 チャンネル)
    stMobileRotate,//回転角度 (セクション 3.4.1「HumanAction API」に関する説明をご参照ください)
    iConfig,//動作の検知。本パラメーターを変更して、特定の動作を検知できます。config コマンドは st_mobi le_human_action で定義されています。
    &detectResult //検知結果
);

4.2 美化

事前に顔検知機能を有効にします。

美化機能を有効にします

有効にする方法 1 (テクスチャのみ出力):

iRet = st_mobile_beautify_process_texture(_hBeautify,//美化 API ハンドル
                                          _textureOriginInput,//入力テクスチャ
                                          iWidth,//幅
                                          iHeight,//高さ
                                          &detectResult,//動作結果
                                          _textureBeautifyOutput,//出力テクスチャの美化
                                          &processedResult//美化実施後の検知結果
                                          );

美化を実施した後のデータをストリーミングまたはショートビデオの録画に使用する場合、テクスチャの前処理段階で作成された _cvBeaufigyBuffer でデータを読み取ることができます。

方法 2 (テクスチャとバッファーを出力):

st_mobile_beautify_process_and_output_texture(
    st_handle_t handle,//初期化された美化 API ハンドル
    unsigned int textureid_src,//保留中のテクスチャ ID
    int image_width, int image_height,//入力テクスチャの幅と高さ
    const st_mobile_human_action_t* p_human_action_t,//顔データ
    unsigned int textureid_dst,//出力テクスチャ
    unsigned char *img_out, st_pixel_format fmt_out,//出力バッファ、出力データ形式
    st_mobile_human_action_t* p_huaman_out//美化実施後の顔データ
);

補足: ストリーミングのアプリケーションシナリオの場合、

1.テクスチャの前処理段階で作成された _cvBeaufigyBuffer のデータを使用します。バッファーの作成方法の詳細については、セクション 3.3 「テクスチャの前処理」をご参照ください。

2.方法 2 で説明したように、出力バッファを使用して、美化機能を有効化できます。glReadPixels のパフォーマンスに影響するため、この方法は使用しないでください。

4.3 スタンプ

事前に顔検知機能を有効にします。

スタンプ機能の有効化

方法 1:

iRet = st_mobile_sticker_process_texture(_hSticker ,//スタンプハンドル
    _textureOriginInput,//入力テクスチャ
    iWidth,//幅
    iHeight,//高さ
    stMobileRotate,//回転角度
    ST_CLOCKWISE_ROTATE_0,//前景スタンプの回転角度。必要に応じて設定します。
    false,//ミラーリングするかどうか
    &detectResult,//動作の検知結果
    -1, //カスタムイベント
    _textureStickerOutput//スタンプ処理後の画像データ
);

スタンプ追加後のデータをストリーミングやショートビデオの録画に使用する際は、テクスチャの前処理段階で作成された _cvStickerBuffer データを読み込むことができます。

方法 2:

st_mobile_sticker_process_and_output_texture(
    st_handle_t handle,//初期化されたスタンプハンドル
    unsigned int textureid_src,//入力テクスチャ
    int image_width, //幅
    int image_height,//高さ
    st_rotate_type rotate,//回転角度
    st_rotate_type frontStickerRotate,//前景スタンプの回転角度。必要に応じて設定します。
    bool need_mirror,//ミラーリングするかどうか
    p_st_mobile_human_action_t human_action,//動作の検知結果
    int custom_event,//カスタムイベント
    unsigned int textureid_dst,//スタンプ処理後の画像データ
    unsigned char* img_out, //出力バッファー
    st_pixel_format fmt_out//出力画像データ形式
);

出力バッファーのデータはスタンプと一緒に追加されます。ストリーミングやショートビデオの録画に使用できます。glReadPixels のパフォーマンスに影響するため、この方法は使用しないでください。

まとめ: 第 4 章では、美化機能とスタンプ機能を個別に有効にする方法について説明しました。前述の概念に従って自由に機能を有効にして、目的の効果を得ることができます。

5 統合に関する考慮事項

バックグラウンドで、OpenGL 関連の操作を実行しないでください。

6 検知のレンダリングの最適化

サンプルでは、検知およびレンダリングの並列ポリシーが採用されています。これは、1 つのスレッドで動作を検知し、別のスレッドで検知した動作をレンダリングすることを意味します。iOS の場合、カメラのコールバックキューで動作を直接検知します。検知した後で、動作を同期された別のキューで次のようにレンダリングします (特定のコードは省略されています。全コードは、サンプルをご参照ください)。

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

    //2 つのフレームをバッファー処理します。
    if (self.iBufferedCount >= 2) {
        return;
    }
    //動作を検知します。
    st_result_t iRet = st_mobile_human_action_detect(_hDetector,pBGRAImageIn,ST_PIX_FMT_BGRA8888,iWidth,iHeight,iBytesPerRow,stMobileRotate,self.iCurrentAction,&detectResult);
    self.iBufferedCount ++;
    CFRetain(pixelBuffer);
    //動作検知結果を別のスレッドでレンダリングするためにコピーします
    __block st_mobile_human_action_t newDetectResult;
    memset(&newDetectResult, 0, sizeof(st_mobile_human_action_t));
    copyHumanAction(&detectResult, &newDetectResult);
    //スレッドをレンダリングします
    dispatch_async(self.renderQueue, ^{
        //美化やスタンプなどの操作
        //コピーした動作の検知結果を解放します
        freeHumanAction(&newDetectResult);
        //結果をレンダリングします
        [self.glPreview renderTexture:textureResult];
        CFRelease(pixelBuffer);
        self.iBufferedCount --;
    });
}

copyHumanAction および freeHumanAction メソッドの詳細については、サンプルをご参照ください。

Last updated