Update app.py
Browse files
app.py
CHANGED
|
@@ -267,6 +267,73 @@ def process_video_with_green_screen(video_path, background_url, progress_callbac
|
|
| 267 |
logger.error(f"Video processing failed: {e}")
|
| 268 |
return None
|
| 269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
def main():
|
| 271 |
"""Streamlit main function"""
|
| 272 |
st.set_page_config(
|
|
@@ -316,32 +383,70 @@ def main():
|
|
| 316 |
with col2:
|
| 317 |
st.markdown("### πΌοΈ Background Image")
|
| 318 |
|
| 319 |
-
#
|
| 320 |
-
|
| 321 |
-
"
|
| 322 |
-
"
|
| 323 |
-
"Nature": "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1280&h=720&fit=crop",
|
| 324 |
-
"City": "https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=1280&h=720&fit=crop"
|
| 325 |
-
}
|
| 326 |
-
|
| 327 |
-
selected_background = st.selectbox(
|
| 328 |
-
"Choose background",
|
| 329 |
-
options=list(background_options.keys()),
|
| 330 |
index=0
|
| 331 |
)
|
| 332 |
|
| 333 |
-
background_url =
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 341 |
|
| 342 |
# Process button
|
| 343 |
if uploaded_video and st.button("π¬ Process Video", type="primary"):
|
| 344 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 345 |
with st.spinner("Processing video with green screen workflow..."):
|
| 346 |
# Create progress bar
|
| 347 |
progress_bar = st.progress(0)
|
|
@@ -351,12 +456,19 @@ def update_progress(progress, message):
|
|
| 351 |
progress_bar.progress(progress)
|
| 352 |
status_text.text(message)
|
| 353 |
|
| 354 |
-
# Process video
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 360 |
|
| 361 |
if output_path and os.path.exists(output_path):
|
| 362 |
st.success("β
Video processing completed!")
|
|
|
|
| 267 |
logger.error(f"Video processing failed: {e}")
|
| 268 |
return None
|
| 269 |
|
| 270 |
+
def process_video_with_green_screen_custom(video_path, background_image, progress_callback=None):
|
| 271 |
+
"""Process video with custom background image"""
|
| 272 |
+
try:
|
| 273 |
+
# Open video
|
| 274 |
+
cap = cv2.VideoCapture(video_path)
|
| 275 |
+
|
| 276 |
+
# Get video properties
|
| 277 |
+
fps = int(cap.get(cv2.CAP_PROP_FPS))
|
| 278 |
+
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
| 279 |
+
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
| 280 |
+
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
| 281 |
+
|
| 282 |
+
# Create output video writer
|
| 283 |
+
output_path = tempfile.mktemp(suffix='.mp4')
|
| 284 |
+
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
| 285 |
+
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
|
| 286 |
+
|
| 287 |
+
frame_count = 0
|
| 288 |
+
|
| 289 |
+
while True:
|
| 290 |
+
ret, frame = cap.read()
|
| 291 |
+
if not ret:
|
| 292 |
+
break
|
| 293 |
+
|
| 294 |
+
# Convert BGR to RGB
|
| 295 |
+
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 296 |
+
|
| 297 |
+
# Step 1: Segment person
|
| 298 |
+
if SAM2_AVAILABLE:
|
| 299 |
+
person_mask = segment_person_sam2(frame_rgb)
|
| 300 |
+
method_used = "SAM2"
|
| 301 |
+
else:
|
| 302 |
+
person_mask = segment_person_fallback(frame_rgb)
|
| 303 |
+
method_used = "Fallback"
|
| 304 |
+
|
| 305 |
+
if person_mask is not None:
|
| 306 |
+
# Step 2: Insert green screen
|
| 307 |
+
green_screen_frame = insert_green_screen(frame_rgb, person_mask)
|
| 308 |
+
|
| 309 |
+
# Step 3: Chroma key replacement with custom background
|
| 310 |
+
final_frame = chroma_key_replacement(green_screen_frame, background_image)
|
| 311 |
+
else:
|
| 312 |
+
# If segmentation fails, use original frame
|
| 313 |
+
final_frame = frame_rgb
|
| 314 |
+
method_used = "No segmentation"
|
| 315 |
+
|
| 316 |
+
# Convert back to BGR for video writer
|
| 317 |
+
final_frame_bgr = cv2.cvtColor(final_frame, cv2.COLOR_RGB2BGR)
|
| 318 |
+
out.write(final_frame_bgr)
|
| 319 |
+
|
| 320 |
+
frame_count += 1
|
| 321 |
+
|
| 322 |
+
# Update progress
|
| 323 |
+
if progress_callback:
|
| 324 |
+
progress = frame_count / total_frames
|
| 325 |
+
progress_callback(progress, f"Processing frame {frame_count}/{total_frames} ({method_used})")
|
| 326 |
+
|
| 327 |
+
# Release resources
|
| 328 |
+
cap.release()
|
| 329 |
+
out.release()
|
| 330 |
+
|
| 331 |
+
return output_path
|
| 332 |
+
|
| 333 |
+
except Exception as e:
|
| 334 |
+
logger.error(f"Video processing with custom background failed: {e}")
|
| 335 |
+
return None
|
| 336 |
+
|
| 337 |
def main():
|
| 338 |
"""Streamlit main function"""
|
| 339 |
st.set_page_config(
|
|
|
|
| 383 |
with col2:
|
| 384 |
st.markdown("### πΌοΈ Background Image")
|
| 385 |
|
| 386 |
+
# Background selection method
|
| 387 |
+
background_method = st.radio(
|
| 388 |
+
"Choose background method:",
|
| 389 |
+
["π Preset Backgrounds", "π Upload Custom Image"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 390 |
index=0
|
| 391 |
)
|
| 392 |
|
| 393 |
+
background_url = None
|
| 394 |
+
custom_background = None
|
| 395 |
+
|
| 396 |
+
if background_method == "π Preset Backgrounds":
|
| 397 |
+
# Default background options
|
| 398 |
+
background_options = {
|
| 399 |
+
"Brick Wall": "https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1280&h=720&fit=crop",
|
| 400 |
+
"Office": "https://images.unsplash.com/photo-1497366216548-37526070297c?w=1280&h=720&fit=crop",
|
| 401 |
+
"Nature": "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1280&h=720&fit=crop",
|
| 402 |
+
"City": "https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=1280&h=720&fit=crop"
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
selected_background = st.selectbox(
|
| 406 |
+
"Choose background",
|
| 407 |
+
options=list(background_options.keys()),
|
| 408 |
+
index=0
|
| 409 |
+
)
|
| 410 |
+
|
| 411 |
+
background_url = background_options[selected_background]
|
| 412 |
+
|
| 413 |
+
# Show background preview
|
| 414 |
+
try:
|
| 415 |
+
background_image = load_background_image(background_url)
|
| 416 |
+
st.image(background_image, caption=f"Background: {selected_background}", use_column_width=True)
|
| 417 |
+
except:
|
| 418 |
+
st.error("Failed to load background image")
|
| 419 |
+
|
| 420 |
+
else: # Upload Custom Image
|
| 421 |
+
uploaded_background = st.file_uploader(
|
| 422 |
+
"Upload your background image",
|
| 423 |
+
type=['jpg', 'jpeg', 'png', 'bmp'],
|
| 424 |
+
help="Upload a custom background image (JPG, PNG, BMP)"
|
| 425 |
+
)
|
| 426 |
+
|
| 427 |
+
if uploaded_background:
|
| 428 |
+
# Load and display custom background
|
| 429 |
+
try:
|
| 430 |
+
custom_background = np.array(Image.open(uploaded_background).convert('RGB'))
|
| 431 |
+
st.image(custom_background, caption="Custom Background", use_column_width=True)
|
| 432 |
+
st.success(f"β
Custom background uploaded: {uploaded_background.name}")
|
| 433 |
+
except Exception as e:
|
| 434 |
+
st.error(f"Failed to load custom background: {e}")
|
| 435 |
+
custom_background = None
|
| 436 |
+
else:
|
| 437 |
+
st.info("Please upload a background image")
|
| 438 |
|
| 439 |
# Process button
|
| 440 |
if uploaded_video and st.button("π¬ Process Video", type="primary"):
|
| 441 |
|
| 442 |
+
# Check if background is selected
|
| 443 |
+
if background_method == "π Preset Backgrounds" and not background_url:
|
| 444 |
+
st.error("Please select a preset background")
|
| 445 |
+
return
|
| 446 |
+
elif background_method == "π Upload Custom Image" and custom_background is None:
|
| 447 |
+
st.error("Please upload a custom background image")
|
| 448 |
+
return
|
| 449 |
+
|
| 450 |
with st.spinner("Processing video with green screen workflow..."):
|
| 451 |
# Create progress bar
|
| 452 |
progress_bar = st.progress(0)
|
|
|
|
| 456 |
progress_bar.progress(progress)
|
| 457 |
status_text.text(message)
|
| 458 |
|
| 459 |
+
# Process video with appropriate background
|
| 460 |
+
if background_method == "π Preset Backgrounds":
|
| 461 |
+
output_path = process_video_with_green_screen(
|
| 462 |
+
video_path,
|
| 463 |
+
background_url,
|
| 464 |
+
progress_callback=update_progress
|
| 465 |
+
)
|
| 466 |
+
else: # Custom background
|
| 467 |
+
output_path = process_video_with_green_screen_custom(
|
| 468 |
+
video_path,
|
| 469 |
+
custom_background,
|
| 470 |
+
progress_callback=update_progress
|
| 471 |
+
)
|
| 472 |
|
| 473 |
if output_path and os.path.exists(output_path):
|
| 474 |
st.success("β
Video processing completed!")
|