maham234 commited on
Commit
29d7659
Β·
verified Β·
1 Parent(s): 4a20880

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -49
app.py CHANGED
@@ -1,116 +1,116 @@
1
  from flask import Flask, request, jsonify
2
  from flask_cors import CORS
3
- import cv2
4
- import mediapipe as mp
5
- import numpy as np
6
- from PIL import Image
7
- import base64
8
- import io
9
  import traceback
 
 
10
 
11
- # Initialize Flask
12
  app = Flask(__name__)
13
- CORS(app) # Allow cross-origin requests (for Flutter or frontend)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- print("βœ… Flask app starting...")
 
16
 
17
- try:
18
- # Initialize MediaPipe Pose
19
- mp_pose = mp.solutions.pose
20
- pose = mp_pose.Pose(static_image_mode=False, min_detection_confidence=0.5)
21
- mp_drawing = mp.solutions.drawing_utils
22
- print("βœ… MediaPipe initialized successfully")
23
- except Exception as e:
24
- print("❌ Error initializing MediaPipe:", e)
25
- traceback.print_exc()
26
 
27
- # ---------- Helper function ----------
28
  def overlay_dress(frame, dress, landmarks):
29
- """Overlay a dress image on the user's frame based on pose landmarks."""
30
  if landmarks is not None:
31
  h, w, _ = frame.shape
32
 
33
- def to_pixel(lm):
34
- return int(lm.x * w), int(lm.y * h)
35
 
36
  left_shoulder = to_pixel(landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value])
37
  right_shoulder = to_pixel(landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value])
38
  left_hip = to_pixel(landmarks[mp_pose.PoseLandmark.LEFT_HIP.value])
39
  right_hip = to_pixel(landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value])
40
 
41
- # Estimate size and position of the dress
42
  dress_width = int(np.linalg.norm(np.array(left_shoulder) - np.array(right_shoulder)) * 1.8)
43
- top_shoulder_y = min(left_shoulder[1], right_shoulder[1])
44
- bottom_hip_y = max(left_hip[1], right_hip[1])
45
- dress_height = int((bottom_hip_y - top_shoulder_y) * 1.2)
46
 
47
  center_x = (left_shoulder[0] + right_shoulder[0]) // 2
48
  x1 = max(center_x - dress_width // 2, 0)
49
- y1 = max(top_shoulder_y - 30, 0)
50
  x2 = min(x1 + dress_width, w)
51
  y2 = min(y1 + dress_height, h)
52
 
53
- # Resize and overlay
54
  dress_resized = cv2.resize(dress, (x2 - x1, y2 - y1), interpolation=cv2.INTER_AREA)
55
- if dress_resized.shape[2] == 4: # if dress has alpha channel
56
  alpha_s = dress_resized[:, :, 3] / 255.0
57
  alpha_l = 1.0 - alpha_s
58
  for c in range(3):
59
  frame[y1:y2, x1:x2, c] = (
60
  alpha_s * dress_resized[:, :, c] + alpha_l * frame[y1:y2, x1:x2, c]
61
  )
62
-
63
  return frame
64
 
65
 
66
- # ---------- Routes ----------
67
- @app.route("/", methods=["GET"])
68
- def home():
69
- return "<h1>βœ… Flask Virtual Try-On API is Running!</h1>"
70
-
71
-
72
  @app.route("/tryon", methods=["POST"])
73
  def tryon():
74
  try:
75
- data = request.json.get("image") # User webcam image in base64
76
- dress_data = request.json.get("dress") # Dress image in base64
 
 
 
 
77
 
78
  if not data or not dress_data:
79
  return jsonify({"error": "Missing image or dress data"}), 400
80
 
81
- # Decode user image
82
  img_bytes = base64.b64decode(data.split(",")[1])
83
  img = Image.open(io.BytesIO(img_bytes)).convert("RGB")
84
  frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
85
 
86
- # Decode dress image
87
  dress_bytes = base64.b64decode(dress_data.split(",")[1])
88
  dress_img = cv2.imdecode(np.frombuffer(dress_bytes, np.uint8), cv2.IMREAD_UNCHANGED)
89
 
90
- # Pose detection
91
  results = pose.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
92
  landmarks = results.pose_landmarks.landmark if results.pose_landmarks else None
93
 
94
- # Overlay dress
95
  frame = overlay_dress(frame, dress_img, landmarks)
96
-
97
- # Draw pose landmarks (optional for debugging)
98
  if results.pose_landmarks:
99
  mp_drawing.draw_landmarks(frame, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
100
 
101
- # Encode output to base64
102
  _, buffer = cv2.imencode(".jpg", frame)
103
  img_base64 = "data:image/jpeg;base64," + base64.b64encode(buffer).decode()
104
 
105
  return jsonify({"image": img_base64})
106
-
107
  except Exception as e:
108
- print("❌ Error during /tryon:", e)
109
  traceback.print_exc()
110
  return jsonify({"error": str(e)}), 500
111
 
112
 
113
- # ---------- Local Debug Mode ----------
114
  if __name__ == "__main__":
115
- # Only for local testing (Gunicorn will handle production)
116
  app.run(debug=True, host="0.0.0.0", port=5000)
 
1
  from flask import Flask, request, jsonify
2
  from flask_cors import CORS
3
+ import threading
4
+ import time
 
 
 
 
5
  import traceback
6
+ import cv2, mediapipe as mp, numpy as np, base64, io
7
+ from PIL import Image
8
 
 
9
  app = Flask(__name__)
10
+ CORS(app)
11
+
12
+ pose = None
13
+ mp_drawing = None
14
+ mp_pose = mp.solutions.pose
15
+
16
+ print("πŸš€ Flask app starting...")
17
+
18
+ @app.route("/", methods=["GET"])
19
+ def home():
20
+ return "<h1>βœ… Virtual Try-On API is Running (Health OK)</h1>", 200
21
+
22
+ @app.route("/health", methods=["GET"])
23
+ def health():
24
+ return jsonify({"status": "ok"}), 200
25
+
26
+
27
+ def init_mediapipe():
28
+ """Load MediaPipe Pose in a background thread."""
29
+ global pose, mp_drawing
30
+ try:
31
+ print("🧠 Initializing MediaPipe Pose (CPU)...")
32
+ start = time.time()
33
+ pose = mp_pose.Pose(static_image_mode=False, min_detection_confidence=0.5)
34
+ mp_drawing = mp.solutions.drawing_utils
35
+ print("βœ… MediaPipe initialized in", round(time.time() - start, 2), "seconds")
36
+ except Exception as e:
37
+ print("❌ MediaPipe init error:", e)
38
+ traceback.print_exc()
39
+
40
 
41
+ # Start loading MediaPipe asynchronously
42
+ threading.Thread(target=init_mediapipe, daemon=True).start()
43
 
 
 
 
 
 
 
 
 
 
44
 
 
45
  def overlay_dress(frame, dress, landmarks):
 
46
  if landmarks is not None:
47
  h, w, _ = frame.shape
48
 
49
+ def to_pixel(lm): return int(lm.x * w), int(lm.y * h)
 
50
 
51
  left_shoulder = to_pixel(landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value])
52
  right_shoulder = to_pixel(landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value])
