feat(datascience): promover remove_background al registry + mask en depth_to_relief_glb (grupo img-to-3d)
Completa la promoción del flujo imagen->3D al registry (grupo de capacidad img-to-3d), extraído de la app img_to_3d_webapp. - remove_background_py_datascience (nueva): elimina el fondo con cascada rembg/U2Net -> OpenCV GrabCut -> umbral NumPy, compone el objeto sobre gris neutro y devuelve image + mask + engine. Impura, nunca lanza. Adaptada de backend/bg_removal.py con firma de ruta (image_path) y salida dict, demo CLI JSON-serializable. - depth_to_relief_glb_py_datascience (v1.1.0): añade el parámetro opcional mask para recortar la malla de relieve al objeto (descarta las caras del fondo), cerrando la cadena con remove_background. Aditivo (mask=None = comportamiento previo), fiel al original de backend/depth.py. - docs/capabilities/img-to-3d.md: incorpora remove_background como paso 0 (pre-proceso), actualiza el flujo a 3 pasos encadenados, la tabla de funciones (4), el ejemplo end-to-end con mask y las deps (rembg/opencv). - docs/capabilities/INDEX.md: conteo del grupo 3 -> 4. Las dos funciones ya presentes (estimate_image_depth, depth_to_relief_glb) y el pipeline build_relief_glb_from_image fueron promovidas en una ronda previa. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ def depth_to_relief_glb(
|
||||
out_glb_path: str,
|
||||
z_scale: float = 0.35,
|
||||
max_dim: int = 220,
|
||||
mask: "np.ndarray | None" = None,
|
||||
) -> dict:
|
||||
"""
|
||||
Construye una malla de relieve texturizada y la exporta como .glb.
|
||||
@@ -33,6 +34,9 @@ def depth_to_relief_glb(
|
||||
z_scale: amplitud del relieve (fracción del lado de la malla). Default 0.35.
|
||||
max_dim: lado máximo del grid tras downsample (controla nº de vértices/caras).
|
||||
Default 220 (~48k vértices, ~96k caras).
|
||||
mask: máscara opcional HxW (0..255, 255 = objeto), típicamente la "mask" devuelta por
|
||||
remove_background. Si se pasa, el fondo se aplana y las caras cuyos vértices caigan
|
||||
en el fondo se descartan: la malla contiene solo el objeto, sin el plano de fondo.
|
||||
|
||||
Devuelve (dict, nunca lanza):
|
||||
Éxito: {"status": "ok", "glb_path": out_glb_path, "vertices": int, "faces": int,
|
||||
@@ -58,6 +62,14 @@ def depth_to_relief_glb(
|
||||
depth = np.asarray(depth_img, dtype=np.float32) / 255.0
|
||||
H, W = depth.shape
|
||||
|
||||
# Si se pasó máscara (objeto vs fondo), reescalarla al grid ya downsampleado: el fondo
|
||||
# no aporta relieve (se aplana a 0) y luego sus caras se descartan, dejando solo el objeto.
|
||||
fg = None
|
||||
if mask is not None:
|
||||
mask_img = Image.fromarray(np.asarray(mask).astype(np.uint8)).resize((W, H), Image.NEAREST)
|
||||
fg = np.asarray(mask_img) >= 128
|
||||
depth = np.where(fg, depth, 0.0).astype(np.float32)
|
||||
|
||||
# Coordenadas del grid: X corrige aspect ratio, Y hacia abajo, Z = profundidad.
|
||||
aspect = W / float(H)
|
||||
xs = np.linspace(-aspect / 2.0, aspect / 2.0, W, dtype=np.float32)
|
||||
@@ -79,6 +91,12 @@ def depth_to_relief_glb(
|
||||
]
|
||||
)
|
||||
|
||||
# Con máscara: conservar solo las caras cuyos tres vértices son objeto. La malla queda
|
||||
# recortada al objeto, sin el plano de fondo que deformaría el relieve.
|
||||
if fg is not None:
|
||||
keep = fg.ravel()[faces].all(axis=1)
|
||||
faces = faces[keep]
|
||||
|
||||
# UV mapeando cada vértice al pixel de la imagen (V invertido para convención glTF).
|
||||
u = np.linspace(0.0, 1.0, W, dtype=np.float32)
|
||||
v = np.linspace(0.0, 1.0, H, dtype=np.float32)
|
||||
|
||||
Reference in New Issue
Block a user