5

5分钟给商品建立3D模型,我是如何做到的?

 2 years ago
source link: https://my.oschina.net/u/4956408/blog/5132633
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

5分钟给商品建立3D模型,我是如何做到的? - 华为移动服务的个人空间 - OSCHINA - 中文开源技术交流社区

提问:3D模型展示商品不香吗?
香!当然香。

当3D建模成为电商网购应用的左膀右臂,大同小异的产品首图就有了焕然一新的呈现面貌!商品3D模型360°全方位展示,细节更丰富,辅以线上虚拟“看、试、穿、戴”,提供接近实物的差异化网购体验,助力高效提升用户转化。
3D模型虽美丽,然而,时下效果佳的3D建模技术因其较高的成本而使得让广大需求者望而却步。

  • 技术门槛高:专业人员手工制作,师带徒传承,学习成本高;
  • 时间成本高:完成一个简单物体的低模模型,工作量以小时起步,高模模型耗时更长。
  • 耗费高:单个商品的专业建模成本高,平均价格达到上千元,复杂模型更贵;

华为移动服务最新开放的3D建模服务,助力轻松建模。用户只需使用普通的RGB相机,通过拍摄物体的不同角度图像,便可实现物体的3D几何模型和纹理的自动化生成,为应用提供3D模型构建、预览等能力。如在电商鞋子展示的场景,您可以通过此能力自动生成鞋子3D模型,用于3D展示,用户可360°随心放大或缩小商品,为用户提供差异化的购买体验。 

3D物体建模能力由端云协同完成,端侧负责采集RGB图像,通过环绕物体一周拍摄多张图像,从而获取物体的不同角度图像,拍摄完毕后上传至云端实现3D物体建模。云端建模的流程及关键技术包括目标检测分割、特征检测与匹配、稀疏点云计算、稠密点云计算以及纹理重建等模块。最终输出业界通用的3D模型格式(.obj文件),面片数约40K~200K。

1. 配置集成的SDK包

在应用的build.gradle文件中,dependencies内添加3D建模服务的SDK依赖

// 3D Modeling Kit SDK
implementation 'com.huawei.hms:modeling3d-object-reconstruct:1.0.0.300'

2. 配置AndroidManifest.xml

打开main文件夹中的AndroidManifest.xml文件,可以根据场景和使用需要,配置读取和写入手机存储以及相机权限,在<application>前添加

<!-- 往sdcard中写入数据的权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 使用相机的权限 -->
<uses-permission android:name="android.permission.CAMERA" />

1. 配置存储权限申请

在MainActivity的onCreate()方法中,首先对手机存储的读取权限进行判断,如果未获取权限,则通过requestPermissions进行申请。

if (EasyPermissions.hasPermissions(MainActivity.this, PERMISSIONS)) {
    Log.i(TAG, "Permissions OK");
} else {
    EasyPermissions.requestPermissions(MainActivity.this, "To use this app, you need to enable the permission.",
            RC_CAMERA_AND_EXTERNAL_STORAGE, PERMISSIONS);
}

检查权限申请的结果,如果有权限初始化界面,没有权限提示用户开启。

@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
    Log.i(TAG, "permissions = " + perms);
    if (requestCode == RC_CAMERA_AND_EXTERNAL_STORAGE &&              PERMISSIONS.length == perms.size()) {
        initView();
        initListener();
    }
}

@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
    if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
        new AppSettingsDialog.Builder(this)
                .setRequestCode(RC_CAMERA_AND_EXTERNAL_STORAGE)
                .setRationale("To use this app, you need to enable the permission.")
                .setTitle("Insufficient permissions")
                .build()
                .show();
    }
}

2. 新建3D物体建模配置器

// Initializing the RGB Mode
Modeling3dReconstructSetting setting = new Modeling3dReconstructSetting.Factory()
        .setReconstructMode(Modeling3dReconstructConstants.ReconstructMode.PICTURE)
        .create();

3. 新建3D物体建模引擎并初始化任务

调用Modeling3dReconstructEngine的getInstance()接口,传入当前应用的上下文创建3D建模引擎实例

// Initializing the Rebuild Engine
modeling3dReconstructEngine = Modeling3dReconstructEngine.getInstance(mContext);

使用3D物体建模引擎初始化任务

// Creating a Rebuilding Task
modeling3dReconstructInitResult = modeling3dReconstructEngine.initTask(setting);
// Getting a Rebuilding Task
String taskId = modeling3dReconstructInitResult.getTaskId();

4. 新建上传监听器回调,处理拍摄的物体上传结果

新建上传回调接口,您可以在该回调接口中编写上传成功或失败后需要执行的操作。

