Spaces:
Running
Running
Upload 14 files
Browse files- __pycache__/app_gradio.cpython-313.pyc +0 -0
- app_gradio.py +289 -20
__pycache__/app_gradio.cpython-313.pyc
CHANGED
Binary files a/__pycache__/app_gradio.cpython-313.pyc and b/__pycache__/app_gradio.cpython-313.pyc differ
|
|
app_gradio.py
CHANGED
@@ -521,14 +521,107 @@ def create_layered_furniture_mask(image):
|
|
521 |
|
522 |
# Keep the old function for compatibility
|
523 |
def create_precise_furniture_mask(image):
|
524 |
-
"""
|
525 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
526 |
|
527 |
def get_prompt_preview(room_type, design_style, inpainting_mode):
|
528 |
"""Generate preview of prompt and negative prompt that will be used"""
|
529 |
|
530 |
# Create positive prompt based on mode
|
531 |
-
if inpainting_mode == "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
532 |
# Simple, direct furniture prompt for smart mode
|
533 |
if room_type == "Living Room":
|
534 |
furniture_items = "sofa, coffee table, side tables, floor lamp, dining table with chairs"
|
@@ -545,18 +638,185 @@ def get_prompt_preview(room_type, design_style, inpainting_mode):
|
|
545 |
else:
|
546 |
furniture_items = "appropriate furniture"
|
547 |
|
548 |
-
positive_prompt = f"
|
549 |
else:
|
550 |
# Get detailed template-based prompt for full mode
|
551 |
detailed_prompt = DETAILED_PROMPTS.get((room_type, design_style),
|
552 |
DETAILED_PROMPTS[("Living Room", "Modern")])
|
553 |
positive_prompt = f"photorealistic interior design, {detailed_prompt}, keep existing windows unchanged, preserve original window placement, professionally photographed, architectural photography, natural lighting, ultra-realistic, high resolution, sharp focus, interior design magazine quality, realistic textures, realistic materials"
|
554 |
|
555 |
-
#
|
556 |
-
|
|
|
|
|
|
|
|
|
|
|
557 |
|
558 |
return positive_prompt, negative_prompt
|
559 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
560 |
def post_process_blend(original, generated):
|
561 |
"""Post-process to reduce seam artifacts between original and generated areas"""
|
562 |
from PIL import ImageFilter
|
@@ -642,7 +902,15 @@ def design_space(input_image, room_type, design_style, inpainting_mode, num_step
|
|
642 |
mlsd_image = resized_image.copy()
|
643 |
|
644 |
# Create mask based on selected mode
|
645 |
-
if inpainting_mode == "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
646 |
# Use precise smart mask for furniture-only placement
|
647 |
mask_image = create_precise_furniture_mask(resized_image)
|
648 |
|
@@ -662,7 +930,7 @@ def design_space(input_image, room_type, design_style, inpainting_mode, num_step
|
|
662 |
else:
|
663 |
furniture_items = "appropriate furniture"
|
664 |
|
665 |
-
prompt = f"add {furniture_items}
|
666 |
print(f"Smart mode prompt: {prompt}")
|
667 |
else:
|
668 |
mask_image = create_full_mask(resized_image)
|
@@ -671,8 +939,8 @@ def design_space(input_image, room_type, design_style, inpainting_mode, num_step
|
|
671 |
|
672 |
# Generate image with optimized strength for furniture generation
|
673 |
if inpainting_mode == "smart":
|
674 |
-
#
|
675 |
-
actual_strength = min(0.
|
676 |
else:
|
677 |
actual_strength = float(strength)
|
678 |
|
@@ -685,16 +953,16 @@ def design_space(input_image, room_type, design_style, inpainting_mode, num_step
|
|
685 |
|
686 |
result = pipe(
|
687 |
prompt=prompt,
|
688 |
-
negative_prompt="
|
689 |
num_inference_steps=int(num_steps),
|
690 |
strength=actual_strength,
|
691 |
guidance_scale=float(guidance_scale),
|
692 |
image=resized_image,
|
693 |
mask_image=mask_image,
|
694 |
control_image=[seg_control, mlsd_image],
|
695 |
-
controlnet_conditioning_scale=[0.4, 0.2],
|
696 |
-
control_guidance_start=[0, 0.1],
|
697 |
-
control_guidance_end=[0.5, 0.25],
|
698 |
).images[0]
|
699 |
|
700 |
# Restore original size
|
@@ -745,9 +1013,10 @@ def create_interface():
|
|
745 |
inpainting_mode = gr.Radio(
|
746 |
choices=[
|
747 |
("Complete Room Redesign", "full"),
|
748 |
-
("Add Furniture Only (Preserve Walls)", "smart")
|
|
|
749 |
],
|
750 |
-
value="
|
751 |
label="π¨ Design Mode",
|
752 |
info="Choose how to modify your image"
|
753 |
)
|
@@ -758,12 +1027,12 @@ def create_interface():
|
|
758 |
label="Number of denoising steps"
|
759 |
)
|
760 |
guidance_scale = gr.Slider(
|
761 |
-
minimum=1, maximum=50, value=
|
762 |
-
label="Scale for classifier-free guidance"
|
763 |
)
|
764 |
strength = gr.Slider(
|
765 |
-
minimum=0, maximum=1, value=0.
|
766 |
-
label="Prompt strength for inpainting"
|
767 |
)
|
768 |
|
769 |
generate_btn = gr.Button("π¨ Generate Design", variant="primary", size="lg")
|
|
|
521 |
|
522 |
# Keep the old function for compatibility
|
523 |
def create_precise_furniture_mask(image):
|
524 |
+
"""Create ultra-conservative mask that ONLY targets floor center - preserves ALL walls and windows"""
|
525 |
+
import cv2
|
526 |
+
|
527 |
+
print("π― Creating ULTRA-CONSERVATIVE furniture mask...")
|
528 |
+
|
529 |
+
img_array = np.array(image)
|
530 |
+
h, w = img_array.shape[:2]
|
531 |
+
gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
|
532 |
+
|
533 |
+
# Create conservative mask - ONLY center floor area
|
534 |
+
mask = np.zeros((h, w), dtype=np.uint8)
|
535 |
+
|
536 |
+
# ULTRA CONSERVATIVE: Only center 30% of image, bottom 40% (floor only)
|
537 |
+
safe_x_start = int(w * 0.35) # 35% from left
|
538 |
+
safe_x_end = int(w * 0.65) # 35% from right
|
539 |
+
safe_y_start = int(h * 0.6) # 60% from top (avoid walls/windows)
|
540 |
+
safe_y_end = int(h * 0.85) # 15% from bottom
|
541 |
+
|
542 |
+
# Create small circular mask in safe center floor area
|
543 |
+
center_x, center_y = w // 2, int(h * 0.72) # Lower center for floor
|
544 |
+
|
545 |
+
# SMALL ellipse parameters - very conservative
|
546 |
+
ellipse_w = int(w * 0.18) # Only 18% of width (very small area)
|
547 |
+
ellipse_h = int(h * 0.15) # Only 15% of height (very small area)
|
548 |
+
|
549 |
+
# Draw small ellipse mask
|
550 |
+
Y, X = np.ogrid[:h, :w]
|
551 |
+
ellipse_mask = ((X - center_x) / ellipse_w) ** 2 + ((Y - center_y) / ellipse_h) ** 2 <= 1
|
552 |
+
|
553 |
+
# Apply soft gradient within ellipse - strong at center, fade at edges
|
554 |
+
for y in range(h):
|
555 |
+
for x in range(w):
|
556 |
+
if ellipse_mask[y, x]:
|
557 |
+
# Distance from center
|
558 |
+
dist = np.sqrt(((x - center_x) / ellipse_w) ** 2 + ((y - center_y) / ellipse_h) ** 2)
|
559 |
+
# Very conservative gradient
|
560 |
+
strength = max(0, (1 - dist) ** 2) * 200 # Softer, max 200 not 255
|
561 |
+
mask[y, x] = int(strength)
|
562 |
+
|
563 |
+
# HARD EXCLUSIONS - absolutely no modification near walls/windows
|
564 |
+
|
565 |
+
# Exclude all bright areas (windows) completely
|
566 |
+
windows = gray > 180 # Lower threshold to catch more window areas
|
567 |
+
mask[windows] = 0
|
568 |
+
|
569 |
+
# Exclude all dark areas (corners/shadows)
|
570 |
+
dark_areas = gray < 60
|
571 |
+
mask[dark_areas] = 0
|
572 |
+
|
573 |
+
# Exclude outer 25% of image (wall areas)
|
574 |
+
wall_margin = 0.25
|
575 |
+
mask[:int(h*wall_margin), :] = 0 # Top 25%
|
576 |
+
mask[-int(h*wall_margin):, :] = 0 # Bottom 25%
|
577 |
+
mask[:, :int(w*wall_margin)] = 0 # Left 25%
|
578 |
+
mask[:, -int(w*wall_margin):] = 0 # Right 25%
|
579 |
+
|
580 |
+
# Exclude top 50% completely (ceiling/wall area)
|
581 |
+
mask[:int(h*0.5), :] = 0
|
582 |
+
|
583 |
+
# Apply strong blur for very smooth transitions
|
584 |
+
mask = cv2.GaussianBlur(mask, (31, 31), 0)
|
585 |
+
|
586 |
+
# Final safety check - make sure mask is very conservative
|
587 |
+
mask = np.clip(mask, 0, 150) # Lower maximum intensity
|
588 |
+
|
589 |
+
# Statistics
|
590 |
+
furniture_pixels = np.count_nonzero(mask)
|
591 |
+
coverage = (furniture_pixels / (h * w)) * 100
|
592 |
+
|
593 |
+
print(f"π‘οΈ ULTRA-CONSERVATIVE mask stats:")
|
594 |
+
print(f" - Total coverage: {furniture_pixels} pixels ({coverage:.1f}%)")
|
595 |
+
print(f" - Max intensity: {mask.max()}")
|
596 |
+
print(f" - Center: ({center_x}, {center_y}), Size: {ellipse_w}x{ellipse_h}")
|
597 |
+
print(f" - Coverage should be < 15% for wall preservation")
|
598 |
+
|
599 |
+
return Image.fromarray(mask).convert("RGB")
|
600 |
|
601 |
def get_prompt_preview(room_type, design_style, inpainting_mode):
|
602 |
"""Generate preview of prompt and negative prompt that will be used"""
|
603 |
|
604 |
# Create positive prompt based on mode
|
605 |
+
if inpainting_mode == "layered":
|
606 |
+
# Layered furniture generation
|
607 |
+
if room_type == "Living Room":
|
608 |
+
furniture_items = "modern sofa, coffee table, side table, floor lamp"
|
609 |
+
elif room_type == "Bedroom" or room_type == "Master Bedroom":
|
610 |
+
furniture_items = "bed with headboard, two nightstands, dresser"
|
611 |
+
elif room_type == "Kitchen":
|
612 |
+
furniture_items = "kitchen island, bar stools"
|
613 |
+
elif room_type == "Dining Room":
|
614 |
+
furniture_items = "dining table, dining chairs"
|
615 |
+
elif room_type == "Home Office":
|
616 |
+
furniture_items = "desk, office chair, bookshelf"
|
617 |
+
elif room_type == "Bathroom":
|
618 |
+
furniture_items = "vanity, mirror, storage cabinet"
|
619 |
+
else:
|
620 |
+
furniture_items = "appropriate furniture"
|
621 |
+
|
622 |
+
positive_prompt = f"LAYERED APPROACH: same room layout, preserve perspective, layout preserving realistic interior design - Generate realistic {furniture_items}, {design_style.lower()} style, photorealistic furniture placement, maintain room proportions, professional furniture photography, clean lighting, realistic materials and shadows"
|
623 |
+
|
624 |
+
elif inpainting_mode == "smart":
|
625 |
# Simple, direct furniture prompt for smart mode
|
626 |
if room_type == "Living Room":
|
627 |
furniture_items = "sofa, coffee table, side tables, floor lamp, dining table with chairs"
|
|
|
638 |
else:
|
639 |
furniture_items = "appropriate furniture"
|
640 |
|
641 |
+
positive_prompt = f"FURNITURE ONLY: add {furniture_items} on floor center, {design_style.lower()} style, photorealistic furniture objects, PRESERVE: keep all walls unchanged, keep ceiling unchanged, keep floor color unchanged, keep window unchanged, no structural changes, no wall modifications, only place furniture objects in room center, professional furniture placement, realistic shadows"
|
642 |
else:
|
643 |
# Get detailed template-based prompt for full mode
|
644 |
detailed_prompt = DETAILED_PROMPTS.get((room_type, design_style),
|
645 |
DETAILED_PROMPTS[("Living Room", "Modern")])
|
646 |
positive_prompt = f"photorealistic interior design, {detailed_prompt}, keep existing windows unchanged, preserve original window placement, professionally photographed, architectural photography, natural lighting, ultra-realistic, high resolution, sharp focus, interior design magazine quality, realistic textures, realistic materials"
|
647 |
|
648 |
+
# Updated negative prompt
|
649 |
+
if inpainting_mode == "layered":
|
650 |
+
negative_prompt = "distortion, warped structure, perspective distortion, room layout changes, architectural changes, structural modifications, empty room, no furniture, floating furniture, unrealistic placement, bad proportions, distorted furniture, warped perspective, gray background, neutral background, plain background, lowres, watermark, blurry, deformed"
|
651 |
+
elif inpainting_mode == "smart":
|
652 |
+
negative_prompt = "FORBIDDEN CHANGES: changing walls, different wall color, wall texture changes, new wall paint, different walls, wall modifications, changing windows, different window, new windows, window alterations, changing ceiling, different ceiling, ceiling changes, changing floor, different floor material, floor changes, structural modifications, architectural changes, room alterations, wall decorations, wall art, curtains, blinds, wall shelves, wall mounted items, lowres, watermark, blurry, deformed, floating furniture, unrealistic placement"
|
653 |
+
else:
|
654 |
+
negative_prompt = "STRUCTURAL REPLACEMENT FORBIDDEN: changing wall color, different wall texture, new walls, removing walls, changing ceiling, different ceiling, new windows, different windows, removing windows, changing floor material, different floor, PRESERVE STRUCTURE: keep original room architecture, floating furniture, unrealistic placement, furniture in ceiling, lowres, watermark, banner, logo, contactinfo, text, deformed, blurry, blur, out of focus, surreal, ugly"
|
655 |
|
656 |
return positive_prompt, negative_prompt
|
657 |
|
658 |
+
def generate_furniture_layer(original_image, room_type, design_style, num_steps, guidance_scale, strength):
|
659 |
+
"""Generate furniture objects using neutral background, then extract for layering"""
|
660 |
+
global pipe, seg_processor, seg_model, mlsd_processor
|
661 |
+
|
662 |
+
print("πͺ Generating furniture layer...")
|
663 |
+
|
664 |
+
# Create neutral gray background same size as original for furniture generation
|
665 |
+
w, h = original_image.size
|
666 |
+
neutral_bg = Image.new('RGB', (w, h), (128, 128, 128)) # Neutral gray
|
667 |
+
|
668 |
+
# Create furniture mask (center area only)
|
669 |
+
furniture_mask = create_precise_furniture_mask(neutral_bg)
|
670 |
+
|
671 |
+
# Create furniture prompt
|
672 |
+
if room_type == "Living Room":
|
673 |
+
furniture_items = "modern sofa, coffee table, side table, floor lamp"
|
674 |
+
elif room_type == "Bedroom":
|
675 |
+
furniture_items = "bed with headboard, two nightstands, dresser"
|
676 |
+
elif room_type == "Kitchen":
|
677 |
+
furniture_items = "kitchen island, bar stools"
|
678 |
+
elif room_type == "Dining Room":
|
679 |
+
furniture_items = "dining table, dining chairs"
|
680 |
+
elif room_type == "Home Office":
|
681 |
+
furniture_items = "desk, office chair, bookshelf"
|
682 |
+
else:
|
683 |
+
furniture_items = "appropriate furniture"
|
684 |
+
|
685 |
+
furniture_prompt = f"same room layout, preserve perspective, layout preserving realistic interior design: {furniture_items}, {design_style.lower()} style, photorealistic furniture placement, natural floor positioning, professional furniture photography, clean professional lighting, realistic materials and textures, high quality furniture catalog, maintain room proportions, realistic shadows and reflections"
|
686 |
+
|
687 |
+
# Generate furniture on neutral background
|
688 |
+
try:
|
689 |
+
if pipe is None:
|
690 |
+
print("β Pipeline not loaded")
|
691 |
+
return Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
692 |
+
|
693 |
+
# Resize for processing
|
694 |
+
max_size = 768
|
695 |
+
if max(w, h) > max_size:
|
696 |
+
if w > h:
|
697 |
+
new_w, new_h = max_size, int(max_size * h / w)
|
698 |
+
else:
|
699 |
+
new_w, new_h = int(max_size * w / h), max_size
|
700 |
+
else:
|
701 |
+
new_w, new_h = w, h
|
702 |
+
|
703 |
+
resized_neutral = neutral_bg.resize((new_w, new_h))
|
704 |
+
resized_mask = furniture_mask.resize((new_w, new_h))
|
705 |
+
|
706 |
+
# Generate furniture with inpainting
|
707 |
+
seg_control = resized_neutral.copy()
|
708 |
+
mlsd_image = resized_neutral.copy()
|
709 |
+
|
710 |
+
# Optimized parameters based on user feedback
|
711 |
+
optimized_guidance = max(7.0, min(10.0, float(guidance_scale))) # Clamp 7-10
|
712 |
+
optimized_strength = max(0.4, min(0.6, float(strength))) # Clamp 0.4-0.6
|
713 |
+
|
714 |
+
result = pipe(
|
715 |
+
prompt=furniture_prompt,
|
716 |
+
negative_prompt="distortion, warped structure, perspective distortion, room layout changes, architectural changes, structural modifications, empty room, no furniture, floating furniture, unrealistic placement, bad proportions, distorted furniture, warped perspective",
|
717 |
+
num_inference_steps=int(num_steps),
|
718 |
+
strength=optimized_strength, # Optimized strength range
|
719 |
+
guidance_scale=optimized_guidance, # Optimized guidance range
|
720 |
+
image=resized_neutral,
|
721 |
+
mask_image=resized_mask,
|
722 |
+
control_image=[seg_control, mlsd_image],
|
723 |
+
controlnet_conditioning_scale=[0.5, 0.3], # Stronger control for layout preservation
|
724 |
+
control_guidance_start=[0, 0],
|
725 |
+
control_guidance_end=[0.7, 0.5], # Extended guidance for better control
|
726 |
+
).images[0]
|
727 |
+
|
728 |
+
# Restore original size
|
729 |
+
furniture_generated = result.resize((w, h), Image.Resampling.LANCZOS)
|
730 |
+
|
731 |
+
print("β
Furniture generated on neutral background")
|
732 |
+
return furniture_generated
|
733 |
+
|
734 |
+
except Exception as e:
|
735 |
+
print(f"β Furniture layer generation failed: {e}")
|
736 |
+
return Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
737 |
+
|
738 |
+
def extract_furniture_from_generated(furniture_generated, original_neutral_bg):
|
739 |
+
"""Extract furniture from generated image by removing neutral background"""
|
740 |
+
import cv2
|
741 |
+
|
742 |
+
print("βοΈ Extracting furniture from generated image...")
|
743 |
+
|
744 |
+
# Convert to numpy arrays
|
745 |
+
furniture_array = np.array(furniture_generated)
|
746 |
+
neutral_array = np.array(original_neutral_bg)
|
747 |
+
|
748 |
+
h, w = furniture_array.shape[:2]
|
749 |
+
|
750 |
+
# Create mask for furniture areas (areas that changed from neutral gray)
|
751 |
+
# Neutral gray is (128, 128, 128)
|
752 |
+
gray_tolerance = 30
|
753 |
+
|
754 |
+
# Calculate difference from neutral gray
|
755 |
+
diff = np.abs(furniture_array.astype(np.float32) - 128.0)
|
756 |
+
diff_magnitude = np.sqrt(np.sum(diff**2, axis=2))
|
757 |
+
|
758 |
+
# Create furniture mask - areas significantly different from gray
|
759 |
+
furniture_mask = diff_magnitude > gray_tolerance
|
760 |
+
|
761 |
+
# Refine mask - remove small noise
|
762 |
+
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
|
763 |
+
furniture_mask = cv2.morphologyEx(furniture_mask.astype(np.uint8), cv2.MORPH_OPEN, kernel)
|
764 |
+
furniture_mask = cv2.morphologyEx(furniture_mask, cv2.MORPH_CLOSE, kernel)
|
765 |
+
|
766 |
+
# Create RGBA image with transparency
|
767 |
+
furniture_rgba = np.zeros((h, w, 4), dtype=np.uint8)
|
768 |
+
furniture_rgba[:, :, :3] = furniture_array # Copy RGB
|
769 |
+
furniture_rgba[:, :, 3] = furniture_mask * 255 # Alpha channel
|
770 |
+
|
771 |
+
# Apply gaussian blur to alpha for smoother edges
|
772 |
+
furniture_rgba[:, :, 3] = cv2.GaussianBlur(furniture_rgba[:, :, 3], (3, 3), 0)
|
773 |
+
|
774 |
+
furniture_layer = Image.fromarray(furniture_rgba, 'RGBA')
|
775 |
+
|
776 |
+
print(f"β
Extracted furniture layer with {np.count_nonzero(furniture_mask)} furniture pixels")
|
777 |
+
|
778 |
+
return furniture_layer
|
779 |
+
|
780 |
+
def composite_layers(background, furniture_generated, furniture_mask=None):
|
781 |
+
"""Composite furniture layer onto background with realistic placement"""
|
782 |
+
print("π¨ Compositing layers...")
|
783 |
+
|
784 |
+
# Step 1: Extract furniture from generated image
|
785 |
+
neutral_bg = Image.new('RGB', background.size, (128, 128, 128))
|
786 |
+
furniture_layer = extract_furniture_from_generated(furniture_generated, neutral_bg)
|
787 |
+
|
788 |
+
# Step 2: Composite furniture onto original background
|
789 |
+
if background.mode != 'RGBA':
|
790 |
+
background = background.convert('RGBA')
|
791 |
+
|
792 |
+
# Alpha composite
|
793 |
+
result = Image.alpha_composite(background, furniture_layer)
|
794 |
+
|
795 |
+
# Convert back to RGB
|
796 |
+
final = Image.new('RGB', result.size, (255, 255, 255))
|
797 |
+
final.paste(result, mask=result.split()[-1])
|
798 |
+
|
799 |
+
return final
|
800 |
+
|
801 |
+
def create_layered_design(input_image, room_type, design_style, num_steps, guidance_scale, strength):
|
802 |
+
"""LAYERED APPROACH: Generate furniture separately and composite onto preserved background"""
|
803 |
+
print("ποΈ Starting layered design generation...")
|
804 |
+
print(f"π Optimized parameters - Guidance: {guidance_scale} β {max(7.0, min(10.0, float(guidance_scale)))}, Strength: {strength} β {max(0.4, min(0.6, float(strength)))}")
|
805 |
+
|
806 |
+
# Step 1: Preserve original background completely
|
807 |
+
background_layer = input_image.copy()
|
808 |
+
print("β
Background layer preserved")
|
809 |
+
|
810 |
+
# Step 2: Generate furniture objects separately
|
811 |
+
furniture_layer = generate_furniture_layer(input_image, room_type, design_style, num_steps, guidance_scale, strength)
|
812 |
+
print("β
Furniture layer generated")
|
813 |
+
|
814 |
+
# Step 3: Composite layers
|
815 |
+
final_image = composite_layers(background_layer, furniture_layer)
|
816 |
+
print("β
Layers composited")
|
817 |
+
|
818 |
+
return final_image
|
819 |
+
|
820 |
def post_process_blend(original, generated):
|
821 |
"""Post-process to reduce seam artifacts between original and generated areas"""
|
822 |
from PIL import ImageFilter
|
|
|
902 |
mlsd_image = resized_image.copy()
|
903 |
|
904 |
# Create mask based on selected mode
|
905 |
+
if inpainting_mode == "layered":
|
906 |
+
# Use new layered approach
|
907 |
+
final_image = create_layered_design(resized_image, room_type, design_style, num_steps, guidance_scale, strength)
|
908 |
+
# Restore original size
|
909 |
+
final_image = final_image.resize((orig_w, orig_h), Image.Resampling.LANCZOS)
|
910 |
+
success_msg = f"β
Layered {room_type} in {design_style} style completed!"
|
911 |
+
return final_image, success_msg
|
912 |
+
|
913 |
+
elif inpainting_mode == "smart":
|
914 |
# Use precise smart mask for furniture-only placement
|
915 |
mask_image = create_precise_furniture_mask(resized_image)
|
916 |
|
|
|
930 |
else:
|
931 |
furniture_items = "appropriate furniture"
|
932 |
|
933 |
+
prompt = f"FURNITURE ONLY: add {furniture_items} on floor center, {design_style.lower()} style, photorealistic furniture objects, PRESERVE: keep all walls unchanged, keep ceiling unchanged, keep floor color unchanged, keep window unchanged, no structural changes, no wall modifications, only place furniture objects in room center, professional furniture placement, realistic shadows"
|
934 |
print(f"Smart mode prompt: {prompt}")
|
935 |
else:
|
936 |
mask_image = create_full_mask(resized_image)
|
|
|
939 |
|
940 |
# Generate image with optimized strength for furniture generation
|
941 |
if inpainting_mode == "smart":
|
942 |
+
# Lower strength for better structure preservation in smart mode
|
943 |
+
actual_strength = min(0.65, float(strength) * 0.8) # Reduce by 20%, cap at 0.65
|
944 |
else:
|
945 |
actual_strength = float(strength)
|
946 |
|
|
|
953 |
|
954 |
result = pipe(
|
955 |
prompt=prompt,
|
956 |
+
negative_prompt="FORBIDDEN CHANGES: changing walls, different wall color, wall texture changes, new wall paint, different walls, wall modifications, changing windows, different window, new windows, window alterations, changing ceiling, different ceiling, ceiling changes, changing floor, different floor material, floor changes, structural modifications, architectural changes, room alterations, wall decorations, wall art, curtains, blinds, wall shelves, wall mounted items, lowres, watermark, blurry, deformed, floating furniture, unrealistic placement",
|
957 |
num_inference_steps=int(num_steps),
|
958 |
strength=actual_strength,
|
959 |
guidance_scale=float(guidance_scale),
|
960 |
image=resized_image,
|
961 |
mask_image=mask_image,
|
962 |
control_image=[seg_control, mlsd_image],
|
963 |
+
controlnet_conditioning_scale=[0.8, 0.6] if inpainting_mode == "smart" else [0.4, 0.2],
|
964 |
+
control_guidance_start=[0, 0] if inpainting_mode == "smart" else [0, 0.1],
|
965 |
+
control_guidance_end=[0.9, 0.8] if inpainting_mode == "smart" else [0.5, 0.25],
|
966 |
).images[0]
|
967 |
|
968 |
# Restore original size
|
|
|
1013 |
inpainting_mode = gr.Radio(
|
1014 |
choices=[
|
1015 |
("Complete Room Redesign", "full"),
|
1016 |
+
("Add Furniture Only (Preserve Walls)", "smart"),
|
1017 |
+
("π Layered Furniture (Background + Furniture Overlay)", "layered")
|
1018 |
],
|
1019 |
+
value="layered",
|
1020 |
label="π¨ Design Mode",
|
1021 |
info="Choose how to modify your image"
|
1022 |
)
|
|
|
1027 |
label="Number of denoising steps"
|
1028 |
)
|
1029 |
guidance_scale = gr.Slider(
|
1030 |
+
minimum=1, maximum=50, value=8, step=0.5,
|
1031 |
+
label="Scale for classifier-free guidance (7-10 optimal for Layered mode)"
|
1032 |
)
|
1033 |
strength = gr.Slider(
|
1034 |
+
minimum=0, maximum=1, value=0.5, step=0.05,
|
1035 |
+
label="Prompt strength for inpainting (0.4-0.6 optimal for Layered mode)"
|
1036 |
)
|
1037 |
|
1038 |
generate_btn = gr.Button("π¨ Generate Design", variant="primary", size="lg")
|