如何用AR引擎技术, 5步优雅实现物体识别和跟踪

如何用AR引擎技术, 5步优雅实现物体识别和跟踪

AR技术让应用实现虚拟世界和现实世界的融合,让开发者的创意和脑洞能够拥有更多炫酷有趣的呈现方式。AR拍照、AR购物、AR教育、AR搜索等丰富应用场景,凭借着AR技术的加持,为用户带来更优质的沉浸式体验,为用户创造更多价值。

例如,在运动健身应用中,AR的人体识别技术,能精准识别用户健身操练时的姿态是否符合规范动作,从而达到有效健身的作用;

在博物馆等展览展厅,AR技术也大有用处,用户在参览展品过程中,通过识别展品,手机根据识别出的展品自动呈现展品介绍信息,辅助用户参观;……

下面手把手教你,如何运用华为AR Engine 快速实现简单的物体识别和跟踪。

效果示例

基本原理和实现步骤

物体识别通过对图像中的物体进行识别辨认,从而报告出物体在图像所呈现场景中的位置和方向。

实现步骤:

图片预处理:在图像预处理环节,通过编码、阈值及滤波、改善模式、离散模式运算等基本运算方式,在尽可能保留图像所有内容信息的基础上,整理突出图像特征,以达到最佳图像特征提取的状态。图像特征提取:经过预处理的图像在特征提取环节,提取出价值高的特征,使高维特征空间拥有更好的分离性,更便于进行算法识别。图像特征提取一般细分成几个模块来进行:灰度值、亮度值、形状、纹理等视觉上的基本特征提取;基于像素点颜色的颜色特征提取;物体纹理及结构材质的纹理特征提取;基于轮廓和基于区域的形状特征提取;以及图像分割出的多个目标之间空间位置关系信息的空间特征提取。特征选择:特征提取后,可根据具体物体识别情况进行特征选择。比如在特征种类繁多、物体种类多的情况下,通过特征选择找到各个特征适配的场合。建模:特征选择之后,在建模环节建立特征集合,分辨异同点,提取相同点,主要建模对象是特征与特征之间的空间结构关系。匹配:匹配环节是用模型去识别匹配新图像,识别图像属于哪类物体,条件符合可将物体与图像其他部分分离。定位:物体识别后进行对目标物体的定位,即将识别到的物体坐标与实际物理空间坐标结合起来,之后可以进行对应的跟踪和模型叠加处理。

AR Engine提供三大能力

华为AR Engine提供的三大能力分别是运动跟踪、环境跟踪、人体和人脸跟踪。

运动跟踪主要通过终端设备摄像头标识特征点,并跟踪这些特征点的移动变化,来不断跟踪终端设备位置和姿态。环境跟踪可以识别平面,如地面、墙壁等,也可估测平面周围的光照强度。人体和人脸跟踪让终端设备具备了对人的理解能力。通过定位人的手部位置和对特定手势的识别,可将虚拟物体或内容特效放置在人的手上;结合深度器件,还可精确还原手部的21个骨骼点的运动跟踪,做更为精细化的交互控制和特效叠加;当识别范围扩展到人的全身时,可利用识别到的23个人体关键位置,实时的检测人体的姿态,为体感和运动健康类的应用开发提供能力支撑。

开发准备

Maven仓和SDK的配置步骤可以参考开发者网站中的应用开发介绍

https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/preparations-0000001059812995?ha_source=hms1

在AndroidManifest.xml中添加权限

打开main中的AndroidManifest.xml文件,在

开发步骤

配置MainActivity的显示效果

首先通过 MainActivity extends Activity implements GLSurfaceView.Renderer创建MainActivity,在MainActivity的layout文件中新建一个GLSurfaceView,用于显示摄像头拍摄的实时画面,提供给AREngine进行识别:

android:id="@+id/surfaceview"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_gravity="top" />

在MainActivity的onCreate阶段进行SurfaceView的配置:

private GLSurfaceView mSurfaceView;

private static final int CONFIG_CHOOSER_RED_SIZE = 8;

