nexusbert commited on
Commit
cb4555d
·
1 Parent(s): a06b2f8
Files changed (5) hide show
  1. Dockerfile +23 -0
  2. app.py +154 -0
  3. bg_remover.py +36 -0
  4. requirements.txt +7 -0
  5. run.sh +5 -0
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ libgl1-mesa-glx \
8
+ libglib2.0-0 \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Copy requirements and install Python dependencies
12
+ COPY requirements.txt .
13
+ RUN pip install --no-cache-dir -r requirements.txt
14
+
15
+ # Copy application code
16
+ COPY . .
17
+
18
+ # Expose port
19
+ EXPOSE 7860
20
+
21
+ # Run the application
22
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
23
+
app.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ from fastapi.responses import Response, JSONResponse
3
+ from PIL import Image
4
+ import io
5
+ import logging
6
+ from bg_remover import BackgroundRemover
7
+
8
+ logging.basicConfig(level=logging.INFO)
9
+ logger = logging.getLogger(__name__)
10
+
11
+ app = FastAPI(
12
+ title="Background Remover API",
13
+ description="API for removing backgrounds from images",
14
+ version="1.0.0"
15
+ )
16
+
17
+ background_remover: BackgroundRemover = None
18
+
19
+ def get_background_remover():
20
+ global background_remover
21
+ if background_remover is None:
22
+ logger.info("Initializing background remover...")
23
+ background_remover = BackgroundRemover()
24
+ logger.info("Background remover initialized")
25
+ return background_remover
26
+
27
+ @app.get("/")
28
+ async def root():
29
+ return {
30
+ "message": "Background Remover API",
31
+ "version": "1.0.0",
32
+ "endpoints": {
33
+ "/": "API information",
34
+ "/health": "Health check",
35
+ "/remove-background": "Remove background from image (POST)"
36
+ }
37
+ }
38
+
39
+ @app.get("/health")
40
+ async def health_check():
41
+ try:
42
+ get_background_remover()
43
+ return {"status": "healthy", "service": "background_remover"}
44
+ except Exception as e:
45
+ logger.error(f"Health check failed: {str(e)}")
46
+ raise HTTPException(status_code=503, detail=f"Service unhealthy: {str(e)}")
47
+
48
+ @app.post("/remove-background")
49
+ async def remove_background(
50
+ file: UploadFile = File(..., description="Image file to process")
51
+ ):
52
+ try:
53
+ if not file.content_type or not file.content_type.startswith('image/'):
54
+ raise HTTPException(
55
+ status_code=400,
56
+ detail="File must be an image. Supported formats: JPEG, PNG, WEBP, etc."
57
+ )
58
+
59
+ image_data = await file.read()
60
+
61
+ try:
62
+ input_image = Image.open(io.BytesIO(image_data))
63
+ if input_image.mode != 'RGBA':
64
+ input_image = input_image.convert('RGB')
65
+ except Exception as e:
66
+ raise HTTPException(
67
+ status_code=400,
68
+ detail=f"Invalid image file: {str(e)}"
69
+ )
70
+
71
+ remover = get_background_remover()
72
+
73
+ logger.info(f"Processing image: {file.filename}")
74
+ output_image = remover.remove_background(input_image)
75
+
76
+ output_buffer = io.BytesIO()
77
+ output_image.save(output_buffer, format='PNG')
78
+ output_buffer.seek(0)
79
+
80
+ logger.info(f"Successfully processed image: {file.filename}")
81
+
82
+ return Response(
83
+ content=output_buffer.getvalue(),
84
+ media_type="image/png",
85
+ headers={
86
+ "Content-Disposition": f"attachment; filename=removed_bg_{file.filename or 'image'}.png"
87
+ }
88
+ )
89
+
90
+ except HTTPException:
91
+ raise
92
+ except Exception as e:
93
+ logger.error(f"Error processing image: {str(e)}", exc_info=True)
94
+ raise HTTPException(
95
+ status_code=500,
96
+ detail=f"Error processing image: {str(e)}"
97
+ )
98
+
99
+ @app.post("/remove-background/json")
100
+ async def remove_background_json(
101
+ file: UploadFile = File(..., description="Image file to process")
102
+ ):
103
+ import base64
104
+
105
+ try:
106
+ if not file.content_type or not file.content_type.startswith('image/'):
107
+ raise HTTPException(
108
+ status_code=400,
109
+ detail="File must be an image. Supported formats: JPEG, PNG, WEBP, etc."
110
+ )
111
+
112
+ image_data = await file.read()
113
+
114
+ try:
115
+ input_image = Image.open(io.BytesIO(image_data))
116
+ if input_image.mode != 'RGBA':
117
+ input_image = input_image.convert('RGB')
118
+ except Exception as e:
119
+ raise HTTPException(
120
+ status_code=400,
121
+ detail=f"Invalid image file: {str(e)}"
122
+ )
123
+
124
+ remover = get_background_remover()
125
+
126
+ logger.info(f"Processing image: {file.filename}")
127
+ output_image = remover.remove_background(input_image)
128
+
129
+ output_buffer = io.BytesIO()
130
+ output_image.save(output_buffer, format='PNG')
131
+ output_buffer.seek(0)
132
+ image_base64 = base64.b64encode(output_buffer.getvalue()).decode('utf-8')
133
+
134
+ logger.info(f"Successfully processed image: {file.filename}")
135
+
136
+ return JSONResponse({
137
+ "success": True,
138
+ "message": "Background removed successfully",
139
+ "image": f"data:image/png;base64,{image_base64}",
140
+ "filename": f"removed_bg_{file.filename or 'image'}.png"
141
+ })
142
+
143
+ except HTTPException:
144
+ raise
145
+ except Exception as e:
146
+ logger.error(f"Error processing image: {str(e)}", exc_info=True)
147
+ return JSONResponse(
148
+ status_code=500,
149
+ content={
150
+ "success": False,
151
+ "message": f"Error processing image: {str(e)}"
152
+ }
153
+ )
154
+
bg_remover.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ from rembg import remove, new_session
3
+ import logging
4
+ import os
5
+ from typing import Tuple
6
+
7
+ class BackgroundRemover:
8
+ def __init__(self, model_name: str = "isnet-general-use"):
9
+ self.model = model_name
10
+ self.session = new_session(model_name)
11
+ logging.basicConfig(level=logging.INFO)
12
+
13
+ def remove_background(self, input_image: Image.Image) -> Image.Image:
14
+ return remove(
15
+ input_image,
16
+ session=self.session,
17
+ alpha_matting=True,
18
+ alpha_matting_foreground_threshold=270,
19
+ alpha_matting_background_threshold=20,
20
+ alpha_matting_erode_size=11
21
+ )
22
+
23
+ def process_image(self, input_path: str, output_path: str) -> Tuple[bool, str]:
24
+ try:
25
+ with Image.open(input_path) as input_image:
26
+ output = self.remove_background(input_image)
27
+
28
+ if not output_path.lower().endswith('.png'):
29
+ output_path = os.path.splitext(output_path)[0] + '.png'
30
+
31
+ output.save(output_path, 'PNG')
32
+ return True, "Background removed successfully"
33
+ except Exception as e:
34
+ logging.error(f"Error processing image: {str(e)}")
35
+ return False, f"Error processing image: {str(e)}"
36
+
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastapi>=0.104.0
2
+ uvicorn[standard]>=0.24.0
3
+ python-multipart>=0.0.6
4
+ pillow>=10.0.0
5
+ rembg>=2.0.50
6
+ numpy>=1.24.0
7
+
run.sh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Simple script to run the FastAPI app locally
3
+
4
+ uvicorn app:app --host 0.0.0.0 --port 7860 --reload
5
+