diff --git a/src/depth_anything_3/api.py b/src/depth_anything_3/api.py index d0f18aad..9ecd8af3 100644 --- a/src/depth_anything_3/api.py +++ b/src/depth_anything_3/api.py @@ -350,13 +350,18 @@ def _align_to_input_extrinsics_intrinsics( if extrinsics is None: return prediction prediction.intrinsics = intrinsics.numpy() - _, _, scale, aligned_extrinsics = align_poses_umeyama( - prediction.extrinsics, - extrinsics.numpy(), - ransac=len(extrinsics) >= ransac_view_thresh, - return_aligned=True, - random_state=42, - ) + try: + _, _, scale, aligned_extrinsics = align_poses_umeyama( + prediction.extrinsics, + extrinsics.numpy(), + ransac=len(extrinsics) >= ransac_view_thresh, + return_aligned=True, + random_state=42, + ) + except Exception as e: + logger.error(f"Error aligning poses: {e}, using original extrinsics") + aligned_extrinsics = extrinsics.numpy() + scale = 1.0 if align_to_input_ext_scale: prediction.extrinsics = extrinsics[..., :3, :].numpy() prediction.depth /= scale diff --git a/src/depth_anything_3/utils/export/__init__.py b/src/depth_anything_3/utils/export/__init__.py index e3e4c657..eb5165ba 100644 --- a/src/depth_anything_3/utils/export/__init__.py +++ b/src/depth_anything_3/utils/export/__init__.py @@ -20,6 +20,7 @@ from .feat_vis import export_to_feat_vis from .glb import export_to_glb from .npz import export_to_mini_npz, export_to_npz +from .npy import export_to_mini_npy, export_to_npy def export( @@ -40,6 +41,10 @@ def export( export_to_mini_npz(prediction, export_dir) elif export_format == "npz": export_to_npz(prediction, export_dir) + elif export_format == "mini_npy": + export_to_mini_npy(prediction, export_dir) + elif export_format == "npy": + export_to_npy(prediction, export_dir) elif export_format == "feat_vis": export_to_feat_vis(prediction, export_dir, **kwargs.get(export_format, {})) elif export_format == "depth_vis": diff --git a/src/depth_anything_3/utils/export/npy.py b/src/depth_anything_3/utils/export/npy.py new file mode 100644 index 00000000..77ab2fa5 --- /dev/null +++ b/src/depth_anything_3/utils/export/npy.py @@ -0,0 +1,61 @@ +# Copyright (c) 2025 ByteDance Ltd. and/or its affiliates +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import numpy as np + +from depth_anything_3.specs import Prediction +from depth_anything_3.utils.parallel_utils import async_call + + +@async_call +def export_to_mini_npy( + prediction: Prediction, + export_dir: str, +): + output_dir = os.path.join(export_dir, "exports", "mini_npy") + os.makedirs(output_dir, exist_ok=True) + + np.save(os.path.join(output_dir, "depth.npy"), np.round(prediction.depth, 8)) + if prediction.conf is not None: + np.save(os.path.join(output_dir, "conf.npy"), np.round(prediction.conf, 2)) + if prediction.extrinsics is not None: + np.save(os.path.join(output_dir, "extrinsics.npy"), prediction.extrinsics) + if prediction.intrinsics is not None: + np.save(os.path.join(output_dir, "intrinsics.npy"), prediction.intrinsics) + + +@async_call +def export_to_npy( + prediction: Prediction, + export_dir: str, +): + output_dir = os.path.join(export_dir, "exports", "npy") + os.makedirs(output_dir, exist_ok=True) + + # Use prediction.processed_images, which is already processed image data + if prediction.processed_images is None: + raise ValueError("prediction.processed_images is required but not available") + + image = prediction.processed_images # (N,H,W,3) uint8 + + np.save(os.path.join(output_dir, "image.npy"), image) + np.save(os.path.join(output_dir, "depth.npy"), np.round(prediction.depth, 8)) + + if prediction.conf is not None: + np.save(os.path.join(output_dir, "conf.npy"), np.round(prediction.conf, 2)) + if prediction.extrinsics is not None: + np.save(os.path.join(output_dir, "extrinsics.npy"), prediction.extrinsics) + if prediction.intrinsics is not None: + np.save(os.path.join(output_dir, "intrinsics.npy"), prediction.intrinsics) \ No newline at end of file