File size: 11,150 Bytes
c290e43 c645839 df2abe8 c645839 df2abe8 2bc8286 c645839 6ff0647 343349d cf5b603 89f7e0d ffa8ad6 343349d c645839 9bd137d df2abe8 9bd137d df2abe8 9bd137d df2abe8 9bd137d df2abe8 9bd137d df2abe8 9bd137d df2abe8 9bd137d df2abe8 9bd137d 5647bfd 9bd137d df2abe8 9bd137d ffa8ad6 9bd137d ffa8ad6 9bd137d df2abe8 9bd137d df2abe8 9bd137d 343349d 9bd137d 343349d 9bd137d ffa8ad6 9bd137d c645839 9bd137d ffa8ad6 9bd137d df2abe8 9bd137d c645839 9bd137d c645839 9bd137d c645839 9bd137d ffa8ad6 c645839 9bd137d ffa8ad6 9bd137d d20b726 9bd137d d20b726 c645839 9bd137d df2abe8 9bd137d df2abe8 9bd137d df2abe8 9bd137d ffa8ad6 9bd137d df2abe8 9bd137d df2abe8 9bd137d c290e43 9bd137d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
import gradio as gr
import os
from PIL import Image, ImageDraw, ImageFont, ImageEnhance, ImageFilter
import requests
import io
import gc
import json
from typing import Tuple, Optional, Dict, Any, List
import logging
from dotenv import load_dotenv
import numpy as np
import cv2
from skimage import exposure
import torch
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
load_dotenv()
# Constantes pour les styles disponibles
STYLE_CATEGORIES = {
"TRADITIONAL": {
"Renaissance": {
"prompt": "renaissance style masterpiece, anatomical precision, detailed texture, chiaroscuro lighting, oil painting technique, museum quality",
"negative_prompt": "modern, abstract, simple, flat, digital art",
"params": {
"guidance_scale": 9.0,
"num_inference_steps": 50,
"resolution": (4096, 4096),
"detail_threshold": 0.95,
}
},
"Impressionnisme": {
"prompt": "impressionist style, loose brushstrokes, natural light, vivid colors, en plein air painting",
"negative_prompt": "sharp details, digital art, modern",
"params": {
"guidance_scale": 7.5,
"num_inference_steps": 40,
"resolution": (2048, 2048),
"brush_simulation": True,
}
},
# ... autres styles traditionnels
},
"DIGITAL": {
"Cyberpunk": {
"prompt": "cyberpunk style, neon lights, volumetric fog, tech noir, high contrast, futuristic city",
"negative_prompt": "natural, vintage, traditional art",
"params": {
"guidance_scale": 8.0,
"neon_intensity": 1.5,
"volumetric_lighting": True,
"resolution": (3840, 2160),
}
},
"Holographique": {
"prompt": "holographic effect, iridescent colors, light refraction, transparent layers, futuristic",
"negative_prompt": "flat, matte, solid colors",
"params": {
"iridescence": 1.0,
"transparency": 0.7,
"resolution": (2560, 1440),
}
},
# ... autres styles numériques
}
}
class TextEffectProcessor:
def __init__(self):
self.effects = {
"Réaliste": self._realistic_text,
"Néon": self._neon_text,
"Holographique": self._holographic_text,
"3D": self._3d_text,
"Vintage": self._vintage_text,
"Graffiti": self._graffiti_text,
"Matrix": self._matrix_text
}
def apply_effect(self, image: Image.Image, text: str, effect: str, position: Tuple[int, int]) -> Image.Image:
if effect in self.effects:
return self.effects[effect](image, text, position)
return self._default_text(image, text, position)
def _realistic_text(self, image: Image.Image, text: str, position: Tuple[int, int]) -> Image.Image:
try:
draw = ImageDraw.Draw(image)
# Chargement d'une police par défaut
font = ImageFont.load_default()
# Effet d'ombre réaliste
shadow_offset = 2
# Dessiner l'ombre
draw.text((position[0] + shadow_offset, position[1] + shadow_offset),
text, font=font, fill=(0, 0, 0, 128))
# Dessiner le texte principal
draw.text(position, text, font=font, fill=(255, 255, 255))
return image
except Exception as e:
logger.error(f"Erreur lors du rendu réaliste: {str(e)}")
return image
def _neon_text(self, image: Image.Image, text: str, position: Tuple[int, int]) -> Image.Image:
try:
# Création d'un calque pour le texte néon
text_layer = Image.new('RGBA', image.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(text_layer)
font = ImageFont.load_default()
# Effet de glow
glow_colors = [(255, 182, 193), (255, 192, 203), (255, 202, 213)]
for i, color in enumerate(glow_colors):
offset = (3 - i) * 2
draw.text((position[0] - offset, position[1] - offset),
text, font=font, fill=color + (150,))
# Texte principal
draw.text(position, text, font=font, fill=(255, 255, 255, 255))
# Fusion des calques
return Image.alpha_composite(image.convert('RGBA'), text_layer)
except Exception as e:
logger.error(f"Erreur lors du rendu néon: {str(e)}")
return image
# ... autres méthodes d'effets de texte
class ImageGenerator:
def __init__(self):
self.api_url = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0"
self.headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_TOKEN')}"}
self.text_processor = TextEffectProcessor()
async def generate_image(self, prompt: str, style_category: str, style_name: str,
text: Optional[str] = None, text_effect: Optional[str] = None,
position: Optional[Tuple[int, int]] = None) -> Tuple[Optional[Image.Image], str]:
try:
# Récupération des paramètres du style
style_info = STYLE_CATEGORIES[style_category][style_name]
# Construction du prompt final
final_prompt = f"{style_info['prompt']}, {prompt}"
# Paramètres de génération
generation_params = {
"inputs": final_prompt,
"negative_prompt": style_info["negative_prompt"],
"num_inference_steps": style_info["params"]["num_inference_steps"],
"guidance_scale": style_info["params"]["guidance_scale"],
}
# Appel à l'API
response = requests.post(
self.api_url,
headers=self.headers,
json=generation_params,
timeout=30
)
if response.status_code != 200:
return None, f"Erreur API: {response.status_code}"
# Traitement de l'image générée
image = Image.open(io.BytesIO(response.content))
# Application des effets de style spécifiques
image = self._apply_style_effects(image, style_info["params"])
# Ajout de texte si demandé
if text and text_effect:
image = self.text_processor.apply_effect(
image, text, text_effect,
position or (image.width//2, image.height//2)
)
return image, "Génération réussie!"
except Exception as e:
logger.error(f"Erreur lors de la génération: {str(e)}")
return None, f"Erreur: {str(e)}"
def _apply_style_effects(self, image: Image.Image, style_params: Dict) -> Image.Image:
"""Application des effets spécifiques au style"""
try:
# Conversion pour traitement
img_array = np.array(image)
# Application des effets selon les paramètres
if style_params.get("neon_intensity"):
img_array = self._apply_neon_effect(img_array, style_params["neon_intensity"])
if style_params.get("volumetric_lighting"):
img_array = self._apply_volumetric_lighting(img_array)
# Reconversion en image PIL
return Image.fromarray(img_array)
except Exception as e:
logger.error(f"Erreur lors de l'application des effets: {str(e)}")
return image
def _apply_neon_effect(self, img_array: np.ndarray, intensity: float) -> np.ndarray:
"""Applique un effet néon à l'image"""
# Conversion en HSV pour manipulation des couleurs
hsv = cv2.cvtColor(img_array, cv2.COLOR_RGB2HSV)
# Augmentation de la saturation
hsv[..., 1] = np.clip(hsv[..., 1] * intensity, 0, 255)
return cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
def _apply_volumetric_lighting(self, img_array: np.ndarray) -> np.ndarray:
"""Ajoute un effet de lumière volumétrique"""
# Création d'un masque de luminosité
gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
blur = cv2.GaussianBlur(gray, (0, 0), 15)
return cv2.addWeighted(img_array, 1, cv2.cvtColor(blur, cv2.COLOR_GRAY2RGB), 0.2, 0)
def create_interface():
generator = ImageGenerator()
with gr.Blocks() as demo:
gr.HTML("""<h1 style='text-align: center'>🎨 Equity Art Engine</h1>""")
with gr.Row():
with gr.Column(scale=1):
# Contrôles de génération
prompt = gr.Textbox(label="Description de l'image")
style_category = gr.Dropdown(
choices=list(STYLE_CATEGORIES.keys()),
label="Catégorie de Style"
)
style_name = gr.Dropdown(
label="Style Spécifique"
)
# Mise à jour dynamique des styles disponibles
def update_styles(category):
return gr.Dropdown.update(
choices=list(STYLE_CATEGORIES[category].keys())
)
style_category.change(
update_styles,
inputs=[style_category],
outputs=[style_name]
)
# Contrôles de texte
text_input = gr.Textbox(label="Texte à ajouter (optionnel)")
text_effect = gr.Dropdown(
choices=["Réaliste", "Néon", "Holographique", "3D", "Vintage", "Graffiti", "Matrix"],
label="Effet de texte"
)
with gr.Column(scale=2):
# Zone de résultat
image_output = gr.Image(label="Image générée")
status_output = gr.Textbox(label="Status")
# Bouton de génération
generate_btn = gr.Button("Générer")
# Logique de génération
def generate(prompt, category, style, text, effect):
if not prompt or not category or not style:
return None, "Veuillez remplir tous les champs requis"
image, status = generator.generate_image(
prompt=prompt,
style_category=category,
style_name=style,
text=text if text else None,
text_effect=effect if text else None
)
return image, status
generate_btn.click(
generate,
inputs=[prompt, style_category, style_name, text_input, text_effect],
outputs=[image_output, status_output]
)
return demo
if __name__ == "__main__":
demo = create_interface()
demo.launch() |