File size: 16,884 Bytes
60c0c4a
f2385f0
60c0c4a
 
990379b
 
 
 
 
 
f2385f0
990379b
60c0c4a
f2385f0
60c0c4a
 
f2385f0
60c0c4a
 
 
 
 
 
 
990379b
60c0c4a
 
 
 
990379b
 
f2385f0
990379b
 
f2385f0
60c0c4a
 
f2385f0
60c0c4a
f2385f0
60c0c4a
 
 
f2385f0
990379b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60c0c4a
f2385f0
60c0c4a
 
 
990379b
 
60c0c4a
 
990379b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f2385f0
 
60c0c4a
f2385f0
60c0c4a
 
 
f2385f0
60c0c4a
 
990379b
 
 
60c0c4a
990379b
 
 
60c0c4a
990379b
60c0c4a
 
990379b
60c0c4a
 
990379b
 
 
 
 
 
 
 
f2385f0
990379b
60c0c4a
f2385f0
 
60c0c4a
 
f2385f0
990379b
60c0c4a
f2385f0
60c0c4a
 
f2385f0
990379b
 
60c0c4a
990379b
 
 
f2385f0
60c0c4a
990379b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60c0c4a
990379b
 
60c0c4a
 
990379b
 
f2385f0
 
60c0c4a
 
f2385f0
60c0c4a
 
f2385f0
990379b
60c0c4a
 
f2385f0
990379b
 
 
 
 
 
 
 
 
 
 
 
f2385f0
990379b
 
 
 
f2385f0
990379b
 
f2385f0
990379b
 
 
 
 
 
 
 
 
 
 
 
 
 
f2385f0
60c0c4a
f2385f0
60c0c4a
f2385f0
60c0c4a
f2385f0
 
60c0c4a
 
 
f2385f0
 
 
60c0c4a
 
f2385f0
60c0c4a
f2385f0
990379b
 
 
 
 
 
 
 
 
f2385f0
 
 
 
990379b
 
 
 
 
 
 
60c0c4a
990379b
 
 
 
 
 
 
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# app.py (Gradio界面)
import gradio as gr
import requests
from PIL import Image
import numpy as np
from sklearn.cluster import KMeans
import time
import random
import os
import torch

# 模型管理器
from models.model_manager import ModelManager

# 初始化模型管理器
model_manager = ModelManager()

def upload_and_analyze(image_path):
    """分析上传的图片"""
    try:
        if image_path is None:
            return {}, {}, []
        
        # 打开图片
        image = Image.open(image_path).convert('RGB')
        
        # 生成图像描述
        caption = model_manager.generate_caption(image)
        
        # 基于图像描述进行智能分析
        analysis_result = analyze_image_content(image, caption)
        
        # 基于分析结果生成个性化建议
        suggestions = generate_personalized_suggestions(analysis_result, caption)
        
        # 创建选择选项
        choices = list(suggestions.keys())
        
        return analysis_result, suggestions, gr.Radio(choices=choices, value=choices[0] if choices else None)
        
    except Exception as e:
        error_result = {"错误": f"分析失败: {str(e)}"}
        return error_result, {}, []

def analyze_image_content(image, caption):
    """基于图像和描述进行深度分析"""
    # 分析图像颜色
    colors = extract_dominant_colors(image)
    
    # 根据描述推断风格类型
    style_type = infer_style_from_caption(caption)
    
    # 根据描述推断服装类别
    clothing_category = infer_clothing_category(caption)
    
    # 根据风格推荐适合场景
    suitable_scenes = get_suitable_scenes(style_type)
    
    return {
        "图像描述": caption,
        "检测到的颜色": colors,
        "风格类型": style_type,
        "服装类别": clothing_category,
        "适合场景": suitable_scenes,
        "图像尺寸": f"{image.width} x {image.height}",
        "分析时间": time.strftime("%Y-%m-%d %H:%M:%S")
    }

def extract_dominant_colors(image):
    """提取图像主要颜色"""
    # 调整图像大小以提高处理速度
    image = image.resize((150, 150))
    
    # 转换为numpy数组
    img_array = np.array(image)
    
    # 重塑为颜色列表
    pixels = img_array.reshape(-1, 3)
    
    # 使用KMeans聚类找到主要颜色
    kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
    kmeans.fit(pixels)
    
    # 将RGB值转换为颜色名称
    color_names = []
    for color in kmeans.cluster_centers_:
        color_name = rgb_to_color_name(color)
        color_names.append(color_name)
    
    return color_names

