MalikSahib1 commited on
Commit
7bb4830
·
verified ·
1 Parent(s): 0a48362

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +34 -54
main.py CHANGED
@@ -6,85 +6,65 @@ import numpy as np
6
  from PIL import Image, ImageEnhance, ImageFilter
7
  from rembg import remove, new_session
8
  import mediapipe as mp
 
 
9
 
10
- app = FastAPI(title="Pro Passport API")
11
 
12
- # Global variables
13
  session = None
14
- face_mesh = None
15
 
16
  @app.on_event("startup")
17
  async def startup_event():
18
- global session, face_mesh
19
  print("Loading AI Models...")
20
- # Use the portrait-specific model for higher precision
21
  session = new_session("birefnet-portrait")
22
- face_mesh = mp.solutions.face_mesh.FaceMesh(
23
- static_image_mode=True,
24
- refine_landmarks=True,
25
- max_num_faces=1
26
- )
 
 
27
  print("AI Models Loaded.")
28
 
29
  @app.post("/generate")
30
- async def generate_passport(
31
- file: UploadFile = File(...),
32
- suit_mode: bool = Form(True)
33
- ):
34
- # 1. Load image
35
  contents = await file.read()
36
  pil_img = Image.open(io.BytesIO(contents)).convert("RGBA")
37
  np_img = np.array(pil_img.convert("RGB"))
38
- h, w, _ = np_img.shape
39
-
40
- # 2. Precise Landmark Analysis
41
- results = face_mesh.process(cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR))
42
- if not results.multi_face_landmarks:
43
- raise HTTPException(status_code=400, detail="No face detected")
44
 
45
- landmarks = results.multi_face_landmarks[0].landmark
46
- # 152 = Chin, 10 = Top of head
47
- chin_y = int(landmarks[152].y * h)
48
- crown_y = int(landmarks[10].y * h)
49
- head_h = chin_y - crown_y
50
 
51
- # 3. Compliance Crop (The "Passport Math")
52
- # US standard: Chin to top of head is 50-69% of image height.
53
- # We aim for ~60%.
54
- margin_top = int(head_h * 0.8) # Space above head
55
- margin_bottom = int(head_h * 1.5) # Space below chin for shoulders
56
 
57
- y_start = max(0, crown_y - margin_top)
58
- y_end = min(h, chin_y + margin_bottom)
 
59
 
60
- # Crop the person
 
 
61
  crop = pil_img.crop((0, y_start, w, y_end))
62
 
63
- # 4. Professional Background Removal
64
  no_bg = remove(crop, session=session, alpha_matting=True)
65
 
66
- # 5. Composite White BG
67
  final = Image.new("RGBA", (600, 600), (255, 255, 255, 255))
68
- # Resize keeping aspect ratio
69
  no_bg.thumbnail((500, 500), Image.Resampling.LANCZOS)
70
- paste_x = (600 - no_bg.width) // 2
71
- paste_y = (600 - no_bg.height) + 20 # Offset to center head
72
- final.paste(no_bg, (paste_x, paste_y), no_bg)
73
-
74
- # 6. Formal Suit Enhancer (Cutout.pro style)
75
- if suit_mode:
76
- # Create a "formal" filter for the lower half
77
- lower_half = final.crop((0, 300, 600, 600))
78
- lower_half = lower_half.filter(ImageFilter.GaussianBlur(1))
79
- enhancer = ImageEnhance.Contrast(lower_half)
80
- lower_half = enhancer.enhance(1.2)
81
- final.paste(lower_half, (0, 300))
82
-
83
- # 7. Final Polish (DSLR Look)
84
- final = ImageEnhance.Sharpness(final).enhance(1.3)
85
- final = ImageEnhance.Color(final).enhance(1.1)
86
 
 
87
  buf = io.BytesIO()
88
- final.convert("RGB").save(buf, format="JPEG", quality=95, optimize=True)
89
  buf.seek(0)
90
  return StreamingResponse(buf, media_type="image/jpeg")
 
6
  from PIL import Image, ImageEnhance, ImageFilter
7
  from rembg import remove, new_session
8
  import mediapipe as mp
9
+ from mediapipe.tasks import python
10
+ from mediapipe.tasks.vision import FaceDetector, FaceDetectorOptions, RunningMode
11
 
12
+ app = FastAPI()
13
 
14
+ # Global models
15
  session = None
16
+ detector = None
17
 
18
  @app.on_event("startup")
19
  async def startup_event():
20
+ global session, detector
21
  print("Loading AI Models...")
22
+ # Use rembg with BiRefNet (best for portraits)
23
  session = new_session("birefnet-portrait")
24
+
25
+ # Initialize MediaPipe Tasks API (The only stable way)
26
+ # Note: You must ensure 'detector.tflite' exists in your /app directory
27
+ # If not present, download it from Google's official site
28
+ base_options = python.BaseOptions(model_asset_path='detector.tflite')
29
+ options = FaceDetectorOptions(base_options=base_options, running_mode=RunningMode.IMAGE)
30
+ detector = mp.tasks.vision.FaceDetector.create_from_options(options)
31
  print("AI Models Loaded.")
32
 
33
  @app.post("/generate")
34
+ async def generate_passport(file: UploadFile = File(...)):
35
+ if detector is None:
36
+ raise HTTPException(status_code=500, detail="Models not loaded")
37
+
 
38
  contents = await file.read()
39
  pil_img = Image.open(io.BytesIO(contents)).convert("RGBA")
40
  np_img = np.array(pil_img.convert("RGB"))
 
 
 
 
 
 
41
 
42
+ # 1. Detection via Tasks API
43
+ mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=np_img)
44
+ results = detector.detect(mp_image)
 
 
45
 
46
+ if not results.detections:
47
+ raise HTTPException(status_code=400, detail="No face detected")
 
 
 
48
 
49
+ # 2. Extract Box
50
+ bbox = results.detections[0].bounding_box
51
+ h, w = np_img.shape[:2]
52
 
53
+ # Simple Crop logic based on bounding box
54
+ y_start = max(0, int(bbox.origin_y - bbox.height * 0.5))
55
+ y_end = min(h, int(bbox.origin_y + bbox.height * 1.5))
56
  crop = pil_img.crop((0, y_start, w, y_end))
57
 
58
+ # 3. Background Removal
59
  no_bg = remove(crop, session=session, alpha_matting=True)
60
 
61
+ # 4. White BG + Resize
62
  final = Image.new("RGBA", (600, 600), (255, 255, 255, 255))
 
63
  no_bg.thumbnail((500, 500), Image.Resampling.LANCZOS)
64
+ final.paste(no_bg, ((600-no_bg.width)//2, (600-no_bg.height)+20), no_bg)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
+ # 5. Export
67
  buf = io.BytesIO()
68
+ final.convert("RGB").save(buf, format="JPEG", quality=95)
69
  buf.seek(0)
70
  return StreamingResponse(buf, media_type="image/jpeg")