JCV AR SDK
Search…
JCV AR SDK Android統合ドキュメント

目次

1.統合の準備

  • 1.1 リソースファイルの使用
  • 1.2 Android Studio ランタイム環境の設定
  • 1.3 JNI の難読化

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

  • 2.1 ライセンスファイルを使用したアルゴリズムライブラリの認証
  • 2.2 モデルファイルの使用
  • 2.3 スタンプファイルの使用

3.シングルおよびダブル入力モード

  • 3.1 シングル入力モード
  • 3.2 ダブル入力モード
  • 3.3 最適化されたシングル入力モード
  • 3.4 最適化されたダブル入力モード
  • 3.5 入力モードの切り替え

4.SDK の API の使用

  • 4.1 SDK ハンドルの初期化
  • 4.2 カメラプレビューのテクスチャとデータの取得
  • 4.3 カメラプレビューのテクスチャとデータの処理
  • 4.4 フレーム処理フロー
  • 4.5 SDK ハンドルの解放

5.JNI API の概要

  • 5.1 STMobileCommon
  • 5.2 STMobileHumanActionNative
  • 5.3 STMobileFaceAttributeNative
  • 5.4 STBeautifyNative
  • 5.5 STMobileStickerNative
  • 5.6 STSoundPlay
  • 5.7 STMobileStreamFilterNative
  • 5.8 STMobileFilterNative
  • 5.9 STMobileObjectTrackNative
  • 5.10 STHumanAction

6.回転と方向に関する手順

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

1 統合の準備

1.1 リソースファイルの使用

  • Android Studio プロジェクトを開きます。ライセンスファイル、モデルファイル、スタンプなどのファイルを JCV AR SDK ディレクトリからプロジェクトのアセットフォルダーにコピーします。
  • ライセンスファイルの名前を「SenseME.lic」に変更し、アセットフォルダーにコピーします。
  • face_attribute_x.x.x.model や M_SenseME_Action_x.x.x.model を含むモデルファイルをアセットフォルダーにコピーします。
  • スタンプパッケージを "2D"、"3D"、"hand_action"、"deformation"、"segment" に分類し、アセットフォルダーにサブフォルダーを作成します。スタンプを分類し、名前が同じアイコンと一緒に、それぞれサブフォルダーにコピーします。アイコンがない場合は "なし" と表示されます。分類方法はカスタマイズできます詳細はサンプルの FileUtils ファイルをご参照ください。
  • アセットフォルダーに "filter_xx" という名前のフィルターカテゴリフォルダーを作成し、後で使用できるようにカスタム分類フィルターモデルを適切なフォルダーにコピーします。

1.2 Android Studio ランタイム環境の設定

  • 初めてサンプルプロジェクトを開くと、"NDK が見つかりません" というメッセージが表示される可能性があります。[プロジェクト] を右クリックし、[モジュール設定を開く]、[SDK の場所]、[Android NDK の場所] の順にクリックして、NDK のパスを設定します。
  • サンプルの JNI の部分をプロジェクトに統合するには、build.gradle プロジェクトに JNI の部分の依存関係を追加します。
dependencies {
... ...
////STMobileJNI の依存関係を追加します
compile project(':STMobileJNI')
... ...
}

1.3 JNI の難読化

  • プロジェクトで STMobileJNI を引用するには、次のようにプロジェクトの proguard-rules.pro ファイルに JNI の難読化を追加します。
-keep class com.sensetime.stmobile.* { *;}
-keep class com.sensetime.stmobile.model.* { *;}

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

2.1 ライセンスファイルを使用したアルゴリズムライブラリの認証

  • SDK は、アルゴリズムライブラリの権限をライセンスファイルと照合します。 認証された後にのみ、SDK の機能を使用できます。
  • SenseME.lic ファイルをアセットフォルダーにコピーした後、統合するために、次のように STLicenseUtils ユーティリティクラスの checkLicense() 関数のみを呼び出すことができます。
  1. 1.
    まずlicenseファイルの内容を読み込みます。
  2. 2.
    ローカルに保存されているアクティブコードを取得します。
  3. 3.
    利用可能なアクティベーションコードがない場合は、生成します。
  4. 4.
    checkActiveCode* コマンドを直接実行して、アクティベーションコードが有効であるかどうか確認します。
  5. 5.
    確認に失敗した場合は、別のアクティベーションコードを生成します。
  6. 6.
    生成に失敗した場合は、エラーメッセージが表示されます。成功すると、新しいアクティベーションコードが保存され、成功したことを示すメッセージが表示されます。
