STLooo commited on
Commit
57ec27f
·
verified ·
1 Parent(s): a571ccf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +79 -81
app.py CHANGED
@@ -3,125 +3,123 @@ import numpy as np
3
  import os
4
  import gradio as gr
5
  import gc
 
6
 
7
- # 常量配置
8
  MAX_FILES = 250
9
- BG_PATH = "background.jpg"
10
  FG_DIR = "foregrounds"
11
  OUTPUT_DIR = "output"
12
- os.makedirs(FG_DIR, exist_ok=True)
13
- os.makedirs(OUTPUT_DIR, exist_ok=True)
 
 
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def overlay_image(bg, fg, x, y):
16
- """高效合成函数(内存优化)"""
17
- alpha = fg[:, :, 3:] / 255.0
18
- bg[y:y+fg.shape[0], x:x+fg.shape[1]] = alpha * fg[:, :, :3] + (1 - alpha) * bg[y:y+fg.shape[0], x:x+fg.shape[1]]
 
 
 
 
 
 
 
19
  return bg
20
 
21
- def save_background(file):
22
- """正确处理上传的背景图"""
23
- if file is None:
24
- return "请上传背景图"
25
- try:
26
- with open(file.name, 'rb') as f:
27
- img_data = np.frombuffer(f.read(), np.uint8)
28
- img = cv2.imdecode(img_data, cv2.IMREAD_COLOR)
29
- cv2.imwrite(BG_PATH, img)
30
- return "背景图已更新!"
31
- except Exception as e:
32
- return f"背景图更新失败: {str(e)}"
33
 
 
34
  def process_images(fg_files):
35
  try:
36
  progress = gr.Progress()
37
- progress(0, desc="正在准备...")
38
-
39
- # 检查上传数量
40
- num_files = len(fg_files)
41
- if num_files > MAX_FILES:
42
- raise gr.Error(f"最多支 {MAX_FILES} 张前景图!")
43
- if num_files == 0:
44
- return [], "没有可处理的图片"
45
-
46
- # 读取背景图
47
  bg = cv2.imread(BG_PATH)
48
  if bg is None:
49
- raise gr.Error("请先上传背景图!")
 
 
 
 
 
50
 
51
  results = []
52
  for i, fg_file in enumerate(fg_files, 1):
53
- progress(i/len(fg_files), f"合成 ({i}/{len(fg_files)})")
54
-
55
  try:
56
- # 读取前景图
57
  with open(fg_file.name, 'rb') as f:
58
  fg_data = np.frombuffer(f.read(), np.uint8)
59
  fg = cv2.imdecode(fg_data, cv2.IMREAD_UNCHANGED)
60
  if fg is None:
61
  continue
62
-
63
- # 调整大小
64
- fg = cv2.resize(fg, (300, int(300 * fg.shape[0] / fg.shape[1])))
65
-
66
- # 合成图片
67
- result = overlay_image(bg.copy(), fg, 100, 50)
68
- result = overlay_image(result, fg, 400, 50)
69
-
70
- # 保存结果
71
  output_path = f"{OUTPUT_DIR}/result_{i:03d}.jpg"
72
  cv2.imwrite(output_path, result)
73
-
74
- # 将图片路径转换为可显示的格式
75
- results.append(output_path)
76
-
77
- # 定期清理内存
78
  if i % 10 == 0:
79
  gc.collect()
80
-
81
  except Exception as e:
82
- print(f"理 {fg_file.name} 失: {str(e)}")
83
  continue
84
 
85
- progress(1, "处理完成!")
86
-
87
- # 确保返回格式正确:图列表 + 日志消息
88
- if not results:
89
- return [], "没有生成有效结果"
90
-
91
- # 将图片路径转换为可显示的格式
92
- display_results = [(img_path,) for img_path in results]
93
- return display_results, f"成功处理 {len(results)}/{num_files} 张图片"
94
 
95
  except Exception as e:
96
- raise gr.Error(f"理出错: {str(e)}")
97
 
98
- # Gradio
99
  with gr.Blocks() as demo:
100
- gr.Markdown("## 🖼️ 灵活图片合成工具 (1~250张)")
101
-
102
- with gr.Row():
103
- bg_upload = gr.File(label="1. 上传背景图", file_types=[".jpg", ".png"])
104
- fg_upload = gr.Files(
105
- label=f"2. 上传前景图 (1~{MAX_FILES}张)",
106
- file_types=[".png"]
107
- )
108
- btn_run = gr.Button("开始合成", variant="primary")
109
-
110
  with gr.Row():
111
- gallery = gr.Gallery(label="合成果", columns=5)
112
- log_output = gr.Textbox(label="日志", interactive=False)
113
-
114
- # 事件绑定
115
- bg_upload.upload(
116
- fn=save_background,
117
- inputs=bg_upload,
118
- outputs=log_output
119
- )
120
-
121
  btn_run.click(
122
  fn=process_images,
123
  inputs=fg_upload,
124
- outputs=[gallery, log_output],
125
  concurrency_limit=4
126
  )
127
 
 
3
  import os
4
  import gradio as gr
5
  import gc
6
+ import zipfile
7
 
8
+ # 常量設定
9
  MAX_FILES = 250
10
+ BG_PATH = "background.jpg" # 預設背景圖,請自行放置
11
  FG_DIR = "foregrounds"
12
  OUTPUT_DIR = "output"
