MalikSahib1 commited on
Commit
94c9525
·
verified ·
1 Parent(s): 666f5b2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -40
app.py CHANGED
@@ -1,22 +1,28 @@
1
  import os
 
2
  import cv2
3
  import numpy as np
4
  import requests
5
- from PIL import Image, ImageEnhance, ImageOps
6
  from rembg import remove, new_session
7
  import mediapipe as mp
8
  import gradio as gr
9
 
10
  # Force MediaPipe to use its internal stable solutions
11
- mp_face_detection = mp.solutions.face_detection
 
 
 
 
12
 
13
  # Initialize AI Models at startup
14
- print("Loading Pro-Grade AI Models...")
15
- # birefnet-portrait is the world-class cutout model
16
  session = new_session("birefnet-portrait")
17
  face_detector = mp_face_detection.FaceDetection(model_selection=1, min_detection_confidence=0.5)
18
 
19
  # Download Professional Suit Assets
 
20
  SUITS = {
21
  "Navy Blue Business": "https://raw.githubusercontent.com/AIGuy-Official/Passport-Assets/main/suit1.png",
22
  "Classic Black Formal": "https://raw.githubusercontent.com/AIGuy-Official/Passport-Assets/main/suit2.png"
@@ -24,16 +30,17 @@ SUITS = {
24
 
25
  os.makedirs('suits', exist_ok=True)
26
  for name, url in SUITS.items():
27
- if not os.path.exists(f"suits/{name}.png"):
 
28
  try:
29
  r = requests.get(url, timeout=10)
30
- with open(f"suits/{name}.png", 'wb') as f: f.write(r.content)
31
  except: pass
32
 
33
  def make_passport(input_image, suit_choice, bg_color):
34
  if input_image is None: return None
35
 
36
- # 1. Image Preparation
37
  pil_img = Image.fromarray(input_image).convert("RGBA")
38
  np_img = cv2.cvtColor(input_image, cv2.COLOR_RGB2BGR)
39
  h, w, _ = np_img.shape
@@ -43,76 +50,78 @@ def make_passport(input_image, suit_choice, bg_color):
43
  if not results.detections:
44
  return None
45
 
46
- # Get coordinates
47
  bbox = results.detections[0].location_data.relative_bounding_box
48
  fx, fy, fw, fh = int(bbox.xmin * w), int(bbox.ymin * h), int(bbox.width * w), int(bbox.height * h)
49
 
50
- # 3. Professional Passport Math (Compliance)
51
- # Head must be 50-70% of the image height
52
- margin_top = int(fh * 0.4)
53
- margin_bottom = int(fh * 1.5)
54
 
55
  crop_y1 = max(0, fy - margin_top)
56
  crop_y2 = min(h, fy + fh + margin_bottom)
57
 
58
- # Crop to maintain aspect ratio for a square 1:1 passport
59
- crop_width = (crop_y2 - crop_y1)
60
  center_x = fx + (fw // 2)
61
- crop_x1 = max(0, center_x - (crop_width // 2))
62
- crop_x2 = min(w, center_x + (crop_width // 2))
63
 
64
  person_crop = pil_img.crop((crop_x1, crop_y1, crop_x2, crop_y2))
65
 
66
- # 4. Expert Background Removal
 
67
  no_bg = remove(person_crop, session=session, alpha_matting=True)
68
 
69
  # 5. Create Background Layer
70
- hex_c = bg_color.lstrip('#')
71
- rgb_c = tuple(int(hex_c[i:i+2], 16) for i in (0, 2, 4))
72
- canvas = Image.new("RGBA", no_bg.size, rgb_c + (255,))
73
 
74
- # 6. Apply Suit (The Layering Trick)
75
- if suit_choice != "None":
76
  suit_img = Image.open(f"suits/{suit_choice}.png").convert("RGBA")
77
 
78
- # Scale suit to 3.2x face width
79
- target_sw = int((fw/w * no_bg.width) * 3.2)
80
  aspect = suit_img.size[1] / suit_img.size[0]
81
- suit_res = suit_img.resize((target_sw, int(target_sw * aspect)), Image.Resampling.LANCZOS)
82
 
83
- # Calculate neck position
84
- px = (canvas.width - target_sw) // 2
85
- py = int((fy - crop_y1)/person_crop.height * canvas.height + (fh/person_crop.height * canvas.height) * 0.9)
86
 
87
- # Paste suit ONTO background first
88
  canvas.paste(suit_res, (px, py), suit_res)
89
 
90
- # Paste person ONTO the canvas (covering the suit collar correctly)
91
  canvas.paste(no_bg, (0, 0), no_bg)
92
 
93
- # 7. Final High-Quality Resize & Polish
94
  final = canvas.resize((600, 600), Image.Resampling.LANCZOS)
95
 
96
- # Auto-leveling (Studio lighting effect)
97
- final = ImageEnhance.Sharpness(final).enhance(1.4)
98
- final = ImageEnhance.Contrast(final).enhance(1.1)
 
99
 
100
  return final.convert("RGB")
101
 
102
  # --- CUSTOM THEME UI ---
103
- with gr.Blocks(theme=gr.themes.Soft()) as app:
104
- gr.Markdown("# 👔 AI Studio Passport Maker")
105
- gr.Markdown("Zero-cost, High-Quality, and Unlimited.")
106
 
107
  with gr.Row():
108
  with gr.Column():
109
  img_in = gr.Image(label="1. Upload Selfie", type="numpy")
110
- suit_in = gr.Dropdown(choices=["None"] + list(SUITS.keys()), label="2. Choose Suit", value="None")
111
  bg_in = gr.ColorPicker(label="3. Background Color", value="#FFFFFF")
112
- btn = gr.Button("Generate Passport Photo", variant="primary")
113
 
114
  with gr.Column():
115
- img_out = gr.Image(label="Download Result (600x600px)")
116
 
117
  btn.click(make_passport, inputs=[img_in, suit_in, bg_in], outputs=img_out)
118
 
 
1
  import os
2
+ import sys
3
  import cv2
4
  import numpy as np
5
  import requests
6
+ from PIL import Image, ImageEnhance, ImageFilter
7
  from rembg import remove, new_session
8
  import mediapipe as mp
9
  import gradio as gr
10
 
11
  # Force MediaPipe to use its internal stable solutions
12
+ # This handles the AttributeError: module 'mediapipe' has no attribute 'solutions'
13
+ try:
14
+ import mediapipe.python.solutions.face_detection as mp_face_detection
15
+ except:
16
+ import mediapipe.solutions.face_detection as mp_face_detection
17
 
18
  # Initialize AI Models at startup
19
+ print("Step 1: Loading Pro-Grade AI Models...")
20
+ # birefnet-portrait is the industry standard for high-end cutouts
21
  session = new_session("birefnet-portrait")
22
  face_detector = mp_face_detection.FaceDetection(model_selection=1, min_detection_confidence=0.5)
23
 
24
  # Download Professional Suit Assets
25
+ print("Step 2: Downloading Suit Assets...")
26
  SUITS = {
27
  "Navy Blue Business": "https://raw.githubusercontent.com/AIGuy-Official/Passport-Assets/main/suit1.png",
28
  "Classic Black Formal": "https://raw.githubusercontent.com/AIGuy-Official/Passport-Assets/main/suit2.png"
 
30
 
31
  os.makedirs('suits', exist_ok=True)
32
  for name, url in SUITS.items():
33
+ suit_path = f"suits/{name}.png"
34
+ if not os.path.exists(suit_path):
35
  try:
36
  r = requests.get(url, timeout=10)
37
+ with open(suit_path, 'wb') as f: f.write(r.content)
38
  except: pass
39
 
40
  def make_passport(input_image, suit_choice, bg_color):
41
  if input_image is None: return None
42
 
43
+ # 1. Prepare Images
44
  pil_img = Image.fromarray(input_image).convert("RGBA")
45
  np_img = cv2.cvtColor(input_image, cv2.COLOR_RGB2BGR)
46
  h, w, _ = np_img.shape
 
50
  if not results.detections:
51
  return None
52
 
53
+ # Get Detection Box
54
  bbox = results.detections[0].location_data.relative_bounding_box
55
  fx, fy, fw, fh = int(bbox.xmin * w), int(bbox.ymin * h), int(bbox.width * w), int(bbox.height * h)
56
 
57
+ # 3. Calculated Passport Crop (Professional Rules)
58
+ # Head should take up roughly 60% of the vertical space
59
+ margin_top = int(fh * 0.5)
60
+ margin_bottom = int(fh * 1.8) # Room for suit/shoulders
61
 
62
  crop_y1 = max(0, fy - margin_top)
63
  crop_y2 = min(h, fy + fh + margin_bottom)
64
 
65
+ # Keep it 1:1 Aspect Ratio (Square)
66
+ crop_h = crop_y2 - crop_y1
67
  center_x = fx + (fw // 2)
68
+ crop_x1 = max(0, center_x - (crop_h // 2))
69
+ crop_x2 = min(w, center_x + (crop_h // 2))
70
 
71
  person_crop = pil_img.crop((crop_x1, crop_y1, crop_x2, crop_y2))
72
 
73
+ # 4. Premium Background Removal
74
+ # We remove BG from the crop for maximum speed and quality
75
  no_bg = remove(person_crop, session=session, alpha_matting=True)
76
 
77
  # 5. Create Background Layer
78
+ bg_hex = bg_color.lstrip('#')
79
+ bg_rgb = tuple(int(bg_hex[i:i+2], 16) for i in (0, 2, 4))
80
+ canvas = Image.new("RGBA", no_bg.size, bg_rgb + (255,))
81
 
82
+ # 6. Advanced Suit Layering
83
+ if suit_choice != "None" and os.path.exists(f"suits/{suit_choice}.png"):
84
  suit_img = Image.open(f"suits/{suit_choice}.png").convert("RGBA")
85
 
86
+ # Scale suit width to be 3.4x the detected face width
87
+ target_suit_w = int((fw / w * no_bg.width) * 3.4)
88
  aspect = suit_img.size[1] / suit_img.size[0]
89
+ suit_res = suit_img.resize((target_suit_w, int(target_suit_w * aspect)), Image.Resampling.LANCZOS)
90
 
91
+ # Place suit exactly under the chin
92
+ px = (canvas.width - target_suit_w) // 2
93
+ py = int((fy - crop_y1) / person_crop.height * canvas.height + (fh / person_crop.height * canvas.height) * 0.95)
94
 
95
+ # Paste suit on BG, THEN paste person on top (collars look real)
96
  canvas.paste(suit_res, (px, py), suit_res)
97
 
98
+ # Layer the person over the suit
99
  canvas.paste(no_bg, (0, 0), no_bg)
100
 
101
+ # 7. Final Polish (DSLR Quality)
102
  final = canvas.resize((600, 600), Image.Resampling.LANCZOS)
103
 
104
+ # Enhance sharpness and contrast for a "studio" look
105
+ final = ImageEnhance.Sharpness(final).enhance(1.5)
106
+ final = ImageEnhance.Contrast(final).enhance(1.15)
107
+ final = ImageEnhance.Brightness(final).enhance(1.05)
108
 
109
  return final.convert("RGB")
110
 
111
  # --- CUSTOM THEME UI ---
112
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue")) as app:
113
+ gr.Markdown("# 👔 AI Passport Photo Studio (Expert Version)")
114
+ gr.Markdown("High-quality, Auto-Crop, and Suit Alignment. Unlimited usage.")
115
 
116
  with gr.Row():
117
  with gr.Column():
118
  img_in = gr.Image(label="1. Upload Selfie", type="numpy")
119
+ suit_in = gr.Dropdown(choices=["None"] + list(SUITS.keys()), label="2. Select Suit", value="None")
120
  bg_in = gr.ColorPicker(label="3. Background Color", value="#FFFFFF")
121
+ btn = gr.Button("Generate Professional Passport", variant="primary")
122
 
123
  with gr.Column():
124
+ img_out = gr.Image(label="Result (600x600px Print Ready)")
125
 
126
  btn.click(make_passport, inputs=[img_in, suit_in, bg_in], outputs=img_out)
127