private final static String PREF_ACTIVATE_CODE_FILE = "activate_code_file";
private final static String PREF_ACTIVATE_CODE = "activate_code";
private static final String LICENSE_NAME = "SenseME.lic";
/**
* 既存のアクティベーションコードが有効か確認します
* @return 成功した場合は true を、失敗した場合は false を返します
*/
public static boolean checkLicense(Context context) {
StringBuilder sb = new StringBuilder();
InputStreamReader isr = null;
BufferedReader br = null;
//ライセンスファイルの内容を確認します
try {
isr = new InputStreamReader(
context.getResources().getAssets().open(LICENSE_NAME)
);
br = new BufferedReader(isr);
String line = null;
while((line=br.readLine()) != null) {
sb.append(line).append("\n");
}
}
... ...
//ライセンスファイルが空の場合、エラーメッセージが返されます
if (sb.toString().length() == 0) {
LogUtils.e(TAG, "read license data error");
return false;
}
String licenseBuffer = sb.toString();
SharedPreferences sp = context.getApplicationContext()
.getSharedPreferences(
PREF_ACTIVATE_CODE_FILE,
Context.MODE_PRIVATE
);
String activateCode = sp.getString(PREF_ACTIVATE_CODE, null);
Integer error = new Integer(-1);
if (activateCode == null ||
(STMobileAuthentificationNative.checkActiveCodeFromBuffer(
context,
licenseBuffer,
licenseBuffer.length(),
activateCode,
activateCode.length()
) != 0)) {
activateCode = STMobileAuthentificationNative
.generateActiveCodeFromBuffer(
context,
licenseBuffer,
licenseBuffer.length()
);
if (activateCode != null && activateCode.length() >0) {
SharedPreferences.Editor editor = sp.edit();
editor.putString(PREF_ACTIVATE_CODE, activateCode);
editor.commit();
return true;
}
return false;
}
return true;
}

2.2 モデルファイルの使用

  • FileUtils ファイルを使用して、サンプルのモデルファイルを管理します。AssetsManager を使用してモデルファイルにアクセスできます。モデルファイルの使用方法については、サンプルをご参照ください。
public static final String MODEL_NAME_ACTION =
"M_SenseME_Action_5.5.1.model";
public static final String MODEL_NAME_FACE_ATTRIBUTE =
"M_SenseME_Attribute_1.0.1.model";
public static final String MODEL_NAME_EYEBALL_CENTER =
"M_Eyeball_Center.model";
public static final String MODEL_NAME_EYEBALL_CONTOUR =
"M_SenseME_Iris_1.11.1.model";
public static final String MODEL_NAME_FACE_EXTRA =
"M_SenseME_Face_Extra_5.6.0.model";
public static final String MODEL_NAME_BODY_FOURTEEN =
"M_SenseME_Body_Fourteen_1.2.0.model";
public static final String MODEL_NAME_HAND =
"M_SenseME_Hand_5.0.0.model";
public static final String MODEL_NAME_AVATAR_CORE =
"M_SenseME_Avatar_Core_1.0.0.model";
......

2.3 スタンプファイルの使用

  • 制御下のスタンプファイルを SD カードにコピーし、パスを取得します。スタンプの変更時は、SDK の API にパスを割り当てます。
  • FileUtils ツールクラスの copyStickerZipFiless() 関数を使用して、スタンプをコピーできます。
//スタンプファイルを、スタンプファイルごとに返されるパスと一緒にコピーします
public static ArrayList<String> copyStickerZipFiles(Context context) {
String files[] = null;
ArrayList<String> zipfiles = new ArrayList<String>();
try {
files = context.getAssets().list("");
} catch (IOException e) {
e.printStackTrace();
}
... ...
return zipfiles;
}
  • FileUtils ツールクラスの getStickerFiles() 関数を実行して、レンダリング用にスタンプのパスを取得します
  • サブフォルダーでファイルをコピーするには、サンプルのメソッドをご参照ください。必要に応じて、メソッドをカスタマイズすることも可能です。