13
+ ZIP_PATH = "output/results.zip"
14
+ TARGET_WIDTH, TARGET_HEIGHT = 2133, 1200
15
+ POS1 = (1032, 0)
16
+ POS2 = (4666, 0)
17
 
18
+ # 初始化資料夾與權限檢查
19
+ def check_write_permission(path):
20
+ if not os.path.exists(path):
21
+ try:
22
+ os.makedirs(path)
23
+ except Exception as e:
24
+ raise RuntimeError(f"❌ 無法建立目錄 '{path}':{e}")
25
+ elif not os.access(path, os.W_OK):
26
+ raise RuntimeError(f"❌ 目錄 '{path}' 存在,但沒有寫入權限!")
27
+
28
+ check_write_permission(FG_DIR)
29
+ check_write_permission(OUTPUT_DIR)
30
+
31
+ # 合成圖片
32
  def overlay_image(bg, fg, x, y):
33
+ h, w = fg.shape[:2]
34
+ bh, bw = bg.shape[:2]
35
+ if x + w > bw or y + h > bh:
36
+ raise ValueError(f"前景圖超出背景邊界:({x},{y},{w},{h}) > 背景({bw},{bh})")
37
+
38
+ if fg.shape[2] == 4:
39
+ alpha = fg[:, :, 3:] / 255.0
40
+ bg[y:y+h, x:x+w] = alpha * fg[:, :, :3] + (1 - alpha) * bg[y:y+h, x:x+w]
41
+ else:
42
+ bg[y:y+h, x:x+w] = fg[:, :, :3]
43
  return bg
44
 
45
+ # 壓縮成 zip
46
+ def zip_output_files():
47
+ with zipfile.ZipFile(ZIP_PATH, "w", zipfile.ZIP_DEFLATED) as zipf:
48
+ for file in sorted(os.listdir(OUTPUT_DIR)):
49
+ if file.endswith(".jpg"):
50
+ zipf.write(os.path.join(OUTPUT_DIR, file), arcname=file)
51
+ return ZIP_PATH
 
 
 
 
 
52
 
53
+ # 處理合成流程
54
  def process_images(fg_files):
55
  try:
56
  progress = gr.Progress()
57
+ progress(0, desc="準備中...")
58
+
59
+ if len(fg_files) == 0:
60
+ return [], None, "請至少上傳一張前景圖"
61
+ if len(fg_files) > MAX_FILES:
62
+ raise gr.Error(f"最多支 {MAX_FILES} 張圖片")
63
+
 
 
 
64
  bg = cv2.imread(BG_PATH)
65
  if bg is None:
66
+ raise gr.Error("無法讀取背景圖(請確認 background.jpg 是否存在)")
67
+
68
+ # 清除舊結果
69
+ for f in os.listdir(OUTPUT_DIR):
70
+ if f.endswith(".jpg"):
71
+ os.remove(os.path.join(OUTPUT_DIR, f))
72
 
73
  results = []
74
  for i, fg_file in enumerate(fg_files, 1):
75
+ progress(i / len(fg_files), f"合成 {i} 張圖...")
76
+
77
  try:
 
78
  with open(fg_file.name, 'rb') as f:
79
  fg_data = np.frombuffer(f.read(), np.uint8)
80
  fg = cv2.imdecode(fg_data, cv2.IMREAD_UNCHANGED)
81
  if fg is None:
82
  continue
83
+
84
+ fg = cv2.resize(fg, (TARGET_WIDTH, TARGET_HEIGHT), interpolation=cv2.INTER_AREA)
85
+
86
+ result = overlay_image(bg.copy(), fg, *POS1)
87
+ result = overlay_image(result, fg, *POS2)
88
+
 
 
 
89
  output_path = f"{OUTPUT_DIR}/result_{i:03d}.jpg"
90
  cv2.imwrite(output_path, result)
91
+ results.append((output_path,))
92
+
 
 
 
93
  if i % 10 == 0:
94
  gc.collect()
95
+
96
  except Exception as e:
97
+ print(f"理 {fg_file.name} 失: {str(e)}")
98
  continue
99
 
100
+ progress(1, "完成!")
101
+ zip_file = zip_output_files()
102
+ return results, zip_file, f"成功處理 {len(results)}/{len(fg_files)} 張圖,已打包為 ZIP 可下載"
 
 
 
 
 
 
103
 
104
  except Exception as e:
105
+ raise gr.Error(f"理出錯:{str(e)}")
106
 
107
+ # Gradio
108
  with gr.Blocks() as demo:
109
+ gr.Markdown("## 🖼️ 寬幅圖片合成工具(背景固定為 7872x1200)")
110
+
111
+ fg_upload = gr.Files(label="上傳前景圖(JPG 或 PNG,自動套用背景)", file_types=[".jpg", ".png"])
112
+ btn_run = gr.Button("開始合成", variant="primary")
113
+
 
 
 
 
 
114
  with gr.Row():
115
+ gallery = gr.Gallery(label="合成預覽", columns=3, preview=True)
116
+ zip_download = gr.File(label="下載結果 ZIP 檔")
117
+ log_output = gr.Textbox(label="日誌", interactive=False)
118
+
 
 
 
 
 
 
119
  btn_run.click(
120
  fn=process_images,
121
  inputs=fg_upload,
122
+ outputs=[gallery, zip_download, log_output],
123
  concurrency_limit=4
124
  )
125