From 303553835608eb935080ccb42d496c174184ecc2 Mon Sep 17 00:00:00 2001 From: u201311 Date: Tue, 13 Jan 2026 16:35:52 +0800 Subject: [PATCH] add img_to_3d service --- .../example_image => demo}/sample_18.jpg | Bin img_to_3d_service.py | 85 ++++++++++++++++++ scripts/run_service.sh | 4 + 3 files changed, 89 insertions(+) rename {apps/assets/example_image => demo}/sample_18.jpg (100%) create mode 100644 img_to_3d_service.py create mode 100644 scripts/run_service.sh diff --git a/apps/assets/example_image/sample_18.jpg b/demo/sample_18.jpg similarity index 100% rename from apps/assets/example_image/sample_18.jpg rename to demo/sample_18.jpg diff --git a/img_to_3d_service.py b/img_to_3d_service.py new file mode 100644 index 0000000..17bd211 --- /dev/null +++ b/img_to_3d_service.py @@ -0,0 +1,85 @@ +import os +import sys +import uvicorn +from fastapi import FastAPI, HTTPException +from pydantic import BaseModel, Field +from typing import List, Optional + +# Ensure the project root is in sys.path +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +try: + # Attempt to import the entrypoint from the existing script + # This assumes the environment is set up correctly with all dependencies + from embodied_gen.scripts.imageto3d import entrypoint +except ImportError as e: + print(f"Error importing embodied_gen: {e}") + print("Please ensure you are running this script from the project root and environment is configured.") + sys.exit(1) + +app = FastAPI(title="Image to 3D Service") + +class ImageTo3DRequest(BaseModel): + image_paths: List[str] = Field(..., description="Path to the input images (e.g. apps/assets/example_image/sample_00.jpg)") + output_root: str = Field(..., description="Root directory for saving outputs (e.g. outputs/imageto3d)") + n_retry: int = Field(2, description="Number of retries") + + # Optional parameters mirroring the CLI arguments + height_range: Optional[str] = None + mass_range: Optional[str] = None + asset_type: Optional[List[str]] = None + skip_exists: bool = False + version: Optional[str] = None + keep_intermediate: bool = False + seed: int = 0 + disable_decompose_convex: bool = False + texture_size: int = 2048 + +@app.post("/process") +async def process_images(request: ImageTo3DRequest): + """ + HTTP wrapper for img3d-cli. + """ + # 1. Validate inputs + for path in request.image_paths: + if not os.path.exists(path): + raise HTTPException(status_code=400, detail=f"Image path does not exist: {path}") + + # 2. Invoke the processing logic + try: + # entrypoint() in imageto3d.py accepts **kwargs to override parsed args + entrypoint( + image_path=request.image_paths, + output_root=request.output_root, + n_retry=request.n_retry, + + # Optional args + height_range=request.height_range, + mass_range=request.mass_range, + asset_type=request.asset_type, + skip_exists=request.skip_exists, + version=request.version, + keep_intermediate=request.keep_intermediate, + seed=request.seed, + disable_decompose_convex=request.disable_decompose_convex, + texture_size=request.texture_size + ) + + return { + "status": "success", + "message": "Processing completed.", + "output_root": request.output_root, + "inputs": request.image_paths + } + + except Exception as e: + # Catch errors from the processing pipeline + raise HTTPException(status_code=500, detail=f"Processing failed: {str(e)}") + +@app.get("/health") +def health(): + return {"status": "ok"} + +if __name__ == "__main__": + # Run server on port 8000 + uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/scripts/run_service.sh b/scripts/run_service.sh new file mode 100644 index 0000000..5ab6477 --- /dev/null +++ b/scripts/run_service.sh @@ -0,0 +1,4 @@ +CUDA_VISIBLE_DEVICES=0 python img_to_3d_service.py + + +curl -X POST "http://localhost:8000/process" -H "Content-Type: application/json" -d '{"image_paths": ["apps/assets/example_image/sample_26.jpg"], "n_retry": 2, "output_root": "outputs/imageto3d"}' \ No newline at end of file