3 シングルおよびダブル入力モード

3.1 シングル入力モード

  • シングル入力モードでは、カメラはテクスチャをコールバックすることによってのみデータを取得します。HumanAction を含む特定の API では、検知用のバッファーデータを入力する必要があります。そのため、glReadPixel() 関数を使用して、ARGB 形式でバッファーデータを取得する必要があります。
  • メリット: バッファーをコールバックする必要がありません。統合およびデータ処理が簡単です。
  • デメリット: glReadPixel() 関数は、ローエンドのマシンでは時間が掛かります。画像形式は ARGB です。顔検知で必要な場合は、グレースケールに変換する必要があります。

3.2 ダブル入力モード

  • ダブル入力モードでは、カメラはテクスチャとデータバッファーを同時にコールバックします。
  • メリット: シングル入力モードと比較すると、ダブル入力モードでは glReadPixel() を必要としません。画像形式は NV21 です。直接、グレースケース画像を取得できます。
  • デメリット: データバッファーのコールバックを使用して、HumanAction を計算します。他の API で使用するために回転およびミラーリングされるため、統合が複雑になります。ARGB 形式を使用する場合は、変換する必要があります。スレッド同期問題もあります。
  • 注記: ダブル入力モードでは、スレッド同期問題、および mGlSurfaceView.requestRender() のタイミングに特に注意してください。

3.3 最適化されたシングル入力モード

  • シングル入力最適化モードは、シングル入力モードに基づいて glReadPixel() を介してバッファーを取得します。取得したバッファーを使用して複数のスレッドでレンダリングおよび検知処理を行います。
  • メリット: シングル入力モードよりフレームレートが高くなり、時間が掛かる検知処理ではパフォーマンスが大幅に向上します。
  • デメリット: 統合が複雑です。スレッドの同期化により、レンダリングが 1 フレーム遅れます。

3.4 最適化されたダブル入力モード

  • ダブル入力最適化モードは、ダブル入力モードに基づいてカメラのコールバックテクスチャを削除します。バッファーを使用したテクスチャのアップロードにより、テクスチャを取得し、そのバッファーを使用して複数のスレッドで検知処理を行います。
  • メリット: シングルおよびダブル入力モードと比べて、フレームレートが高くなり、時間が掛かる検知処理ではパフォーマンスが大幅に向上します。
  • デメリット: 統合が複雑です。テクスチャを手動でアップロードする必要があります。スレッドの同期化により、レンダリングが 1 フレーム遅れます。

3.5 入力モードの切り替え

  • サンプルでは、異なる入力モードを使用できます
  • 異なる入力モードに切り替えるには、サンプルの CameraActivity.java ファイルをご参照ください。
//ダブル入力モードを使用
private CameraDisplayDoubleInput mCameraDisplay;
//シングル入力モードを使用
private CameraDisplaySingleInput mCameraDisplay;
//シングル入力モードの最適化
private CameraDisplaySingleInputMultiThread mCameraDisplay;
//ダブル入力モードの最適化
private CameraDisplayDoubleInputMultithread mCameraDisplay;
//シングル入力モードを使用
mCameraDisplay = new CameraDisplaySingleInput(
getApplicationContext(),
mSingleInputChangePreviewSizeListener,
glSurfaceView
);
//ダブル入力モードを使用
mCameraDisplay = new CameraDisplayDoubleInput(
getApplicationContext(),
mDoubleInputChangePreviewSizeListener,
glSurfaceView
);
//ダブル入力モードを使用
mCameraDisplay = new CameraDisplayDoubleInput(
getApplicationContext(),
mChangePreviewSizeListener,
glSurfaceView
);
//ダブル入力モードとマルチスレッド
mCameraDisplay = new CameraDisplayDoubleInputMultithread(
getApplicationContext(),
mChangePreviewSizeListener,
glSurfaceView
);

4 SDK API の使用

4.1 SDK ハンドルの初期化

4.1.1 HumanAction API の初期化

  • HumanAction API を初期化するには loadModel を実行しますが、この処理は時間が掛かります。そのため、非同期に初期化してください。本バージョンでは、サブモデル追加用の API が提供されています。初期化に必要なmodelのみを使用し、後でさらにサブモデルを追加すれば、初期化にかかる時間を削減できます。
