JasonHong984/ImageProcessingApp
0
1import streamlit as st2import cv23import numpy as np4import random5import os6import zipfile7import shutil8from moviepy.editor import ImageSequenceClip9from PIL import Image10import io11 12# 定義生成白色矩形的函數13def generate_white_rectangles(14 image, # 直接傳入圖像陣列15 min_width_ratio=0.2,16 min_height_ratio=0.2,17 max_width_ratio=0.5,18 max_height_ratio=0.5,19 num_rectangles_range=(2, 5),20 margin_ratio=0.0521):22 height, width, _ = image.shape23 min_width = int(width * min_width_ratio)24 min_height = int(height * min_height_ratio)25 max_width = int(width * max_width_ratio)26 max_height = int(height * max_height_ratio)27 margin = int(min(width, height) * margin_ratio)28 num_rectangles = random.randint(num_rectangles_range[0], num_rectangles_range[1])29 30 output = image.copy()31 positions = []32 33 random.seed(random.randint(0, 1000000))34 35 for _ in range(num_rectangles):36 for attempt in range(500):37 rect_width = random.randint(min_width, max_width)38 rect_height = random.randint(min_height, max_height)39 x = random.randint(0, width - rect_width)40 y = random.randint(0, height - rect_height)41 new_rect = (x, y, x + rect_width, y + rect_height)42 43 expanded_rect = (x - margin, y - margin, x + rect_width + margin, y + rect_height + margin)44 45 if expanded_rect[0] < 0 or expanded_rect[1] < 0 or expanded_rect[2] > width or expanded_rect[3] > height:46 continue47 48 overlap = False49 for (x1, y1, x2, y2) in positions:50 expanded_existing = (x1 - margin, y1 - margin, x2 + margin, y2 + margin)51 if not (expanded_rect[2] <= expanded_existing[0] or expanded_rect[0] >= expanded_existing[2] or52 expanded_rect[3] <= expanded_existing[1] or expanded_rect[1] >= expanded_existing[3]):53 overlap = True54 break55 56 if not overlap:57 positions.append(new_rect)58 cv2.rectangle(output, (x, y), (x + rect_width, y + rect_height), (255, 255, 255), -1)59 break60 61 return output62 63# 定義生成影片的函數64def create_random_video(image_list, fps=2, frame_duration=0.5, total_duration=15):65 required_frames = int(total_duration / frame_duration)66 67 if len(image_list) < required_frames:68 image_list = random.choices(image_list, k=required_frames)69 else:70 image_list = random.sample(image_list, k=required_frames)71 72 random.shuffle(image_list)73 74 first_image = image_list[0]75 height, width, _ = first_image.shape76 77 processed_images = []78 for img in image_list:79 img_resized = cv2.resize(img, (width, height))80 img_rgb = cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)81 processed_images.append(img_rgb)82 83 clip = ImageSequenceClip(processed_images, durations=[frame_duration] * len(processed_images))84 clip = clip.set_fps(fps)85 86 # 將影片寫入記憶體(BytesIO)87 video_io = io.BytesIO()88 clip.write_videofile("temp.mp4", codec="libx264", audio=False)89 with open("temp.mp4", "rb") as f:90 video_io.write(f.read())91 video_io.seek(0)92 os.remove("temp.mp4") # 刪除臨時檔案93 return video_io94 95# Streamlit 應用主邏輯96def main():97 st.title("圖片處理與影片生成工具")98 st.subheader("上傳多張 JPG 或 PNG 圖片,我們將添加隨機白色矩形、保存處理後圖片並生成 15 秒影片(每張 0.5 秒)")99 100 uploaded_files = st.file_uploader("選擇圖片", type=["jpg", "jpeg", "png"], accept_multiple_files=True)101 102 if uploaded_files:103 # 創建臨時資料夾保存處理後圖片104 output_dir = "processed_images"105 if os.path.exists(output_dir):106 shutil.rmtree(output_dir)107 os.makedirs(output_dir)108 109 image_list = []110 processed_paths = []111 112 for uploaded_file in uploaded_files:113 # 讀取上傳的圖片114 image = Image.open(uploaded_file)115 image_np = np.array(image)116 if image_np.shape[2] == 4: # 處理 PNG 的 RGBA117 image_np = cv2.cvtColor(image_np, cv2.COLOR_RGBA2BGR)118 else:119 image_np = cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR)120 121 # 生成處理後圖片122 processed_image = generate_white_rectangles(image_np)123 124 # 保存處理後圖片125 output_path = os.path.join(output_dir, f"masked_{uploaded_file.name}")126 cv2.imwrite(output_path, processed_image)127 processed_paths.append(output_path)128 129 image_list.append(processed_image)130 131 if image_list:132 st.success(f"已處理並保存 {len(image_list)} 張圖片!")133 134 # 顯示處理後圖片135 st.subheader("處理後的圖片")136 for img_path in processed_paths:137 st.image(img_path, caption=os.path.basename(img_path), use_column_width=True)138 139 # 生成影片140 with st.spinner("生成影片中..."):141 video_io = create_random_video(image_list)142 143 # 顯示影片144 st.video(video_io.read(), format="video/mp4")145 146 # 提供影片下載按鈕147 video_io.seek(0)148 st.download_button("下載影片", video_io, file_name="processed_video.mp4", mime="video/mp4")149 150 # 打包處理後圖片為 ZIP 並提供下載151 zip_io = io.BytesIO()152 with zipfile.ZipFile(zip_io, mode='w', compression=zipfile.ZIP_DEFLATED) as zipf:153 for root, _, files in os.walk(output_dir):154 for file in files:155 zipf.write(os.path.join(root, file), arcname=file)156 zip_io.seek(0)157 st.download_button("下載處理後圖片 ZIP", zip_io, file_name="processed_images.zip", mime="application/zip")158 159 # 清空臨時資料夾160 shutil.rmtree(output_dir)161 162# 運行 Streamlit 應用163if __name__ == "__main__":164 main()165 