Spaces:
Running
on
Zero
Running
on
Zero
π§ Add clothing inpainting step (Step 3) with independent prompt and guidance
Browse files- __pycache__/background_edit.cpython-310.pyc +0 -0
- __pycache__/inference.cpython-310.pyc +0 -0
- __pycache__/utils.cpython-310.pyc +0 -0
- app.py +54 -0
- background_edit.py +45 -2
__pycache__/background_edit.cpython-310.pyc
CHANGED
Binary files a/__pycache__/background_edit.cpython-310.pyc and b/__pycache__/background_edit.cpython-310.pyc differ
|
|
__pycache__/inference.cpython-310.pyc
CHANGED
Binary files a/__pycache__/inference.cpython-310.pyc and b/__pycache__/inference.cpython-310.pyc differ
|
|
__pycache__/utils.cpython-310.pyc
CHANGED
Binary files a/__pycache__/utils.cpython-310.pyc and b/__pycache__/utils.cpython-310.pyc differ
|
|
app.py
CHANGED
@@ -7,6 +7,22 @@ import gradio as gr
|
|
7 |
|
8 |
from inference import generate_with_lora
|
9 |
from background_edit import run_background_removal_and_inpaint
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
# βββββββββββββββββββββ Helpers βββββββββββββββββββββ
|
12 |
def _print_trace():
|
@@ -59,6 +75,15 @@ def safe_generate_and_inpaint(
|
|
59 |
_print_trace()
|
60 |
return None, None, f"β Unexpected Error: {type(e).__name__}: {str(e)}"
|
61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
# βββββββββββββββββββββ Gradio UI βββββββββββββββββββββ
|
63 |
with gr.Blocks() as demo:
|
64 |
gr.Markdown("## π§ Headshot + Background Generator (Full Prompt Control)")
|
@@ -102,4 +127,33 @@ with gr.Blocks() as demo:
|
|
102 |
outputs=[output_refined, output_final, error_box]
|
103 |
)
|
104 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
demo.launch(debug=True)
|
|
|
7 |
|
8 |
from inference import generate_with_lora
|
9 |
from background_edit import run_background_removal_and_inpaint
|
10 |
+
from background_edit import run_clothing_inpaint
|
11 |
+
|
12 |
+
import os
|
13 |
+
|
14 |
+
MODEL_URL = "https://huggingface.co/Bingsu/adetailer/resolve/main/deepfashion2_yolov8s-seg.pt"
|
15 |
+
MODEL_PATH = "deepfashion2_yolov8s-seg.pt"
|
16 |
+
|
17 |
+
# βββ Download DeepFashion2 model if not already present βββ
|
18 |
+
if not os.path.exists(MODEL_PATH):
|
19 |
+
import urllib.request
|
20 |
+
print("[INFO] Downloading DeepFashion2 YOLOv8 model...")
|
21 |
+
urllib.request.urlretrieve(MODEL_URL, MODEL_PATH)
|
22 |
+
print("[INFO] Model downloaded.")
|
23 |
+
else:
|
24 |
+
print("[INFO] DeepFashion2 model already exists.")
|
25 |
+
|
26 |
|
27 |
# βββββββββββββββββββββ Helpers βββββββββββββββββββββ
|
28 |
def _print_trace():
|
|
|
75 |
_print_trace()
|
76 |
return None, None, f"β Unexpected Error: {type(e).__name__}: {str(e)}"
|
77 |
|
78 |
+
def guarded_clothing(image, prompt, neg, guidance):
|
79 |
+
try:
|
80 |
+
result, err = run_clothing_inpaint(image, prompt, neg, guidance)
|
81 |
+
return result, err
|
82 |
+
except Exception as e:
|
83 |
+
import traceback
|
84 |
+
traceback.print_exc()
|
85 |
+
return None, f"β Unexpected Error: {type(e).__name__}: {str(e)}"
|
86 |
+
|
87 |
# βββββββββββββββββββββ Gradio UI βββββββββββββββββββββ
|
88 |
with gr.Blocks() as demo:
|
89 |
gr.Markdown("## π§ Headshot + Background Generator (Full Prompt Control)")
|
|
|
127 |
outputs=[output_refined, output_final, error_box]
|
128 |
)
|
129 |
|
130 |
+
gr.Markdown("### π Step 3: Clothing Replacement")
|
131 |
+
|
132 |
+
with gr.Row():
|
133 |
+
clothing_prompt = gr.Textbox(
|
134 |
+
label="Clothing Prompt",
|
135 |
+
value="white female CEO professional blazer, clean look"
|
136 |
+
)
|
137 |
+
clothing_negative = gr.Textbox(
|
138 |
+
label="Clothing Negative Prompt",
|
139 |
+
value="hoodie, casual wear, fantasy, cartoon, jeans, distorted, blurry"
|
140 |
+
)
|
141 |
+
|
142 |
+
with gr.Row():
|
143 |
+
clothing_guidance = gr.Slider(1, 20, value=17.0, step=0.5, label="Clothing Guidance Scale")
|
144 |
+
|
145 |
+
with gr.Row():
|
146 |
+
clothing_btn = gr.Button("π§΅ Inpaint Clothing")
|
147 |
+
clothing_output = gr.Image(type="pil", label="Step 3: Final Image with New Clothing")
|
148 |
+
|
149 |
+
clothing_error = gr.Markdown(label="Clothing Error", value="", visible=True)
|
150 |
+
|
151 |
+
|
152 |
+
clothing_btn.click(
|
153 |
+
fn=guarded_clothing,
|
154 |
+
inputs=[output_final, clothing_prompt, clothing_negative, clothing_guidance],
|
155 |
+
outputs=[clothing_output, clothing_error],
|
156 |
+
preprocess=False
|
157 |
+
)
|
158 |
+
|
159 |
demo.launch(debug=True)
|
background_edit.py
CHANGED
@@ -21,11 +21,15 @@ from diffusers import StableDiffusionXLInpaintPipeline
|
|
21 |
from utils import pil_to_cv2, cv2_to_pil
|
22 |
import gradio as gr # β
Needed for error handling
|
23 |
|
|
|
24 |
|
|
|
|
|
25 |
|
26 |
# β
Load models once
|
27 |
yolo = YOLO("yolov8x-seg.pt")
|
28 |
|
|
|
29 |
inpaint_pipe = StableDiffusionXLInpaintPipeline.from_pretrained(
|
30 |
"diffusers/stable-diffusion-xl-1.0-inpainting-0.1",
|
31 |
torch_dtype=torch.float16,
|
@@ -51,8 +55,8 @@ def run_background_removal_and_inpaint(image_path, prompt, negative_prompt, guid
|
|
51 |
dilated = cv2.dilate(background_mask, kernel, iterations=1)
|
52 |
inpaint_mask = (dilated * 255).astype(np.uint8)
|
53 |
|
54 |
-
mask_pil = cv2_to_pil(inpaint_mask).resize((
|
55 |
-
img_pil = image.resize((
|
56 |
|
57 |
result = inpaint_pipe(
|
58 |
prompt=prompt,
|
@@ -64,3 +68,42 @@ def run_background_removal_and_inpaint(image_path, prompt, negative_prompt, guid
|
|
64 |
).images[0]
|
65 |
|
66 |
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
from utils import pil_to_cv2, cv2_to_pil
|
22 |
import gradio as gr # β
Needed for error handling
|
23 |
|
24 |
+
INPAINT_SIZE = 1024
|
25 |
|
26 |
+
# Load clothing model
|
27 |
+
clothing_model = YOLO("deepfashion2_yolov8s-seg.pt")
|
28 |
|
29 |
# β
Load models once
|
30 |
yolo = YOLO("yolov8x-seg.pt")
|
31 |
|
32 |
+
|
33 |
inpaint_pipe = StableDiffusionXLInpaintPipeline.from_pretrained(
|
34 |
"diffusers/stable-diffusion-xl-1.0-inpainting-0.1",
|
35 |
torch_dtype=torch.float16,
|
|
|
55 |
dilated = cv2.dilate(background_mask, kernel, iterations=1)
|
56 |
inpaint_mask = (dilated * 255).astype(np.uint8)
|
57 |
|
58 |
+
mask_pil = cv2_to_pil(inpaint_mask).resize((INPAINT_SIZE, INPAINT_SIZE)).convert("L")
|
59 |
+
img_pil = image.resize((INPAINT_SIZE, INPAINT_SIZE)).convert("RGB")
|
60 |
|
61 |
result = inpaint_pipe(
|
62 |
prompt=prompt,
|
|
|
68 |
).images[0]
|
69 |
|
70 |
return result
|
71 |
+
|
72 |
+
def run_clothing_inpaint(image, prompt, negative_prompt, guidance):
|
73 |
+
try:
|
74 |
+
print("[INFO] Step 3: Clothing segmentation and inpainting...", flush=True)
|
75 |
+
|
76 |
+
img_cv = np.array(image.convert("RGB"))[..., ::-1] # PIL β OpenCV BGR
|
77 |
+
h, w = img_cv.shape[:2]
|
78 |
+
|
79 |
+
# Segment clothing
|
80 |
+
results = clothing_model(img_cv)
|
81 |
+
masks = results[0].masks.data.cpu().numpy()
|
82 |
+
if len(masks) == 0:
|
83 |
+
raise gr.Error("No clothing detected. Try a different image.")
|
84 |
+
|
85 |
+
mask = masks[0]
|
86 |
+
resized_mask = cv2.resize(mask, (w, h), interpolation=cv2.INTER_NEAREST)
|
87 |
+
binary_mask = (resized_mask > 0.5).astype(np.uint8) * 255
|
88 |
+
mask_pil = Image.fromarray(binary_mask).convert("L").resize((INPAINT_SIZE, INPAINT_SIZE))
|
89 |
+
|
90 |
+
# Resize input image
|
91 |
+
resized_image = image.convert("RGB").resize((INPAINT_SIZE, INPAINT_SIZE))
|
92 |
+
|
93 |
+
# Inpaint clothing
|
94 |
+
result = inpaint_pipe(
|
95 |
+
prompt=prompt,
|
96 |
+
negative_prompt=negative_prompt,
|
97 |
+
image=resized_image,
|
98 |
+
mask_image=mask_pil,
|
99 |
+
guidance_scale=guidance,
|
100 |
+
num_inference_steps=50
|
101 |
+
).images[0]
|
102 |
+
|
103 |
+
return result, ""
|
104 |
+
|
105 |
+
except gr.Error as e:
|
106 |
+
return None, f"π {str(e)}"
|
107 |
+
except Exception as e:
|
108 |
+
traceback.print_exc()
|
109 |
+
return None, f"β Unexpected Error: {type(e).__name__}: {str(e)}"
|