| import io | |
| from typing import Any | |
| import gradio as gr | |
| import httpx | |
| from environs import Env | |
| from gradio_image_annotation import image_annotator | |
| from PIL import Image | |
| env = Env() | |
| env.read_env() | |
| with env.prefixed("ERASER_"): | |
| API_URL: str = str(env.str("API_URL", "https://spaces.finegrain.ai/eraser")) | |
| API_KEY: str | None = env.str("API_KEY", None) | |
| CA_BUNDLE: str | None = env.str("CA_BUNDLE", None) | |
| auth = None if API_KEY is None else httpx.BasicAuth("hf", API_KEY) | |
| def process_bbox(prompts: dict[str, Any]) -> Image.Image: | |
| assert isinstance(img := prompts["image"], Image.Image) | |
| assert isinstance(boxes := prompts["boxes"], list) | |
| assert len(boxes) == 1 | |
| assert isinstance(box := boxes[0], dict) | |
| data = {"bbox": ",".join([str(box[k]) for k in ["xmin", "ymin", "xmax", "ymax"]])} | |
| with io.BytesIO() as f: | |
| img.save(f, format="JPEG") | |
| r = httpx.post( | |
| API_URL, | |
| data=data, | |
| files={"file": f}, | |
| verify=CA_BUNDLE or True, | |
| timeout=30.0, | |
| auth=auth, | |
| ) | |
| r.raise_for_status() | |
| return Image.open(io.BytesIO(r.content)) | |
| def on_change_bbox(prompts: dict[str, Any]): | |
| return gr.update(interactive=len(prompts["boxes"]) > 0) | |
| def process_prompt(img: Image.Image, prompt: str) -> Image.Image: | |
| data = {"prompt": prompt} | |
| with io.BytesIO() as f: | |
| img.save(f, format="JPEG") | |
| r = httpx.post( | |
| API_URL, | |
| data=data, | |
| files={"file": f}, | |
| verify=CA_BUNDLE or True, | |
| timeout=30.0, | |
| auth=auth, | |
| ) | |
| r.raise_for_status() | |
| return Image.open(io.BytesIO(r.content)) | |
| def on_change_prompt(img: Image.Image | None, prompt: str | None): | |
| return gr.update(interactive=bool(img and prompt)) | |
| desc = """ | |
| <center> | |
| <h1>Object Eraser Powered by Refiners</h1> | |
| <p style="font-size: 1.25rem;"> | |
| <a href="https://refine.rs" target="_blank">[refiners]</a> | |
| <a href="https://finegrain.ai/" target="_blank">[finegrain]</a> | |
| </p> | |
| <p> | |
| Erase any object from your image just by naming it — no manual work required! | |
| Not only will the object disappear, but so will its effects on the scene, like shadows or reflections. | |
| </p> | |
| <p> | |
| If you enjoyed this space, please consider starring Refiners on GitHub! | |
| | |
| <a href="https://github.com/finegrain-ai/refiners" target="_blank"> | |
| <img | |
| src="https://img.shields.io/github/stars/finegrain-ai/refiners?style=social" | |
| style="display: inline; vertical-align: middle;" | |
| /> | |
| </a> | |
| </p> | |
| </center> | |
| """ | |
| with gr.Blocks() as demo: | |
| gr.HTML(desc) | |
| with gr.Tab("By prompt", id="tab_prompt"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| iimg = gr.Image(type="pil", label="Input") | |
| prompt = gr.Textbox(label="What should we erase?") | |
| with gr.Column(): | |
| oimg = gr.Image(show_label=False, label="Output") | |
| with gr.Row(): | |
| btn = gr.Button("Erase Object", interactive=False) | |
| for inp in [iimg, prompt]: | |
| inp.change( | |
| fn=on_change_prompt, | |
| inputs=[iimg, prompt], | |
| outputs=[btn], | |
| ) | |
| btn.click(fn=process_prompt, inputs=[iimg, prompt], outputs=[oimg]) | |
| ex = gr.Examples( | |
| examples=[ | |
| [ | |
| "examples/white-towels-rattan-basket-white-table-with-bright-room-background.jpg", | |
| "soap", | |
| ], | |
| [ | |
| "examples/interior-decor-with-mirror-potted-plant.jpg", | |
| "potted plant", | |
| ], | |
| [ | |
| "examples/detail-ball-basketball-court-sunset.jpg", | |
| "basketball", | |
| ], | |
| [ | |
| "examples/still-life-device-table_23-2150994394.jpg", | |
| "glass of water", | |
| ], | |
| [ | |
| "examples/knife-fork-green-checkered-napkin_140725-63576.jpg", | |
| "knife and fork", | |
| ], | |
| [ | |
| "examples/city-night-with-architecture-vibrant-lights_23-2149836930.jpg", | |
| "frontmost black car on right lane", | |
| ], | |
| [ | |
| "examples/close-up-coffee-latte-wooden-table_23-2147893063.jpg", | |
| "coffee cup on plate", | |
| ], | |
| [ | |
| "examples/empty-chair-with-vase-plant_74190-2078.jpg", | |
| "chair", | |
| ], | |
| ], | |
| inputs=[iimg, prompt], | |
| outputs=[oimg], | |
| fn=process_prompt, | |
| cache_examples=True, | |
| ) | |
| with gr.Tab("By bounding box", id="tab_bb"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| annotator = image_annotator( | |
| image_type="pil", | |
| disable_edit_boxes=True, | |
| show_download_button=False, | |
| show_share_button=False, | |
| single_box=True, | |
| label="Input", | |
| ) | |
| with gr.Column(): | |
| oimg = gr.Image(show_label=False, label="Output") | |
| with gr.Row(): | |
| btn = gr.Button("Erase Object", interactive=False) | |
| annotator.change( | |
| fn=on_change_bbox, | |
| inputs=[annotator], | |
| outputs=[btn], | |
| ) | |
| btn.click(fn=process_bbox, inputs=[annotator], outputs=[oimg]) | |
| ex = gr.Examples( | |
| examples=[ | |
| { | |
| "image": "examples/white-towels-rattan-basket-white-table-with-bright-room-background.jpg", | |
| "boxes": [{"xmin": 836, "ymin": 475, "xmax": 1125, "ymax": 1013}], | |
| }, | |
| { | |
| "image": "examples/interior-decor-with-mirror-potted-plant.jpg", | |
| "boxes": [{"xmin": 47, "ymin": 907, "xmax": 397, "ymax": 1633}], | |
| }, | |
| { | |
| "image": "examples/detail-ball-basketball-court-sunset.jpg", | |
| "boxes": [{"xmin": 673, "ymin": 954, "xmax": 911, "ymax": 1186}], | |
| }, | |
| { | |
| "image": "examples/still-life-device-table_23-2150994394.jpg", | |
| "boxes": [{"xmin": 429, "ymin": 586, "xmax": 571, "ymax": 834}], | |
| }, | |
| { | |
| "image": "examples/knife-fork-green-checkered-napkin_140725-63576.jpg", | |
| "boxes": [{"xmin": 972, "ymin": 226, "xmax": 1092, "ymax": 1023}], | |
| }, | |
| { | |
| "image": "examples/city-night-with-architecture-vibrant-lights_23-2149836930.jpg", | |
| "boxes": [{"xmin": 215, "ymin": 637, "xmax": 411, "ymax": 855}], | |
| }, | |
| { | |
| "image": "examples/close-up-coffee-latte-wooden-table_23-2147893063.jpg", | |
| "boxes": [{"xmin": 255, "ymin": 456, "xmax": 1080, "ymax": 1064}], | |
| }, | |
| { | |
| "image": "examples/empty-chair-with-vase-plant_74190-2078.jpg", | |
| "boxes": [{"xmin": 35, "ymin": 320, "xmax": 383, "ymax": 983}], | |
| }, | |
| ], | |
| inputs=[annotator], | |
| outputs=[oimg], | |
| fn=process_bbox, | |
| cache_examples=True, | |
| ) | |
| demo.launch(show_api=False) | |