private static final int CONFIG_CHOOSER_GREEN_SIZE = 8;

private static final int CONFIG_CHOOSER_BLUE_SIZE = 8;

private static final int CONFIG_CHOOSER_ALPHA_SIZE = 8;

private static final int CONFIG_CHOOSER_DEPTH_SIZE = 16;

private static final int CONFIG_CHOOSER_STENCIL_SIZE = 0;

private static final int OPENGLES_VERSION = 2;

mSurfaceView = findViewById(R.id.surfaceview);

mSurfaceView.setPreserveEGLContextOnPause(true);

mSurfaceView.setEGLContextClientVersion(OPENGLES_VERSION);

mSurfaceView.setEGLConfigChooser(CONFIG_CHOOSER_RED_SIZE, // Alpha used for plane blending.

CONFIG_CHOOSER_GREEN_SIZE,

CONFIG_CHOOSER_BLUE_SIZE,

CONFIG_CHOOSER_ALPHA_SIZE,

CONFIG_CHOOSER_DEPTH_SIZE,

CONFIG_CHOOSER_STENCIL_SIZE); // Alpha used for plane blending.

mSurfaceView.setRenderer(this);

mSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);

加载一张框图文件,用于标记识别的位置,引导用户进行物体识别:

fitToScanView = findViewById(R.id.image_view_fit_to_scan);

InputStream bitmapstream;

try {

bitmapstream = getAssets().open("fit_to_scan.png");

} catch (IllegalArgumentException | IOException e) {

Log.d(TAG, "open bitmap failed!");

return;

}

Bitmap bitmap = BitmapFactory.decodeStream(bitmapstream);

fitToScanView.setImageBitmap(bitmap);

AREngine检测和配置权限申请

物体识别功能的使用需要设备支持AREngine,并且已经安装了AREngine的APK包,所以要对运行的设备进行判断,是否支持该功能

private boolean arEngineAbilityCheck() {

boolean isInstallArEngineApk = AREnginesApk.isAREngineApkReady(this);

if (!isInstallArEngineApk && isRemindInstall) {

Toast.makeText(this, "Please agree to install.", Toast.LENGTH_LONG).show();

finish();

}

Log.d(TAG, "Is Install AR Engine Apk: " + isInstallArEngineApk);

if (!isInstallArEngineApk) {

//Code of jumping to AppGallery to download the APK

isRemindInstall = true;

}

return AREnginesApk.isAREngineApkReady(this);

}

AREngine检测完成之后,再进行相机权限的动态申请

private static final String[] PERMISSIONS_ARRAYS = new String[]{Manifest.permission.CAMERA};

public static void requestPermission(final Activity activity) {

Log.d(TAG, "requestPermission >>");

for (String permission : PERMISSIONS_ARRAYS) {

if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {

permissionsList.add(permission);

}

}

ActivityCompat.requestPermissions(activity,

permissionsList.toArray(new String[permissionsList.size()]),

REQUEST_CODE_ASK_PERMISSIONS);

Log.d(TAG, "requestPermission <<");

}

以上步骤完成之后,说明设备支持AREngine的物体识别功能,并且已经获得了相机的使用权限,接下来就可以创建ARSession,并进行识别数据库的配置

配置物体识别数据库

在进行物体识别之前,要将想识别的对象的图片添加到数据库中,使用的是ARAugmentedImageDatabase,创建一个boolean函数,进行数据库的图片添加,并给后续是否进行识别作判断:

private boolean setupAugmentedImageDatabase(ARWorldTrackingConfig config) {

ARAugmentedImageDatabase augmentedImageDatabase;

Optional augmentedImageBitmapOptional = loadAugmentedImageBitmap();

Bitmap augmentedImageBitmap = null;

if (augmentedImageBitmapOptional.isPresent()) {

augmentedImageBitmap = loadAugmentedImageBitmap().get();

} else {

return false;

}

if (augmentedImageBitmap == null) {

return false;

}

augmentedImageDatabase = new ARAugmentedImageDatabase(mSession);

augmentedImageDatabase.addImage("image_name", augmentedImageBitmap);

config.setAugmentedImageDatabase(augmentedImageDatabase);

String text = String.format(Locale.ROOT, "has set ImageNum: %d", augmentedImageDatabase.getNumImages());

messageSnackbarHelper.showMessage(this, text);

return true;

}