//HumanAction ハンドルの初期化は時間が掛かります。そのため、非同期操作を推奨します。
private void initHumanAction() {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (mHumanActionHandleLock) {
//モデルをアセットフォルダーからメモリに読み込み、
//基になる st_mobile_human_action_create_from_buffer API を
//使用して、ハンドルを作成します
int result = mSTHumanActionNative
.createInstanceFromAssetFile(
FileUtils.getActionModelName(),
mHumanActionCreateConfig,
mContext.getAssets()
);
LogUtils.i(
TAG,
"the result for createInstance for human_action is %d",
result
);
if (result == 0) {
mIsCreateHumanActionHandleSucceeded = true;
mSTHumanActionNative.setParam(
STHumanActionParamsType.ST_HUMAN_ACTION_PARAM_BACKGROUND_BLUR_STRENGTH,
0.35f
);
}
}
}
}).start();
}
  • 初期化中に、シナリオに応じて画像またはビデオを設定するか、または必要に応じて修正します (詳細については STMobileHumanActionNative.java ファイルをご参照ください)。
//作成用にデフォルト設定された設定パラメーター
//マルチスレッドを実行して、速度を最大限に早め、遅れを減らします。必要に応じてデフォルトのパラメーターを変更します。
//ビデオを検知するためにマルチスレッドを実行します
public final static int ST_MOBILE_HUMAN_ACTION_DEFAULT_CONFIG_VIDEO =
ST_MOBILE_TRACKING_MULTI_THREAD|
ST_MOBILE_TRACKING_ENABLE_DEBOUNCE|
ST_MOBILE_TRACKING_ENABLE_FACE_ACTION|
ST_MOBILE_ENABLE_FACE_DETECT|
ST_MOBILE_ENABLE_HAND_DETECT|
ST_MOBILE_ENABLE_SEGMENT_DETECT|
ST_MOBILE_DETECT_MODE_VIDEO;
//デフォルト設定を使用して画像を検知します
//画像の検知にはシングルスレッドのみ使用できます
public final static int ST_MOBILE_HUMAN_ACTION_DEFAULT_CONFIG_IMAGE =
ST_MOBILE_TRACKING_SINGLE_THREAD|
ST_MOBILE_ENABLE_FACE_DETECT|
ST_MOBILE_ENABLE_SEGMENT_DETECT|
ST_MOBILE_ENABLE_HAND_DETECT|
ST_MOBILE_DETECT_MODE_IMAGE;
  • HumanAction API を使用して、モデルを動的に追加または削除し、リソースの割り当てを改善できます。非同期に呼び出すこともできます (詳細については、CameraDisplayDoubleInput.java ファイルをご参照してください)。