def rgb_to_color_name(rgb):
    """将RGB值转换为颜色名称"""
    r, g, b = rgb.astype(int)
    
    # 简单的颜色映射
    if r > 200 and g > 200 and b > 200:
        return "白色"
    elif r < 50 and g < 50 and b < 50:
        return "黑色"
    elif r > g and r > b:
        if r > 150:
            return "红色"
        else:
            return "深红色"
    elif g > r and g > b:
        if g > 150:
            return "绿色"
        else:
            return "深绿色"
    elif b > r and b > g:
        if b > 150:
            return "蓝色"
        else:
            return "深蓝色"
    elif r > 150 and g > 150:
        return "黄色"
    elif r > 100 and b > 100:
        return "紫色"
    elif g > 100 and b > 100:
        return "青色"
    else:
        return "灰色"

def infer_style_from_caption(caption):
    """根据图像描述推断风格类型"""
    caption_lower = caption.lower()
    
    style_keywords = {
        "商务正装": ["suit", "formal", "business", "office", "professional", "tie", "blazer", "西装", "正装", "商务"],
        "休闲风": ["casual", "relaxed", "comfortable", "everyday", "jeans", "t-shirt", "休闲", "日常"],
        "运动风": ["sport", "athletic", "gym", "fitness", "running", "training", "运动", "健身"],
        "时尚潮流": ["fashion", "trendy", "stylish", "modern", "chic", "designer", "时尚", "潮流"],
        "复古风": ["vintage", "retro", "classic", "traditional", "old-fashioned", "复古", "经典"],
        "街头风": ["street", "urban", "hip-hop", "cool", "edgy", "街头", "嘻哈"],
        "优雅风": ["elegant", "sophisticated", "graceful", "refined", "classy", "优雅", "高贵"]
    }
    
    for style, keywords in style_keywords.items():
        if any(keyword in caption_lower for keyword in keywords):
            return style
    
    return "休闲风"  # 默认风格

def infer_clothing_category(caption):
    """根据描述推断服装类别"""
    caption_lower = caption.lower()
    
    categories = {
        "上衣": ["shirt", "blouse", "top", "jacket", "sweater", "hoodie", "blazer", "衬衫", "上衣", "外套"],
        "下装": ["pants", "jeans", "skirt", "shorts", "trousers", "裤子", "短裤", "裙子"],
        "连衣裙": ["dress", "gown", "frock", "连衣裙", "礼服"],
        "外套": ["coat", "jacket", "cardigan", "blazer", "外套", "大衣"],
        "配饰": ["hat", "bag", "shoes", "belt", "jewelry", "帽子", "包", "鞋子", "配饰"],
        "全套搭配": ["outfit", "ensemble", "look", "style", "搭配", "整套"]
    }
    
    for category, keywords in categories.items():
        if any(keyword in caption_lower for keyword in keywords):
            return category
    
    return "服装单品"  # 默认类别

def get_suitable_scenes(style_type):
    """根据风格类型推荐适合场景"""
    scene_mapping = {
        "商务正装": ["办公室", "商务会议", "正式场合", "面试"],
        "休闲风": ["日常出街", "朋友聚会", "购物", "咖啡约会"],
        "运动风": ["健身房", "运动", "户外活动", "晨跑"],
        "时尚潮流": ["时尚派对", "约会", "拍照", "社交活动"],
        "复古风": ["艺术展", "文艺活动", "复古主题活动", "拍摄"],
        "街头风": ["街拍", "音乐节", "朋友聚会", "潮流活动"],
        "优雅风": ["晚宴", "正式聚会", "典礼", "高端场所"]
    }
    
    return scene_mapping.get(style_type, ["日常", "休闲", "约会"])

