Spaces:
Running
Running
Refactor API structure: remove Streamlit integration, update Flask app, and enhance documentation
eb4231e
| title: Magic Eraser API | |
| emoji: 🧹 | |
| colorFrom: indigo | |
| colorTo: yellow | |
| sdk: docker | |
| pinned: false | |
| license: mit | |
| short_description: Image processing API for removing objects from images | |
| # Magic Eraser API | |
| An AI-powered REST API that helps you remove unwanted objects from images and perform content-aware resizing. | |
| ## Features | |
| - **Object Removal**: Remove unwanted objects from images with advanced AI inpainting | |
| - **Seam Carving**: Content-aware image resizing and object removal | |
| - **REST API**: Simple endpoints for integrating image processing into your applications | |
| ## API Documentation | |
| The REST API provides these endpoints for image processing: | |
| - `GET /` - Health check endpoint | |
| - `POST /api/inpaint` - For inpainting/object removal | |
| - `POST /api/seam-carve` - For seam carving/content-aware resizing | |
| ### Inpainting API | |
| **Endpoint:** `POST /api/inpaint` | |
| **Request Body:** | |
| ```json | |
| { | |
| "image": "data:image/png;base64,<base64-encoded-image>", | |
| "mask": "data:image/png;base64,<base64-encoded-mask>" | |
| } | |
| ``` | |
| **Response:** | |
| ```json | |
| { | |
| "result": "data:image/png;base64,<base64-encoded-result>" | |
| } | |
| ``` | |
| **JavaScript Example:** | |
| ```javascript | |
| async function removeObject(imageBase64, maskBase64) { | |
| const response = await fetch('https://yourdeployment.hf.space/api/inpaint', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| image: imageBase64, | |
| mask: maskBase64, | |
| }), | |
| }); | |
| const data = await response.json(); | |
| return data.result; // Base64 encoded result image | |
| } | |
| ``` | |
| ### Seam Carving API | |
| **Endpoint:** `POST /api/seam-carve` | |
| **Request Body:** | |
| ```json | |
| { | |
| "image": "data:image/png;base64,<base64-encoded-image>", | |
| "mask": "data:image/png;base64,<base64-encoded-mask>", | |
| "vs": 50, | |
| "hs": 30, | |
| "mode": "resize" | |
| } | |
| ``` | |
| **Response:** | |
| ```json | |
| { | |
| "result": "data:image/png;base64,<base64-encoded-result>" | |
| } | |
| ``` | |
| **JavaScript Example:** | |
| ```javascript | |
| async function resizeImage(imageBase64, maskBase64) { | |
| const response = await fetch('https://yourdeployment.hf.space/api/seam-carve', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| image: imageBase64, | |
| mask: maskBase64, | |
| vs: -50, // Remove 50 vertical seams (make narrower) | |
| hs: 30, // Add 30 horizontal seams (make taller) | |
| mode: 'resize', // or 'remove' to remove objects | |
| }), | |
| }); | |
| const data = await response.json(); | |
| return data.result; | |
| } | |
| ``` | |
| ### Creating a Drawing Canvas for Masks | |
| To integrate with our API, you'll need a way for users to draw masks over images. Here's how to set up a canvas in different frameworks: | |
| #### Using HTML5 Canvas (JavaScript) | |
| ```javascript | |
| function setupCanvas(imageUrl) { | |
| // Create canvas elements | |
| const imageCanvas = document.createElement('canvas'); | |
| const maskCanvas = document.createElement('canvas'); | |
| const container = document.getElementById('canvas-container'); | |
| container.appendChild(imageCanvas); | |
| container.appendChild(maskCanvas); | |
| // Load image | |
| const img = new Image(); | |
| img.onload = function() { | |
| // Set canvas dimensions | |
| imageCanvas.width = maskCanvas.width = img.width; | |
| imageCanvas.height = maskCanvas.height = img.height; | |
| // Draw image on image canvas | |
| const imgCtx = imageCanvas.getContext('2d'); | |
| imgCtx.drawImage(img, 0, 0); | |
| // Setup mask canvas for drawing | |
| const maskCtx = maskCanvas.getContext('2d'); | |
| maskCtx.fillStyle = 'rgba(255, 0, 0, 0.5)'; | |
| // Drawing state | |
| let isDrawing = false; | |
| // Mouse/touch event handlers | |
| maskCanvas.addEventListener('mousedown', startDrawing); | |
| maskCanvas.addEventListener('mousemove', draw); | |
| maskCanvas.addEventListener('mouseup', stopDrawing); | |
| maskCanvas.addEventListener('mouseleave', stopDrawing); | |
| function startDrawing(e) { | |
| isDrawing = true; | |
| draw(e); | |
| } | |
| function draw(e) { | |
| if (!isDrawing) return; | |
| const rect = maskCanvas.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| maskCtx.beginPath(); | |
| maskCtx.arc(x, y, 15, 0, Math.PI * 2); | |
| maskCtx.fill(); | |
| } | |
| function stopDrawing() { | |
| isDrawing = false; | |
| } | |
| // Add button to get mask data | |
| const button = document.createElement('button'); | |
| button.textContent = 'Process Image'; | |
| button.onclick = function() { | |
| const maskData = maskCanvas.toDataURL('image/png'); | |
| const imageData = imageCanvas.toDataURL('image/png'); | |
| // Send to API | |
| sendToAPI(imageData, maskData); | |
| }; | |
| container.appendChild(button); | |
| }; | |
| img.src = imageUrl; | |
| } | |
| function sendToAPI(imageData, maskData) { | |
| fetch('https://yourdeployment.hf.space/api/inpaint', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| image: imageData, | |
| mask: maskData | |
| }), | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| // Display the result | |
| const resultImg = document.createElement('img'); | |
| resultImg.src = data.result; | |
| document.getElementById('result-container').appendChild(resultImg); | |
| }); | |
| } | |
| ``` | |
| #### Using React with Canvas | |
| For React applications, consider using libraries like: | |
| - `react-konva` for general canvas operations | |
| - `react-canvas-draw` for simple drawing tools | |
| - `fabric.js` wrapped in a React component for more complex drawing | |
| Example with react-canvas-draw: | |
| ```jsx | |
| import React, { useRef, useState } from 'react'; | |
| import CanvasDraw from 'react-canvas-draw'; | |
| function MaskDrawer({ imageUrl, onSubmit }) { | |
| const canvasRef = useRef(null); | |
| const [brushSize, setBrushSize] = useState(15); | |
| const handleSubmit = () => { | |
| if (canvasRef.current) { | |
| // Get the mask data | |
| const maskData = canvasRef.current.canvas.drawing.toDataURL(); | |
| onSubmit(imageUrl, maskData); | |
| } | |
| }; | |
| const handleClear = () => { | |
| if (canvasRef.current) { | |
| canvasRef.current.clear(); | |
| } | |
| }; | |
| return ( | |
| <div> | |
| <div> | |
| <label> | |
| Brush Size: | |
| <input | |
| type="range" | |
| min="5" | |
| max="50" | |
| value={brushSize} | |
| onChange={e => setBrushSize(parseInt(e.target.value))} | |
| /> | |
| </label> | |
| </div> | |
| <CanvasDraw | |
| ref={canvasRef} | |
| brushColor="rgba(255, 0, 0, 0.5)" | |
| brushRadius={brushSize} | |
| lazyRadius={0} | |
| canvasWidth={800} | |
| canvasHeight={600} | |
| imgSrc={imageUrl} | |
| /> | |
| <div> | |
| <button onClick={handleClear}>Clear</button> | |
| <button onClick={handleSubmit}>Process Image</button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| ``` | |
| #### Tips for Creating Effective Masks | |
| 1. Use a contrasting color for the mask (red or magenta works well) | |
| 2. Keep brush strokes within the boundaries of the object to remove | |
| 3. For best results, completely cover the object you want to remove | |
| 4. When sending to the API, make sure the mask's alpha channel is 0 for areas to remove | |
| ## Local Development | |
| To run the API locally: | |
| ```bash | |
| # Install dependencies | |
| pip install -r requirements.txt | |
| # Run Flask API | |
| python api.py | |
| ``` | |
| ## License | |
| This project is licensed under the MIT License - see the LICENSE file for details. | |