所添加的识别图片源可以放置在Assets文件夹内,通过InputStream打开为Bitmap的格式

private Optional loadAugmentedImageBitmap() {

try (InputStream is = getAssets().open("cup.jpg")) {

return Optional.of(BitmapFactory.decodeStream(is));

} catch (IOException e) {

Log.e(TAG, "IO exception loading augmented image bitmap.", e);

}

return Optional.empty();

}

配置识别后显示效果

在MainActivity的onDrawFrame中配置识别到物体之后的显示效果,在检测到要识别的物体后,用一个方框将识别的物体标识出来。

public void onDrawFrame(GL10 unused) {

Log.d(TAG, "onDrawFrame >>");

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

if (mSession == null) {

Log.d(TAG, "onDrawFrame mSession is null");

return;

}

try {

ARFrame frame = mSession.update();

ARCamera camera = frame.getCamera();

if (camera.getTrackingState() == ARTrackable.TrackingState.PAUSED) {

return;

}

Log.d(TAG, "ARTrackable.TrackingState" + camera.getTrackingState());

drawAugmentedImages(frame, projmtx, viewmtxs, colorCorrectionRgbas);

} catch (Throwable t) {

Log.e(TAG, "Exception on the OpenGL thread", t);

}

Log.d(TAG, "onDrawFrame <<");

}

判断是否识别到物体时,调用ARAugmentedImage的getTrackingStatus方法,如果是TRACKING的话,则为识别到了

switch (augmentedImage.getTrackingState()) {

case TRACKING:

augmentedImageRenderer.draw(viewmtxs, projmtx, augmentedImage, centerAnchor, colorCorrectionRgbas);

break;

default:

break;

}

之后通过getCenterPose获取物体的中心位置信息,将边框添加到显示中

anchorPose = augmentedImage.getCenterPose();

float scaleFactor = 1.0f;

float[] modelMatrixs = new float[MODEL_MATRIX_SIZE];

float[] tintColors = convertHexToColor(TINT_COLORS_HEXS[augmentedImage.getIndex() % TINT_COLORS_HEXS.length]);

worldBoundaryPoses[0].toMatrix(modelMatrixs, 0);

imageFrameUpperLeft.updateModelMatrix(modelMatrixs, scaleFactor);

imageFrameUpperLeft.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColors);

worldBoundaryPoses[1].toMatrix(modelMatrixs, 0);

imageFrameUpperRight.updateModelMatrix(modelMatrixs, scaleFactor);

imageFrameUpperRight.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColors);

worldBoundaryPoses[2].toMatrix(modelMatrixs, 0);

imageFrameLowerRight.updateModelMatrix(modelMatrixs, scaleFactor);

imageFrameLowerRight.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColors);

worldBoundaryPoses[3].toMatrix(modelMatrixs, 0);

imageFrameLowerLeft.updateModelMatrix(modelMatrixs, scaleFactor);

imageFrameLowerLeft.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColors);

>>访问华为AR Engine 官网,了解更多相关内容

>>获取华为AR Engine 开发指导文档

>>华为AR Engine开源仓库地址:GitHub 、Gitee

>>访问华为开发者联盟官网,了解更多相关内容

>>获取开发指导文档

>>华为移动服务开源仓库地址:GitHub、Gitee

关注我们,第一时间了解华为移动服务最新技术资讯~

相关推荐

2024全球有多少个国家 全世界国家名单列表 世界国家名称大全表格
国内聊天软件哪个隐私最安全可靠(中国10大聊天软件)
Steam评价最高的30款游戏!款款经典必买无疑(上)
365篮球直播吧

Steam评价最高的30款游戏!款款经典必买无疑(上)

📅 07-10 👁️ 7045