53
  left_hip = to_pixel(landmarks[mp_pose.PoseLandmark.LEFT_HIP.value])
54
  right_hip = to_pixel(landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value])
55
 
 
56
  dress_width = int(np.linalg.norm(np.array(left_shoulder) - np.array(right_shoulder)) * 1.8)
57
+ top_y = min(left_shoulder[1], right_shoulder[1])
58
+ bottom_y = max(left_hip[1], right_hip[1])
59
+ dress_height = int((bottom_y - top_y) * 1.2)
60
 
61
  center_x = (left_shoulder[0] + right_shoulder[0]) // 2
62
  x1 = max(center_x - dress_width // 2, 0)
63
+ y1 = max(top_y - 30, 0)
64
  x2 = min(x1 + dress_width, w)
65
  y2 = min(y1 + dress_height, h)
66
 
 
67
  dress_resized = cv2.resize(dress, (x2 - x1, y2 - y1), interpolation=cv2.INTER_AREA)
68
+ if dress_resized.shape[2] == 4:
69
  alpha_s = dress_resized[:, :, 3] / 255.0
70
  alpha_l = 1.0 - alpha_s
71
  for c in range(3):
72
  frame[y1:y2, x1:x2, c] = (
73
  alpha_s * dress_resized[:, :, c] + alpha_l * frame[y1:y2, x1:x2, c]
74
  )
 
75
  return frame
76
 
77
 
 
 
 
 
 
 
78
  @app.route("/tryon", methods=["POST"])
79
  def tryon():
80
  try:
81
+ global pose
82
+ if pose is None:
83
+ return jsonify({"error": "Model still loading, please retry in 1–2 minutes"}), 503
84
+
85
+ data = request.json.get("image")
86
+ dress_data = request.json.get("dress")
87
 
88
  if not data or not dress_data:
89
  return jsonify({"error": "Missing image or dress data"}), 400
90
 
 
91
  img_bytes = base64.b64decode(data.split(",")[1])
92
  img = Image.open(io.BytesIO(img_bytes)).convert("RGB")
93
  frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
94
 
 
95
  dress_bytes = base64.b64decode(dress_data.split(",")[1])
96
  dress_img = cv2.imdecode(np.frombuffer(dress_bytes, np.uint8), cv2.IMREAD_UNCHANGED)
97
 
 
98
  results = pose.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
99
  landmarks = results.pose_landmarks.landmark if results.pose_landmarks else None
100
 
 
101
  frame = overlay_dress(frame, dress_img, landmarks)
 
 
102
  if results.pose_landmarks:
103
  mp_drawing.draw_landmarks(frame, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
104
 
 
105
  _, buffer = cv2.imencode(".jpg", frame)
106
  img_base64 = "data:image/jpeg;base64," + base64.b64encode(buffer).decode()
107
 
108
  return jsonify({"image": img_base64})
 
109
  except Exception as e:
110
+ print("❌ /tryon error:", e)
111
  traceback.print_exc()
112
  return jsonify({"error": str(e)}), 500
113
 
114
 
 
115
  if __name__ == "__main__":
 
116
  app.run(debug=True, host="0.0.0.0", port=5000)