Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import cv2 | |
| from component import bbox | |
| from component import skeleton | |
| from component import control | |
| # Load example image | |
| image_example = cv2.cvtColor(cv2.imread("examples/a.png"), cv2.COLOR_BGR2RGB) | |
| uni_height = 800 | |
| # Create the interface with a cute theme | |
| with gr.Blocks(theme=gr.themes.Soft()) as interface: | |
| # Title with kawaii emojis | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown(f""" | |
| <div style='text-align: center; | |
| padding: 25px; | |
| border-radius: 12px; | |
| background: #f3f4f6; | |
| box-shadow: 0 10px 25px rgba(0, 0, 0, 0.08), | |
| 0 2px 4px rgba(0, 0, 0, 0.05); | |
| margin: 20px 0; | |
| border: 1px solid rgba(0,0,0,0.1); | |
| width: 100%; | |
| position: relative; | |
| transition: transform 0.2s ease, box-shadow 0.2s ease;'> | |
| <h1 style='margin: 0; | |
| color: #BE830E; | |
| font-family: "Comic Sans MS", cursive; | |
| text-shadow: 2px 2px 4px rgba(190, 131, 14, 0.1); | |
| letter-spacing: 1.2px; | |
| position: relative; | |
| z-index: 2;'> | |
| ๐๏ธ HandCraft ๐๏ธ | |
| </h1> | |
| <h3 style='margin: 10px 0 0; | |
| color: #374151; | |
| font-family: "Comic Sans MS", cursive; | |
| font-weight: 500; | |
| position: relative; | |
| z-index: 2; | |
| line-height: 1.4; | |
| text-shadow: 0 1px 2px rgba(0,0,0,0.05);'> | |
| ๐พโจ Anatomically Correct Restoration of Malformed Hands in Diffusion Generated Images โจ๐พ | |
| </h3> | |
| </div> | |
| """) | |
| # Shared input image at the top | |
| input_image = gr.Image( | |
| type="numpy", | |
| label="๐ธ Upload Your Image with Hands", | |
| height=uni_height, | |
| value=image_example | |
| ) | |
| # Button to trigger the cascade | |
| generate_btn = gr.Button("โจ๐ช Generate Control Mask ๐ชโจ", variant="primary", size="lg") | |
| # State variables to store intermediate results | |
| bbox_mask_state = gr.State() | |
| keypoints_state = gr.State() | |
| skeleton_state = gr.State() | |
| # Results section with tabs for each step | |
| with gr.Tabs(): | |
| with gr.TabItem("๐พ Step 1: Malformed Hand Detection"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| output_bbox_result = gr.Textbox(label="๐ท๏ธ Number of Hands & Classification with Confidence") | |
| include_standard = gr.Checkbox( | |
| label="๐คฒ Include All Hands", | |
| value=True | |
| ) | |
| expand_ratio = gr.Slider( | |
| minimum=0.5, | |
| maximum=2, | |
| step=0.01, | |
| value=1, | |
| label="๐ Bounding Box Expand Ratio" | |
| ) | |
| with gr.Column(scale=2): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| output_bbox_vis = gr.Image(type="numpy", label="๐ฆ Bounding Box", height=uni_height) | |
| with gr.Column(scale=1): | |
| output_bbox_mask = gr.Image(type="numpy", label="๐ญ Bounding Box Mask", height=uni_height) | |
| with gr.TabItem("๐ Step 2: Body Pose Estimation"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| output_keypoints = gr.Textbox(label="๐ Key Points String") | |
| with gr.Column(scale=2): | |
| output_skeleton = gr.Image(type="numpy", label="๐ช Body Skeleton", height=uni_height) | |
| with gr.TabItem("๐จ Step 3: Control Image Generation"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| hand_template = gr.Radio( | |
| ["opened-palm", "fist-back"], | |
| label="๐ Hand Template", | |
| value="opened-palm" | |
| ) | |
| control_expand = gr.Slider( | |
| minimum=0.5, | |
| maximum=2, | |
| step=0.01, | |
| value=1, | |
| label="๐ Control Image Expand Ratio" | |
| ) | |
| include_undetected = gr.Checkbox( | |
| label="๐ Include Undetected Hand", | |
| value=True | |
| ) | |
| with gr.Column(scale=2): | |
| with gr.Row(): | |
| with gr.Column(): | |
| output_viz = gr.Image(type="numpy", label="๐๏ธ Visualization Image", height=300) | |
| with gr.Column(): | |
| output_control = gr.Image(type="numpy", label="๐ฎ Control Image", height=300) | |
| with gr.Row(): | |
| with gr.Column(): | |
| output_control_mask = gr.Image(type="numpy", label="๐ญ Control Mask", height=300) | |
| with gr.Column(): | |
| output_union_mask = gr.Image(type="numpy", label="๐ Union Mask", height=300) | |
| with gr.TabItem("๐ Output Control Image"): | |
| gr.Markdown(""" | |
| ### โจ๐ Control Image ๐โจ | |
| Your hand-fixed image is ready! (๏พโใฎโ)๏พ*:๏ฝฅ๏พโง | |
| """) | |
| with gr.Row(): | |
| with gr.Column(): | |
| output_final_control = gr.Image(type="numpy", label="๐ Fixed Hand Image", interactive=False, height=uni_height) | |
| with gr.Column(): | |
| gr.Markdown(""" | |
| ### ๐โจ How to Use Your Control Image โจ๐ | |
| 1. ๐ช Take this Control Image to your favorite Stable Diffusion model | |
| 2. ๐ Apply that to the ControlNet | |
| 3. ๐ฌ Sprinkle some parameters until it looks just right! | |
| """) | |
| # Citation information with cute emojis | |
| with gr.Accordion("๐โจ Citation Information โจ๐", open=False): | |
| gr.Markdown(""" | |
| If you find this tool helpful for your research, please cite our paper: ๐ | |
| ```bibtex | |
| @InProceedings{2025_wacv_handcraft, | |
| author = {Qin, Zhenyue and Zhang, Yiqun and Liu, Yang and Campbell, Dylan}, | |
| title = {HandCraft: Anatomically Correct Restoration of Malformed Hands in Diffusion Generated Images}, | |
| booktitle = {Proceedings of the Winter Conference on Applications of Computer Vision (WACV)}, | |
| month = {February}, | |
| year = {2025}, | |
| pages = {3925-3933} | |
| } | |
| ``` | |
| Thank you for using HandCraft! โจ๐โจ | |
| """) | |
| # Define the step functions with improved data flow | |
| def run_step1(image, include_std, expand_r): | |
| # Step 1: Run hand detection | |
| bbox_result, bbox_vis, bbox_mask = bbox(image, include_std, expand_r) | |
| return bbox_result, bbox_vis, bbox_mask, bbox_mask | |
| def run_step2(image): | |
| # Step 2: Run pose estimation | |
| keypoints, skeleton_img = skeleton(image) | |
| return keypoints, skeleton_img, keypoints, skeleton_img | |
| def run_step3(image, bbox_mask, keypoints, control_exp, hand_tmpl, skeleton_img, include_undetect): | |
| # Step 3: Generate control images | |
| viz, control_img, control_mask, union_mask = control( | |
| image, bbox_mask, keypoints, control_exp, hand_tmpl, skeleton_img, include_undetect | |
| ) | |
| return viz, control_img, control_mask, union_mask, control_img | |
| # Connect the Generate button to trigger all steps in sequence | |
| generate_btn.click( | |
| fn=run_step1, | |
| inputs=[input_image, include_standard, expand_ratio], | |
| outputs=[output_bbox_result, output_bbox_vis, output_bbox_mask, bbox_mask_state] | |
| ).then( | |
| fn=run_step2, | |
| inputs=[input_image], | |
| outputs=[output_keypoints, output_skeleton, keypoints_state, skeleton_state] | |
| ).then( | |
| fn=run_step3, | |
| inputs=[ | |
| input_image, | |
| bbox_mask_state, | |
| keypoints_state, | |
| control_expand, | |
| hand_template, | |
| skeleton_state, | |
| include_undetected | |
| ], | |
| outputs=[output_viz, output_control, output_control_mask, output_union_mask, output_final_control] | |
| ) | |
| # Launch the interface | |
| interface.launch(server_name="0.0.0.0", server_port=7860, share=True) |