def generate_personalized_suggestions(analysis_result, caption):
    """基于分析结果生成个性化建议"""
    style_type = analysis_result["风格类型"]
    clothing_category = analysis_result["服装类别"]
    colors = analysis_result["检测到的颜色"]
    
    suggestions = {}
    
    # 根据检测到的风格生成建议
    if style_type == "商务正装":
        suggestions = {
            "经典商务": f"保持{style_type}特色,搭配{colors[0]}系配饰",
            "现代商务": f"在{style_type}基础上加入现代元素",
            "休闲商务": f"将{style_type}与休闲元素结合",
            "时尚商务": f"{style_type}融入时尚潮流元素"
        }
    elif style_type == "休闲风":
        suggestions = {
            "舒适休闲": f"强化{style_type}的舒适感,主色调{colors[0]}",
            "时尚休闲": f"{style_type}加入时尚元素",
            "运动休闲": f"{style_type}融入运动风格",
            "优雅休闲": f"{style_type}提升优雅感"
        }
    elif style_type == "运动风":
        suggestions = {
            "专业运动": f"增强{style_type}的功能性",
            "休闲运动": f"{style_type}与日常穿着结合",
            "时尚运动": f"{style_type}加入潮流设计元素",
            "户外运动": f"强化{style_type}的户外适应性"
        }
    else:
        suggestions = {
            f"经典{style_type}": f"保持原有{style_type}特色",
            f"现代{style_type}": f"{style_type}加入现代元素",
            f"融合风格": f"{style_type}与其他风格混搭",
            f"个性化{style_type}": f"基于{colors[0]}色调的个性化{style_type}"
        }
    
    return suggestions

def generate_designs(selected_suggestion, progress=gr.Progress()):
    """根据选择的建议生成设计"""
    try:
        if not selected_suggestion:
            return [], gr.Radio(choices=[])
        
        progress(0.1, desc="准备设计提示...")
        
        # 生成设计图像的提示词
        design_prompts = {
            "经典商务": "professional business suit, modern cut, high-quality fabric, clean lines, neutral colors",
            "现代商务": "contemporary business attire, innovative design, slim fit, premium materials",
            "休闲商务": "business casual outfit, comfortable yet professional, versatile style",
            "时尚商务": "fashion-forward business wear, runway inspired, statement piece",
            "舒适休闲": "casual comfort wear, soft fabrics, relaxed fit, everyday style",
            "时尚休闲": "stylish casual outfit, trendy elements, urban chic",
            "运动休闲": "athleisure wear, sporty elements, comfortable and functional",
            "优雅休闲": "elegant casual attire, sophisticated details, refined look",
            "专业运动": "performance sportswear, technical fabrics, functional design",
            "休闲运动": "casual athletic wear, versatile for sports and daily use",
            "时尚运动": "fashion sportswear, trendy athletic style, streetwear influence",
            "户外运动": "outdoor adventure wear, durable materials, weather-resistant",
            "经典复古风": "vintage retro style, classic silhouette, nostalgic elements",
            "现代复古风": "contemporary take on retro fashion, updated classics",
            "融合风格": "fusion fashion, mixed styles, innovative combination",
            "个性化街头风": "personalized streetwear, unique designs, urban style",
            "经典优雅风": "timeless elegant fashion, sophisticated details, refined look",
            "现代优雅风": "modern elegant attire, contemporary sophistication"
        }
        
        prompt = design_prompts.get(selected_suggestion, "fashion design, stylish clothing")
        
        # 生成设计图像
        design_images = []
        design_choices = []
        
        for i in range(3):  # 生成3个设计
            try:
                progress(0.2 + i*0.25, desc=f"生成设计方案 {i+1}/3...")
                
                # 生成真实的设计图像
                image = model_manager.generate_image(
                    prompt=f"{prompt}, design {i+1}, high detail, fashion illustration",
                    negative_prompt="blurry, low quality, distorted, text, watermark",
                    num_inference_steps=30
                )
                
                if image:
                    design_images.append(image)
                    design_choices.append(f"{selected_suggestion} 设计方案 {i+1}")
            except Exception as e:
                print(f"生成设计 {i+1} 失败: {e}")
                # 创建占位图像
                width, height = 512, 512
                img = Image.new('RGB', (width, height), 
                               color=(random.randint(0, 255), 
                                      random.randint(0, 255), 
                                      random.randint(0, 255)))
                design_images.append(img)
                design_choices.append(f"{selected_suggestion} 设计方案 {i+1}")
        
        progress(0.95, desc="完成设计生成")
        return design_images, gr.Radio(choices=design_choices, value=design_choices[0] if design_choices else None)
        
    except Exception as e:
        print(f"设计生成错误: {e}")
        return [], gr.Radio(choices=[])

