Fooocus/modules/image_editor.py

105 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""OpenCV-based image adjustment utilities for the gallery editor."""
import cv2
import numpy as np
# ────────────────────────────────────────────────
# ユーティリティ
# ────────────────────────────────────────────────
def resize_for_preview(img_array, max_size=768):
"""プレビュー用にアスペクト比を保ってリサイズ(高速化)。"""
if img_array is None:
return None
h, w = img_array.shape[:2]
if max(h, w) <= max_size:
return img_array
scale = max_size / max(h, w)
nw, nh = int(w * scale), int(h * scale)
return cv2.resize(img_array, (nw, nh), interpolation=cv2.INTER_AREA)
def rotate_image(img_array, degrees):
"""画像を 90 / 180 / 270 度回転RGB 入出力)。"""
if img_array is None:
return None
degrees = int(degrees) % 360
if degrees == 90:
return cv2.rotate(img_array, cv2.ROTATE_90_CLOCKWISE)
elif degrees == 180:
return cv2.rotate(img_array, cv2.ROTATE_180)
elif degrees == 270:
return cv2.rotate(img_array, cv2.ROTATE_90_COUNTERCLOCKWISE)
return img_array
def flip_image(img_array, direction='h'):
"""水平('h') または垂直('v') 反転RGB 入出力)。"""
if img_array is None:
return None
code = 1 if direction == 'h' else 0
return cv2.flip(img_array, code)
# ────────────────────────────────────────────────
# メイン調整関数
# ────────────────────────────────────────────────
def apply_adjustments(img_array,
brightness=0, contrast=1.0,
saturation=1.0, hue_shift=0,
sharpness=1.0, temperature=0):
"""OpenCV で画像調整を適用する。
Parameters
----------
img_array : numpy ndarray (H, W, 3) RGB
brightness : int -100 … 100 加算
contrast : float 0.1 … 3.0 乗算
saturation : float 0.0 … 3.0 HSV S 倍率
hue_shift : int -90 … 90 HSV H 加算(度)
sharpness : float 0.0 … 3.0 1.0=変化なし / >1=鮮明 / <1=ぼかし
temperature : int -100 … 100 負=クール(青) / 正=ウォーム(赤)
Returns
-------
numpy ndarray (H, W, 3) RGB
"""
if img_array is None:
return None
img = np.clip(img_array, 0, 255).astype(np.uint8)
bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
# ── 明るさ / コントラスト ──────────────────────
if brightness != 0 or contrast != 1.0:
bgr = cv2.convertScaleAbs(bgr, alpha=float(contrast), beta=float(brightness))
# ── 彩度 / 色相 ────────────────────────────────
if saturation != 1.0 or hue_shift != 0:
hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV).astype(np.float32)
hsv[:, :, 0] = (hsv[:, :, 0] + float(hue_shift)) % 180
hsv[:, :, 1] = np.clip(hsv[:, :, 1] * float(saturation), 0, 255)
bgr = cv2.cvtColor(hsv.astype(np.uint8), cv2.COLOR_HSV2BGR)
# ── 色温度 ─────────────────────────────────────
if temperature != 0:
b, g, r = cv2.split(bgr.astype(np.float32))
t = float(temperature)
if t > 0: # ウォーム (赤+, 青-)
r = np.clip(r + t * 0.8, 0, 255)
b = np.clip(b - t * 0.4, 0, 255)
else: # クール (青+, 赤-)
r = np.clip(r + t * 0.4, 0, 255)
b = np.clip(b - t * 0.8, 0, 255)
bgr = cv2.merge([b.astype(np.uint8), g.astype(np.uint8), r.astype(np.uint8)])
# ── シャープネス(アンシャープマスク)─────────
if sharpness != 1.0:
blur = cv2.GaussianBlur(bgr, (0, 0), 3.0)
strength = float(sharpness) - 1.0
bgr = cv2.addWeighted(bgr, 1.0 + strength, blur, -strength, 0)
bgr = np.clip(bgr, 0, 255).astype(np.uint8)
return cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)