character_openpose_editor / utils /image_processing.py
gearmachine's picture
feat: Add DWPose model management and error handling utilities
4555cad
# Image processing utilities for dwpose-editor
import numpy as np
import cv2
from PIL import Image
from .coordinate_system import CoordinateTransformer
from .notifications import notify_success, notify_error, NotificationMessages
def process_uploaded_image(image, target_size=(640, 640)):
"""
アップロードされた画像を処理
Args:
image: PIL Image or numpy array
target_size: 表示用のターゲットサイズ
Returns:
tuple: (processed_image, original_size, scale_info)
"""
try:
if image is None:
return None, None, None
# PIL ImageをNumPy配列に変換
if isinstance(image, Image.Image):
original_image = np.array(image)
else:
original_image = image
original_size = (original_image.shape[1], original_image.shape[0]) # (width, height)
# アスペクト比を保持してリサイズ
processed_image, scale_info = resize_with_aspect_ratio(
original_image, target_size
)
notify_success(NotificationMessages.IMAGE_UPLOADED)
return processed_image, original_size, scale_info
except Exception as e:
notify_error(f"画像処理中にエラーが発生しました: {str(e)}")
return None, None, None
def resize_with_aspect_ratio(image, target_size):
"""
アスペクト比を保持してリサイズ
Args:
image: numpy array
target_size: (width, height)
Returns:
tuple: (resized_image, scale_info)
"""
h, w = image.shape[:2]
target_w, target_h = target_size
# アスペクト比計算
scale = min(target_w / w, target_h / h)
new_w = int(w * scale)
new_h = int(h * scale)
# リサイズ
resized = cv2.resize(image, (new_w, new_h), interpolation=cv2.INTER_AREA)
# パディング(必要に応じて)
if new_w != target_w or new_h != target_h:
# 中央配置でパディング
pad_x = (target_w - new_w) // 2
pad_y = (target_h - new_h) // 2
if len(image.shape) == 3:
padded = np.full((target_h, target_w, image.shape[2]), 128, dtype=image.dtype)
else:
padded = np.full((target_h, target_w), 128, dtype=image.dtype)
padded[pad_y:pad_y+new_h, pad_x:pad_x+new_w] = resized
resized = padded
scale_info = {
'scale': scale,
'original_size': (w, h),
'resized_size': (new_w, new_h),
'final_size': target_size,
'padding': {
'x': pad_x if 'pad_x' in locals() else 0,
'y': pad_y if 'pad_y' in locals() else 0
}
}
return resized, scale_info
def create_background_canvas(image, canvas_size=(640, 640)):
"""
背景画像用のCanvasを作成
Args:
image: 背景画像
canvas_size: Canvasサイズ
Returns:
numpy array: Canvas用背景画像
"""
try:
if image is None:
# デフォルト背景
background = np.full((*canvas_size[::-1], 3), 240, dtype=np.uint8)
return background
# 画像をCanvasサイズに合わせてリサイズ
processed_image, _ = resize_with_aspect_ratio(image, canvas_size)
return processed_image
except Exception as e:
print(f"Background canvas creation error: {e}")
# エラー時はデフォルト背景
background = np.full((*canvas_size[::-1], 3), 240, dtype=np.uint8)
return background
def image_to_base64(image):
"""
画像をbase64文字列に変換(Canvas表示用)
Args:
image: numpy array or PIL Image
Returns:
str: base64エンコードされた画像データ
"""
try:
import base64
import io
if isinstance(image, np.ndarray):
# NumPy配列をPIL Imageに変換
if image.dtype != np.uint8:
image = (image * 255).astype(np.uint8)
pil_image = Image.fromarray(image)
else:
pil_image = image
# base64に変換
buffer = io.BytesIO()
pil_image.save(buffer, format='PNG')
img_str = base64.b64encode(buffer.getvalue()).decode()
return f"data:image/png;base64,{img_str}"
except Exception as e:
print(f"Image to base64 conversion error: {e}")
return None