//動的にモデルを追加します
private void addSubModel(final String modelName){
synchronized (mHumanActionHandleLock) {
int result = mSTHumanActionNative.addSubModelFromAssetFile(
modelName,
mContext.getAssets()
);
LogUtils.i(TAG, "add sub model result: %d", result);
if(result == 0){
if(modelName.equals(FileUtils.MODEL_NAME_BODY_FOURTEEN)){
mDetectConfig |=
STMobileHumanActionNative.ST_MOBILE_BODY_KEYPOINTS;
mSTHumanActionNative.setParam(
STHumanActionParamsType.ST_HUMAN_ACTION_PARAM_BODY_LIMIT,
3.0f
);
}else if(modelName.equals(FileUtils.MODEL_NAME_FACE_EXTRA)){
mDetectConfig |=
STMobileHumanActionNative.ST_MOBILE_DETECT_EXTRA_FACE_POINTS;
}else if(modelName.equals(FileUtils.MODEL_NAME_EYEBALL_CONTOUR)){
mDetectConfig |= STMobileHumanActionNative.ST_MOBILE_DETECT_EYEBALL_CONTOUR |
STMobileHumanActionNative.ST_MOBILE_DETECT_EYEBALL_CENTER;
}else if(modelName.equals(FileUtils.MODEL_NAME_HAND)){
mDetectConfig |= STMobileHumanActionNative.ST_MOBILE_HAND_DETECT_FULL;
}
}
}
}
//動的にモデルを削除します
private void removeSubModel(final int config){
synchronized (mHumanActionHandleLock) {
mSTHumanActionNative.removeSubModelByConfig(config);
if(config == STMobileHumanActionNative.ST_MOBILE_ENABLE_BODY_KEYPOINTS){
mDetectConfig &= ~STMobileHumanActionNative.ST_MOBILE_BODY_KEYPOINTS;
}else if(config == STMobileHumanActionNative.ST_MOBILE_ENABLE_FACE_EXTRA_DETECT){
mDetectConfig &= ~STMobileHumanActionNative.ST_MOBILE_DETECT_EXTRA_FACE_POINTS;
}else if(config == STMobileHumanActionNative.ST_MOBILE_ENABLE_EYEBALL_CONTOUR_DETECT){
mDetectConfig &= ~(STMobileHumanActionNative.ST_MOBILE_DETECT_EYEBALL_CONTOUR |
STMobileHumanActionNative.ST_MOBILE_DETECT_EYEBALL_CENTER);
}else if(config == STMobileHumanActionNative.ST_MOBILE_ENABLE_HAND_DETECT){
mDetectConfig &= ~STMobileHumanActionNative.ST_MOBILE_HAND_DETECT_FULL;
}
}
}

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

  • 顔属性 API ハンドルを初期化します。
//顔属性ハンドルを初期化します
private void initFaceAttribute() {
int result = mSTFaceAttributeNative.createInstanceFromAssetFile(
FileUtils.MODEL_NAME_FACE_ATTRIBUTE,
mContext.getAssets()
);
LogUtils.i(
TAG,
"the result for createInstance for faceAttribute is %d",
result
);
}

4.1.3 美化 API ハンドルの初期化

  • 美化 API ハンドルを初期化します。
//美化ハンドルを初期化します
private void initBeauty() {
//美化およびプレビュー属性の幅と高さを初期化します
int result = mStBeautifyNative.createInstance(
mImageHeight,
mImageWidth
);
LogUtils.i(TAG, "the result is for initBeautify " + result);
... ...
}

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

  • スタンプ API ハンドルを初期化します。
//スタンプハンドルを初期化します
private void initSticker() {
iint result = mStStickerNative.createInstance(mContext, null);
if(mNeedSticker){
mStStickerNative.changeSticker(mCurrentSticker);
}
setHumanActionDetectConfig(
mNeedBeautify|mNeedFaceAttribute,
mStStickerNative.getTriggerAction()
);
LogUtils.i(
TAG, "the result for createInstance for sticker is %d",
result
);
}

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

  • フィルター API ハンドルを初期化します。
//フィルターハンドルを初期化します
private void initFilter(){
mSTMobileStreamFilterNative.createInstance();
LogUtils.i(TAG, "filter create instance result %d", result);
mSTMobileStreamFilterNative.setStyle(mCurrentFilterStyle);
mCurrentFilterStrength = mFilterStrength;
//フィルターの強度を設定します。デフォルト値は 0.5f です。
mSTMobileStreamFilterNative.setParam(
STFilterParamsType.ST_FILTER_STRENGTH,
mCurrentFilterStrength
);
}

4.1.6 一般的なオブジェクトのトラッキング API ハンドルの初期化

  • 一般的なオブジェクトのトラッキング API ハンドルを初期化します。
//一般的なオブジェクトのトラッキングハンドルの初期化
private void initObjectTrack(){
int result = mSTMobileObjectTrackNative.createInstance();
}

4.2 カメラプレビューのテクスチャとデータの取得

  • AndroidManifest.xml ファイルを追加して、システムカメラの権限を有効にします。
<uses-permission android:name="android.permission.CAMERA" />
  • ダブル入力モードでは、2 つのコールバックメソッド (バッファーとテクスチャ) を使用するように Android カメラを設定します。シングル入力モードでは、テクスチャをコールバックするように設定します。