def generate_3d_fitting(selected_design, progress=gr.Progress()):
    """生成3D试穿效果"""
    try:
        if not selected_design:
            return None
        
        progress(0.1, desc="准备3D试穿...")
        
        # 生成3D试穿效果的提示词
        fitting_prompt = f"3D fashion fitting, virtual try-on, {selected_design}, realistic human model, full body, studio lighting"
        
        progress(0.3, desc="生成3D模型...")
        
        # 使用模型生成3D试穿图像
        if model_manager.controlnet_pipeline:
            # 如果有ControlNet,使用更高级的生成
            try:
                # 这里简化了ControlNet的使用,实际需要姿势图等输入
                image = model_manager.controlnet_pipeline(
                    prompt=fitting_prompt,
                    negative_prompt="blurry, distorted, low quality, unrealistic, extra limbs",
                    num_inference_steps=35,
                    guidance_scale=8.0
                ).images[0]
                progress(0.9, desc="渲染3D效果")
                return image
            except Exception as e:
                print(f"使用ControlNet生成失败: {e}")
        
        # 回退到普通SD模型
        progress(0.4, desc="使用标准模型生成...")
        image = model_manager.generate_image(
            prompt=fitting_prompt,
            negative_prompt="blurry, distorted, low quality, unrealistic, extra limbs",
            num_inference_steps=35
        )
        
        progress(0.9, desc="完成3D渲染")
        return image
        
    except Exception as e:
        print(f"3D试穿生成错误: {e}")
        return None

def create_gradio_interface():
    """创建Gradio用户界面"""
    
    with gr.Blocks(title="AI时尚设计师", theme="soft") as demo:
        gr.Markdown("# 🎨 AI时尚设计师")
        gr.Markdown("上传图片,获得专业的服装设计建议和3D试穿效果")
        
        with gr.Row():
            with gr.Column(scale=1):
                image_input = gr.Image(type="filepath", label="上传参考图片", height=400)
                analyze_btn = gr.Button("分析风格", variant="primary")
            
            with gr.Column(scale=2):
                analysis_output = gr.JSON(label="风格分析结果")
        
        with gr.Tab("设计建议"):
            suggestions_output = gr.JSON(label="个性化设计建议")
            suggestion_choice = gr.Radio(label="选择设计方向", interactive=True)
            generate_designs_btn = gr.Button("生成设计方案", variant="primary")
        
        with gr.Tab("样衣设计"):
            designs_gallery = gr.Gallery(label="样衣设计图", columns=3, height=400)
            design_choice = gr.Radio(label="选择设计方案", interactive=True)
            generate_3d_btn = gr.Button("生成3D试穿效果", variant="primary")
        
        with gr.Tab("3D试穿效果"):
            fitting_result = gr.Image(label="3D试穿效果", height=500)
        
        # 添加示例图片
        examples_dir = "examples"
        if os.path.exists(examples_dir):
            example_files = [os.path.join(examples_dir, f) for f in os.listdir(examples_dir) 
                            if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
            
            gr.Examples(
                examples=example_files[:4],  # 最多显示4个示例
                inputs=image_input,
                outputs=[analysis_output, suggestions_output, suggestion_choice],
                fn=upload_and_analyze,
                cache_examples=True,
                label="示例图片"
            )
        
        # 事件绑定
        analyze_btn.click(
            fn=upload_and_analyze,
            inputs=[image_input],
            outputs=[analysis_output, suggestions_output, suggestion_choice]
        )
        
        generate_designs_btn.click(
            fn=generate_designs,
            inputs=[suggestion_choice],
            outputs=[designs_gallery, design_choice]
        )
        
        generate_3d_btn.click(
            fn=generate_3d_fitting,
            inputs=[design_choice],
            outputs=[fitting_result]
        )
        
        # 添加清理按钮
        clear_btn = gr.Button("清理内存", variant="secondary")
        clear_btn.click(
            fn=model_manager.cleanup,
            inputs=[],
            outputs=[]
        )
        gr.Markdown("> **提示**: 生成图像后,点击'清理内存'按钮可以释放GPU资源")
    
    return demo

if __name__ == "__main__":
    # 检查并创建示例目录
    examples_dir = "examples"
    if not os.path.exists(examples_dir):
        os.makedirs(examples_dir)
        print(f"创建了示例目录: {examples_dir}")
        print("请在此目录中添加示例图片以便在界面中使用")
    
    demo = create_gradio_interface()
    demo.queue(concurrency_count=1)  # 限制并发以避免内存问题
    demo.launch(
        server_name="0.0.0.0", 
        server_port=7860, 
        share=True,
        favicon_path="favicon.ico" if os.path.exists("favicon.ico") else None
    )