DimensioDepth / backend /utils /image_processing.py
wwieerrz's picture
🎨 Launch DimensioDepth - Advanced AI Depth Estimation
463afdd
import cv2
import numpy as np
from PIL import Image
import io
import base64
from typing import Tuple, Optional
def load_image_from_bytes(image_bytes: bytes) -> np.ndarray:
"""
Load image from bytes into numpy array
Args:
image_bytes: Raw image bytes
Returns:
Image as RGB numpy array
"""
image = Image.open(io.BytesIO(image_bytes))
# Convert to RGB if needed
if image.mode != 'RGB':
image = image.convert('RGB')
return np.array(image)
def load_image_from_base64(base64_string: str) -> np.ndarray:
"""
Load image from base64 string
Args:
base64_string: Base64 encoded image
Returns:
Image as RGB numpy array
"""
# Remove data URL prefix if present
if ',' in base64_string:
base64_string = base64_string.split(',')[1]
image_bytes = base64.b64decode(base64_string)
return load_image_from_bytes(image_bytes)
def resize_image(
image: np.ndarray,
target_size: int,
maintain_aspect: bool = True
) -> Tuple[np.ndarray, Tuple[int, int]]:
"""
Resize image to target size
Args:
image: Input image array
target_size: Target size (will be longest edge if maintain_aspect=True)
maintain_aspect: Whether to maintain aspect ratio
Returns:
Tuple of (resized_image, original_size)
"""
h, w = image.shape[:2]
original_size = (w, h)
if maintain_aspect:
# Calculate new dimensions maintaining aspect ratio
if h > w:
new_h = target_size
new_w = int(w * (target_size / h))
else:
new_w = target_size
new_h = int(h * (target_size / w))
else:
new_w = target_size
new_h = target_size
resized = cv2.resize(image, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
return resized, original_size
def normalize_image(image: np.ndarray) -> np.ndarray:
"""
Normalize image for model input
Args:
image: Input image array (RGB)
Returns:
Normalized image array
"""
# Convert to float32 and normalize to [0, 1]
image = image.astype(np.float32) / 255.0
# ImageNet normalization
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = (image - mean) / std
return image
def depth_to_colormap(
depth: np.ndarray,
colormap: int = cv2.COLORMAP_INFERNO
) -> np.ndarray:
"""
Convert depth map to colorized visualization
Args:
depth: Depth map array
colormap: OpenCV colormap constant
Returns:
Colorized depth map (RGB)
"""
# Normalize depth to 0-255
depth_normalized = cv2.normalize(depth, None, 0, 255, cv2.NORM_MINMAX)
depth_uint8 = depth_normalized.astype(np.uint8)
# Apply colormap
colored = cv2.applyColorMap(depth_uint8, colormap)
# Convert BGR to RGB
colored = cv2.cvtColor(colored, cv2.COLOR_BGR2RGB)
return colored
def array_to_base64(image: np.ndarray, format: str = 'PNG') -> str:
"""
Convert numpy array to base64 string
Args:
image: Image array
format: Output format (PNG, JPEG, etc.)
Returns:
Base64 encoded image string
"""
pil_image = Image.fromarray(image.astype(np.uint8))
buffer = io.BytesIO()
pil_image.save(buffer, format=format)
buffer.seek(0)
base64_string = base64.b64encode(buffer.read()).decode('utf-8')
return f"data:image/{format.lower()};base64,{base64_string}"
def array_to_bytes(image: np.ndarray, format: str = 'PNG') -> bytes:
"""
Convert numpy array to bytes
Args:
image: Image array
format: Output format (PNG, JPEG, etc.)
Returns:
Image bytes
"""
pil_image = Image.fromarray(image.astype(np.uint8))
buffer = io.BytesIO()
pil_image.save(buffer, format=format)
buffer.seek(0)
return buffer.read()
def create_side_by_side(
original: np.ndarray,
depth: np.ndarray,
colormap: bool = True
) -> np.ndarray:
"""
Create side-by-side comparison of original and depth
Args:
original: Original image
depth: Depth map
colormap: Whether to apply colormap to depth
Returns:
Side-by-side image
"""
# Ensure same height
h = original.shape[0]
depth_resized = cv2.resize(depth, (depth.shape[1], h))
if colormap and len(depth_resized.shape) == 2:
depth_resized = depth_to_colormap(depth_resized)
# Concatenate horizontally
combined = np.hstack([original, depth_resized])
return combined