// Re-establishing the upload callback listener
private final Modeling3dReconstructUploadListener uploadListener = new Modeling3dReconstructUploadListener() {
    @Override
    public void onUploadProgress(String taskId, double progress, Object ext) {
        // Upload progress
    }

    @Override
    public void onResult(String taskId, Modeling3dReconstructUploadResult result, Object ext) {
        if (result.isComplete()) {
            isUpload = true;
            ScanActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    progressCustomDialog.dismiss();
                    Toast.makeText(ScanActivity.this, getString(R.string.upload_text_success), Toast.LENGTH_SHORT).show();
                }
            });
            TaskInfoAppDbUtils.updateTaskIdAndStatusByPath(new Constants(ScanActivity.this).getCaptureImageFile() + manager.getSurfaceViewCallback().getCreateTime(), taskId, 1);
        }
    }

    @Override
    public void onError(String taskId, int errorCode, String message) {
        isUpload = false;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                progressCustomDialog.dismiss();
                Toast.makeText(ScanActivity.this, "Upload failed." + message, Toast.LENGTH_SHORT).show();
                LogUtil.e("taskid" + taskId + "errorCode: " + errorCode + " errorMessage: " + message);
            }
        });

    }
};

5. 3D物体建模引擎设置上传监听器,上传采集的图片数据

上传回调接口传入3D建模引擎并调用uploadFile()接口,传入第三步获取到的任务ID以及需要上传的图片路径,将数据上传到云端服务器。

// Set the callBack to engine.
modeling3dReconstructEngine.setReconstructUploadListener(uploadListener);
// Executing a Rebuild Upload Task
modeling3dReconstructEngine.uploadFile(taskId, filePath);

6. 查询3D物体建模任务状态

调用Modeling3dReconstructTaskUtils的getInstance接口创建3D建模任务处理实例,同样是传入当前应用的上下文作为入参。

// Initialize the reconstruction task tool class.
modeling3dReconstructTaskUtils = Modeling3dReconstructTaskUtils.getInstance(Modeling3dDemo.getApp());

调用任务处理实例的queryTask接口查询当前建模任务的进度。

// Query the reconstruction task execution result. The options are as follows: 0: To be uploaded; 1: Generating; 3: Completed; 4: Failed.
Modeling3dReconstructQueryResult queryResult = modeling3dReconstructTaskUtils.queryTask(task.getTaskId());

7.  新建下载监听器回调,用于处理3D物体建模模型文件的下载结果

新建下载回调接口,您可以在该回调接口中编写下载成功或失败后需要执行的操作

// Re-establishing the download callback listener
private Modeling3dReconstructDownloadListener modeling3dReconstructDownloadListener = new Modeling3dReconstructDownloadListener() {
    @Override
    public void onDownloadProgress(String taskId, double progress, Object ext) {
        ((Activity) mContext).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                dialog.show();
            }
        });
    }

    @Override
    public void onResult(String taskId, Modeling3dReconstructDownloadResult result, Object ext) {
        ((Activity) mContext).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getContext(), "Download complete", Toast.LENGTH_SHORT).show();
                TaskInfoAppDbUtils.updateDownloadByTaskId(taskId, 1);
                dialog.dismiss();
            }
        });
    }

    @Override
    public void onError(String taskId, int errorCode, String message) {
        LogUtil.e(taskId + " <---> " + errorCode + message);
        ((Activity) mContext).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getContext(), "Download failed." + message, Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }
        });
    }
};

8. 3D物体建模引擎加入下载监听,下载重建成功的模型文件

将下载回调接口传入3D建模引擎并调用downloadModel接口,传入第三步中获取的任务id和保存路径进行模型文件的下载。

// Setting Rebuild Download Listening
modeling3dReconstructEngine.setReconstructDownloadListener(modeling3dReconstructDownloadListener);
// Executing a Rebuild Download Task
modeling3dReconstructEngine.downloadModel(appDb.getTaskId(), appDb.getFileSavePath());
  1. 支持的物体纹理需丰富(纹理特征明显)、不反光、不透明/不半透明、尺寸中等、刚体,典型物体包括:商品类(毛绒玩具、包、鞋子)、 家具类(沙发)、文物类(青铜器、石器、木器)等。
  2. 支持物体尺寸15cm*15cm*15cm < 物体尺寸 < 1.5m*1.5m*1.5m(尺寸越大建模时间越长)。
  3. 不支持人脸、人体建模。
  4. 图像拍摄时需将单一的采集物体静置于纯色平面上,光照要柔和、避免灯光过暗,拍摄时要对焦,覆盖均匀而足够的多视角,含仰视、平视、俯视(50张以上),相机移动尽可能缓慢,所有角度照片尽可能一致,同时全过程采集中物体屏占比尽量大且完整,要求尽量保证拍摄无虚焦、运动模糊、抖动模糊。

超详细代码教程奉上,诚邀亲爱的开发者小伙伴们亲自实践一把,再为你身边的物品建个模!

>>访问华为3D建模服务官网,了解更多相关内容
>>获取华为3D建模开发指导文档
>>华为3D建模开源仓库地址GitHubGitee
>>华为HMS Core官方论坛
>>解决集成问题请到Stack Overflow

点击右上角头像右方的关注,第一时间了解HMS Core最新技术~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK