MASSJ77 commited on
Commit
fcc1a0e
·
verified ·
1 Parent(s): 32bb925

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +82 -37
app.py CHANGED
@@ -4,69 +4,112 @@ from fastapi import FastAPI, UploadFile, File
4
  from fastapi.responses import JSONResponse
5
  import cv2
6
  import numpy as np
7
- from huggingface_hub import hf_hub_download
8
- from realesrgan import RealESRGAN
9
  from mediapipe import solutions as mp_solutions
10
 
11
- # Cache dir for Hugging Face
12
- CACHE_DIR = "/tmp/hf_cache"
13
- os.environ["HF_HOME"] = CACHE_DIR
14
- os.makedirs(CACHE_DIR, exist_ok=True)
15
-
16
  app = FastAPI(title="Face Beautification API")
17
 
18
- # Load Mediapipe face detector
19
- mp_face = mp_solutions.face_detection.FaceDetection(
20
- model_selection=1, min_detection_confidence=0.5
21
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
- # ✅ Download ESRGAN weights from Hugging Face (free)
24
- model_path = hf_hub_download(
25
- repo_id="eugenesiow/real-esrgan",
26
- filename="RealESRGAN_x4plus.pth",
27
- cache_dir=CACHE_DIR
28
- )
29
 
30
- # Load ESRGAN model
31
- device = "cuda" if cv2.cuda.getCudaEnabledDeviceCount() > 0 else "cpu"
32
- model = RealESRGAN(device, scale=4)
33
- model.load_weights(model_path)
34
 
35
  @app.get("/")
36
  async def root():
 
37
  return {"message": "Free Face Beautification API is running!"}
38
 
39
  @app.post("/beautify")
40
  async def beautify(image: UploadFile = File(...)):
 
 
 
 
 
 
41
  try:
42
- # Read image
43
  contents = await image.read()
44
  npimg = np.frombuffer(contents, np.uint8)
45
  img = cv2.imdecode(npimg, cv2.IMREAD_COLOR)
46
 
47
- # Detect faces
 
 
 
48
  results = mp_face.process(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
 
49
  if not results.detections:
50
- return JSONResponse({"error": "No face detected"}, status_code=400)
51
 
 
52
  for detection in results.detections:
53
  bbox = detection.location_data.relative_bounding_box
54
  h, w, _ = img.shape
55
- x1 = int(bbox.xmin * w)
56
- y1 = int(bbox.ymin * h)
57
- x2 = int((bbox.xmin + bbox.width) * w)
58
- y2 = int((bbox.ymin + bbox.height) * h)
 
 
 
 
59
  face = img[y1:y2, x1:x2]
60
 
61
- # Beautify (enhance + smooth)
62
- face_upscaled = model.predict(face)
63
- face_smooth = cv2.bilateralFilter(face_upscaled, 9, 75, 75)
 
 
 
64
 
65
- # Blend face back
66
- face_smooth = cv2.resize(face_smooth, (x2 - x1, y2 - y1))
67
- img[y1:y2, x1:x2] = face_smooth
 
 
 
68
 
69
- # Encode final image as Base64
70
  _, buffer = cv2.imencode(".jpg", img)
71
  img_base64 = base64.b64encode(buffer).decode("utf-8")
72
 
@@ -75,9 +118,11 @@ async def beautify(image: UploadFile = File(...)):
75
  "message": "Beautification complete!",
76
  "image_base64": img_base64
77
  })
 
78
  except Exception as e:
79
- return JSONResponse({"error": str(e)}, status_code=500)
80
 
81
  @app.get("/health")
82
  async def health():
83
- return {"ready": True}
 
 
4
  from fastapi.responses import JSONResponse
5
  import cv2
6
  import numpy as np
7
+ from realesrgan import RealESRGANer
8
+ from basicsr.archs.rrdbnet_arch import RRDBNet
9
  from mediapipe import solutions as mp_solutions
10
 
11
+ # Initialize FastAPI app
 
 
 
 
12
  app = FastAPI(title="Face Beautification API")
13
 
14
+ # --- Model Loading ---
15
+
16
+ # Load Mediapipe face detector
17
+ try:
18
+ mp_face = mp_solutions.face_detection.FaceDetection(
19
+ model_selection=1, min_detection_confidence=0.5)
20
+ except Exception as e:
21
+ print(f"Error loading Mediapipe face detector: {e}")
22
+ mp_face = None
23
+
24
+ # Correctly load the Real-ESRGAN model for CPU inference
25
+ # The model weights are pre-downloaded in the Dockerfile to the 'weights' directory
26
+ model_path = os.path.join("weights", "RealESRGAN_x4plus.pth")
27
+ upsampler = None
28
+
29
+ if os.path.exists(model_path) and mp_face:
30
+ try:
31
+ # Define the model architecture
32
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4)
33
+
34
+ # Initialize the RealESRGANer
35
+ # `half=False` is important for CPU-only execution
36
+ upsampler = RealESRGANer(
37
+ scale=4,
38
+ model_path=model_path,
39
+ dni_weight=None,
40
+ model=model,
41
+ tile=0,
42
+ tile_pad=10,
43
+ pre_pad=0,
44
+ half=False,
45
+ gpu_id=None, # Explicitly set to None for CPU
46
+ )
47
+ except Exception as e:
48
+ print(f"Error loading Real-ESRGAN model: {e}")
49
+ upsampler = None
50
+ else:
51
+ print("Model weights not found or face detector failed to load.")
52
 
 
 
 
 
 
 
53
 
54
+ # --- API Endpoints ---
 
 
 
55
 
56
  @app.get("/")
57
  async def root():
58
+ """Root endpoint to check if the API is running."""
59
  return {"message": "Free Face Beautification API is running!"}
60
 
61
  @app.post("/beautify")
62
  async def beautify(image: UploadFile = File(...)):
63
+ """
64
+ Receives an image, detects faces, enhances them, and returns the result.
65
+ """
66
+ if not upsampler or not mp_face:
67
+ return JSONResponse({"error": "Model not loaded, API is not operational."}, status_code=503)
68
+
69
  try:
70
+ # 1. Read and decode the uploaded image
71
  contents = await image.read()
72
  npimg = np.frombuffer(contents, np.uint8)
73
  img = cv2.imdecode(npimg, cv2.IMREAD_COLOR)
74
 
75
+ if img is None:
76
+ return JSONResponse({"error": "Invalid image file."}, status_code=400)
77
+
78
+ # 2. Detect faces using Mediapipe
79
  results = mp_face.process(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
80
+
81
  if not results.detections:
82
+ return JSONResponse({"error": "No face detected in the image."}, status_code=400)
83
 
84
+ # 3. Process each detected face
85
  for detection in results.detections:
86
  bbox = detection.location_data.relative_bounding_box
87
  h, w, _ = img.shape
88
+
89
+ # Ensure coordinates are within image bounds
90
+ x1 = max(0, int(bbox.xmin * w))
91
+ y1 = max(0, int(bbox.ymin * h))
92
+ x2 = min(w, int((bbox.xmin + bbox.width) * w))
93
+ y2 = min(h, int((bbox.ymin + bbox.height) * h))
94
+
95
+ # Crop the face
96
  face = img[y1:y2, x1:x2]
97
 
98
+ if face.size == 0:
99
+ continue
100
+
101
+ # 4. Enhance the face using Real-ESRGAN
102
+ # The `enhance` method returns the upscaled image and its mode
103
+ face_upscaled, _ = upsampler.enhance(face)
104
 
105
+ # 5. Apply a smoothing filter for the "beautification" effect
106
+ face_smooth = cv2.bilateralFilter(face_upscaled, d=9, sigmaColor=75, sigmaSpace=75)
107
+
108
+ # 6. Resize the enhanced face back to its original dimensions and blend it in
109
+ face_smooth_resized = cv2.resize(face_smooth, (x2 - x1, y2 - y1))
110
+ img[y1:y2, x1:x2] = face_smooth_resized
111
 
112
+ # 7. Encode the final image to Base64 to send in the JSON response
113
  _, buffer = cv2.imencode(".jpg", img)
114
  img_base64 = base64.b64encode(buffer).decode("utf-8")
115
 
 
118
  "message": "Beautification complete!",
119
  "image_base64": img_base64
120
  })
121
+
122
  except Exception as e:
123
+ return JSONResponse({"error": f"An unexpected error occurred: {str(e)}"}, status_code=500)
124
 
125
  @app.get("/health")
126
  async def health():
127
+ """Health check endpoint."""
128
+ return {"ready": bool(upsampler and mp_face)}