public void startPreview(
SurfaceTexture surfaceTexture,
PreviewCallback previewcallback
){
try {
//テクスチャをコールバックするように設定します
mCamera.setPreviewTexture(surfaceTexture);
if (previewcallback != null) {
//バッファーをコールバックするように設定します
mCamera.setPreviewCallback(previewcallback);
}
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
  • Android カメラからテクスチャを取得します (詳細については、サンプルの CameraDisplayDoubleInput.java ファイル、および CameraProxy.java ファイルをご参照ください)。
private void setUpCamera(){
//カメラのプレビューで必要な表示領域を初期化します (mSurfaceTexture)
if(mTextureId == OpenGLUtils.NO_TEXTURE){
mTextureId = OpenGLUtils.getExternalOESTextureID();
mSurfaceTexture = new SurfaceTexture(mTextureId);
}
... ...
//mSurfaceTexture にコールバック用のカメラを追加します (テクスチャとバッファー)
mCameraProxy.startPreview(mSurfaceTexture,mPreviewCallback);
}
  • Android カメラからバッファーを取得します (詳細については、サンプルの CameraDisplayDoubleInput.java ファイル、および CameraProxy.java ファイルをご参照ください)。
private Camera.PreviewCallback mPreviewCallback = new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(final byte[] data, Camera camera) {
if (mCameraChanging || mCameraProxy.getCamera() == null) {
return ;
}
... ...
//テクスチャを更新します
mGlSurfaceView.requestRender();
}
};

4.3 カメラプレビューのテクスチャとデータの処理

4.3.1 テクスチャの前処理 (シングル入力モードとダブル入力モードで同様の手順)

  • カメラコールバックテクスチャは水平で、通常は OES 形式です。これを GL_TEXTURE_2D 形式に変換し、回転とミラーリングを適用して、携帯電話の画面上でプレビュー画像が直立するようにします (つまり、システムのフロントカメラで撮った写真と同じ結果)。
  • 容易に統合また利用できるように、デモではテクスチャ前処理クラス GLRender の preProcess() 関数を提供して、効率性を向上します。カメラのコールバックバッファーを使用して HumanAction を検知する際は、preProcess() 関数で readPixel コマンドを実行しないでください。 preProcess() 関数の 2 番目のパラメーターを NULL に設定してください。
//テクスチャの前処理
int textureId = mGLRender.preProcess(mTextureId, null);
  • カメラからテクスチャを取得するには、デモで GLRender クラスの preProcess() 関数の使用に関する概要をご参照ください。入力テクスチャを処理した場合は、preProcess() 関数を呼び出さないでください。
  • 前処理済みのテクスチャは、美化、スタンプ、およびフィルター API で使用できます。

4.3.2 データ処理

  • ダブル入力モードでは、カメラのコールバックバッファーデータを使用して HumanActionDetect プロセスを実行して、HumanAction 結果を取得します。テクスチャが回転およびミラーリングされているため、バッファー内のデータは処理されていません。 HumanAction の方向とテクスチャは一致しないため、後で API で使用できるよう、HumanAction の回転およびミラーリング機能を使用して、データを処理し、HumanAction の方向とテクスチャの方向を合わせます。
//カメラ ID とカメラの方向を使用して、HumanAction を再計算します (ダブル入力モード用)
public static STHumanAction humanActionRotateAndMirror(
STHumanAction humanAction,
int width,
int height,
int cameraId,
int cameraOrientation
){
if(humanAction == null){
return null;
}
if(cameraId != Camera.CameraInfo.CAMERA_FACING_FRONT &&
cameraId != Camera.CameraInfo.CAMERA_FACING_BACK){
return humanAction;
}
if(cameraOrientation != 90 && cameraOrientation != 270){
return humanAction;
}
//humanAction の回転およびミラーリング
if(cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT &&
cameraOrientation == 90){
humanAction = humanActionRotate(
height,
width,
STRotateType.ST_CLOCKWISE_ROTATE_90,
false,
humanAction
);
humanAction = humanActionMirror(width, humanAction);
}else if(cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT &&
cameraOrientation == 270){
humanAction = humanActionRotate(
height,
width,
STRotateType.ST_CLOCKWISE_ROTATE_270,
false,
humanAction
);
humanAction = humanActionMirror(width, humanAction);
}else if(cameraId == Camera.CameraInfo.CAMERA_FACING_BACK &&
cameraOrientation == 270){
humanAction = humanActionRotate(
height,
width,
STRotateType.ST_CLOCKWISE_ROTATE_270,
false,
humanAction
);
}else if(cameraId == Camera.CameraInfo.CAMERA_FACING_BACK &&
cameraOrientation == 90){
humanAction = humanActionRotate(
height,
width,
STRotateType.ST_CLOCKWISE_ROTATE_90,
false,
humanAction
);
}
return humanAction;
}
  • シングル入力モードでは、処理済みテクスチャを使用して、glReadPixel コマンドでバッファーデータを取得します。バッファーを使用して、HumanAction API から結果を計算します。方向はテクスチャの方向と同じであり、データを回転およびミラーリングする必要はありません。

4.4 フレーム処理フロー

注記: 本セクションで説明する美化、スタンプ、フィルター API には、OpenGL 環境が必要です。OpenGL スレッドで実行する必要があります。
  • HumanAction API の使用
//顔特徴点、顔の動き、ジェスチャ、前景と背景のセグメンテーションを検知します
STHumanAction humanAction = mSTHumanActionNative.humanActionDetect(
mRGBABuffer.array(),
STCommon.ST_PIX_FMT_RGBA8888,
mDetectConfig,
orientation,
mImageWidth,
mImageHeight
);

4.4.1 HumanAction API の使用

  • HumanActionDetect 設定は、デフォルトではすべてを検知します。必要に応じて設定をカスタマイズできます。たとえば、前景と背景をセグメント化するには、"|" で結合した ST_MOBILE_SEG_BACKGROUND を追加します。ジェスチャを検知するには、適切な設定を追加してください。
//HumanAction のデフォルト設定
//すべてを検知するのは、時間が掛かり、CPU 使用率が高くなるため、推奨されません。
//必要な動作を検知するようにしてください。
public final static long ST_MOBILE_HUMAN_ACTION_DEFAULT_CONFIG_DETECT =
ST_MOBILE_FACE_DETECT | ST_MOBILE_EYE_BLINK |
ST_MOBILE_MOUTH_AH | ST_MOBILE_HEAD_YAW |
ST_MOBILE_HEAD_PITCH | ST_MOBILE_BROW_JUMP |
ST_MOBILE_HAND_GOOD | ST_MOBILE_HAND_PALM |
ST_MOBILE_HAND_LOVE | ST_MOBILE_HAND_HOLDUP |
ST_MOBILE_HAND_CONGRATULATE | ST_MOBILE_HAND_FINGER_HEART |
ST_MOBILE_DETECT_EYEBALL_CENTER|ST_MOBILE_DETECT_EYEBALL_CONTOUR;
//サポートされた顔検知設定
public final static long ST_MOBILE_FACE_DETECT = 0x00000001; //////<顔検知
//顔の動作
public final static long ST_MOBILE_EYE_BLINK = 0x00000002; ///<まばたきする
public final static long ST_MOBILE_MOUTH_AH = 0x00000004; ///口を大きく開く
public final static long ST_MOBILE_HEAD_YAW = 0x00000008; //////<頭を振る
public final static long ST_MOBILE_HEAD_PITCH = 0x00000010; ///<うなずく
public final static long ST_MOBILE_BROW_JUMP = 0x00000020; ///<眉を上げる
//ジェスチャ
public final static long ST_MOBILE_HAND_GOOD = 0x00000800; ///<親指を立てる 2048
public final static long ST_MOBILE_HAND_PALM = 0x00001000; ///<手のひら 4096
public final static long ST_MOBILE_HAND_LOVE = 0x00004000; ///<ハートのジェスチャ (16384)
public final static long ST_MOBILE_HAND_HOLDUP = 0x00008000; ///<手のひらを上に向ける 32768
public final static long ST_MOBILE_HAND_CONGRATULATE = 0x00020000; ///< お祝い (拳を握る) 131072
public final static long ST_MOBILE_HAND_FINGER_HEART = 0x00040000; //////< 片手でハートを作るジェスチャ (262144)
public final static long ST_MOBILE_HAND_TWO_INDEX_FINGER = 0x00080000;///< 並べた指 (524288)
public final static long ST_MOBILE_HAND_OK = 0x00000200; ///<OK のジェスチャ
public final static long ST_MOBILE_HAND_SCISSOR = 0x00000400; ///<勝利のポーズ
public final static long ST_MOBILE_HAND_PISTOL = 0x00002000; ///<ピストルのジェスチャ
public final static long ST_MOBILE_HAND_FINGER_INDEX = 0x00100000; ///<人差し指で指す
public final static long ST_MOBILE_HAND_FIST = 0x00200000; ///<拳のジェスチャ
public final static long ST_MOBILE_HAND_666 = 0x00400000; ///<ラッキー
public final static long ST_MOBILE_HAND_BLESS = 0x00800000; //////<禅のポーズ
public final static long ST_MOBILE_HAND_ILOVEYOU = 0x010000000000L; ///"愛している" のジェスチャ
public final static long ST_MOBILE_BODY_KEYPOINTS = 0x08000000; ///< 体の特徴点を検知
public final static long ST_MOBILE_SEG_BACKGROUND = 0x00010000; //////<前景と背景のセグメンテーション (65536)
public final static long ST_MOBILE_DETECT_EXTRA_FACE_POINTS = 0x01000000; ///< 240 の顔特徴点を検知
public final static long ST_MOBILE_DETECT_EYEBALL_CENTER = 0x02000000; ///< 眼球の中央点
public final static long ST_MOBILE_DETECT_EYEBALL_CONTOUR = 0x04000000; ///< 眼球の輪郭点
public final static long ST_MOBILE_BODY_ACTION1 = (long)1 << 32; ///龍拳
public final static long ST_MOBILE_BODY_ACTION2 = (long)1 << 33; ///一休さんのジェスチャ
public final static long ST_MOBILE_BODY_ACTION3 = (long)1 << 34; ///お手上げ
public final static long ST_MOBILE_BODY_ACTION4 = (long)1 << 35; ///スパイダーマン
public final static long ST_MOBILE_BODY_ACTION5 = (long)1 << 36; ///スーパーマン
//HumanAction 検知タイプの設定オプションを作成します
///サポートされている検知タイプ
public final static int ST_MOBILE_ENABLE_FACE_DETECT = 0x00000040; ///< 顔を検知
public final static int ST_MOBILE_ENABLE_HAND_DETECT = 0x00000080; ///< ジェスチャを検知
public final static int ST_MOBILE_ENABLE_SEGMENT_DETECT = 0x00000100; ///< 背景のセグメンテーションを検知
public final static int ST_MOBILE_ENABLE_FACE_EXTRA_DETECT = 0x00000200; ///< 240 の顔特徴点を検知
public final static int ST_MOBILE_ENABLE_EYEBALL_CENTER_DETECT = 0x00000400; ///< 眼球の中心点を検知
public final static int ST_MOBILE_ENABLE_EYEBALL_CONTOUR_DETECT = 0x00000800; ///< 眼球の輪郭を検知
public final static int ST_MOBILE_ENABLE_BODY_KEYPOINTS = 0x00001000; ///< 体の特徴点と動作を検知
public final static int ST_MOBILE_FACE_DETECT_FULL = 0x0000003F; ///< すべての顔の動きを検知
public final static int ST_MOBILE_HAND_DETECT_FULL = 0x001EFF00; ///< すべてのジェスチャを検知
///検知モード
public final static int ST_MOBILE_DETECT_MODE_VIDEO = 0x00020000; ///< ビデオの検知
public final static int ST_MOBILE_DETECT_MODE_IMAGE = 0x00040000; ///< 画像の検知
  • HumanActionDetect API を以下のように使用します。
STHumanAction humanAction = mSTHumanActionNative.humanActionDetect(
mNv21ImageData,
STCommon.ST_PIX_FMT_NV21,
mDetectConfig,
getHumanActionOrientation(),
mImageHeight,
mImageWidth
);
  • 顔の表情に関しては、STMobileHumanActionNative API の STMobileExpression コマンドをご参照ください。検知 API は、HumanAction API の結果から入力を受け取り、表情をそれぞれ出力します。以下に示します。
if(humanAction != null && humanAction.faceCount > 0){
mFaceExpressionResult = mSTHumanActionNative.getExpression(
humanAction,
getHumanActionOrientation(),
mCameraID == Camera.CameraInfo.CAMERA_FACING_FRONT
);