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. | |