File size: 4,514 Bytes
15d9d18 4fa21dc e8754de 4fa21dc e8754de 787312f c2a0a37 787312f c2a0a37 15d9d18 4fa21dc c2a0a37 787312f 15d9d18 787312f 15d9d18 4fa21dc 787312f 4fa21dc 787312f 4fa21dc 787312f 4fa21dc 787312f 15d9d18 4fa21dc 15d9d18 787312f c2a0a37 787312f 15d9d18 c2a0a37 4fa21dc c2a0a37 4fa21dc 787312f 15d9d18 787312f c2a0a37 4fa21dc 787312f c2a0a37 4fa21dc c2a0a37 4fa21dc 15d9d18 c2a0a37 787312f 15d9d18 4fa21dc c2a0a37 4fa21dc 15d9d18 4fa21dc 15d9d18 c2a0a37 15d9d18 c2a0a37 4fa21dc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | import os
# 🔥 HARD CPU ENFORCEMENT (BEFORE ANY IMPORTS)
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
os.environ["MEDIAPIPE_DISABLE_GPU"] = "1"
import cv2
import numpy as np
import math
from flask import Flask, request, jsonify
import mediapipe as mp
from cvzone.ClassificationModule import Classifier
# ---------------- CONFIG ----------------
MODEL_PATH = "Model_old/keras_model.h5"
LABELS_PATH = "Model_old/labels.txt"
IMG_SIZE = 300
OFFSET = 20
CONFIDENCE_THRESHOLD = 0.5
STABILITY_THRESHOLD = 3
# ---------------- APP ----------------
app = Flask(__name__)
# ---------------- MEDIAPIPE (CPU-ONLY, CLOUD SAFE) ----------------
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
static_image_mode=True, # REQUIRED for server inference
max_num_hands=1,
model_complexity=0, # CPU graph only
min_detection_confidence=0.6,
min_tracking_confidence=0.6
)
# ---------------- CLASSIFIER ----------------
classifier = Classifier(MODEL_PATH, LABELS_PATH)
with open(LABELS_PATH, "r") as f:
labels = [line.strip() for line in f.readlines()]
stable_gesture = None
stable_count = 0
# ---------------- API ----------------
@app.route("/predict", methods=["POST"])
def predict():
global stable_gesture, stable_count
if "frame" not in request.files:
return jsonify({"gesture": None, "confidence": 0})
# ---- Decode image safely ----
try:
file = request.files["frame"]
img_bytes = np.frombuffer(file.read(), np.uint8)
frame = cv2.imdecode(img_bytes, cv2.IMREAD_COLOR)
if frame is None:
return jsonify({"gesture": None, "confidence": 0})
frame = cv2.flip(frame, 1)
except Exception:
return jsonify({"gesture": None, "confidence": 0})
# ---- MediaPipe inference ----
try:
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
result = hands.process(rgb)
except Exception:
stable_gesture = None
stable_count = 0
return jsonify({"gesture": None, "confidence": 0})
if not result.multi_hand_landmarks:
stable_gesture = None
stable_count = 0
return jsonify({"gesture": None, "confidence": 0})
# ---- Bounding box from landmarks ----
h, w, _ = frame.shape
lm = result.multi_hand_landmarks[0].landmark
x_vals = [int(p.x * w) for p in lm]
y_vals = [int(p.y * h) for p in lm]
x, y = min(x_vals), min(y_vals)
bw, bh = max(x_vals) - x, max(y_vals) - y
if bw <= 0 or bh <= 0:
return jsonify({"gesture": None, "confidence": 0})
# ---- Image preprocessing ----
imgWhite = np.ones((IMG_SIZE, IMG_SIZE, 3), np.uint8) * 255
imgCrop = frame[
max(0, y - OFFSET): y + bh + OFFSET,
max(0, x - OFFSET): x + bw + OFFSET
]
if imgCrop.size == 0:
return jsonify({"gesture": None, "confidence": 0})
aspectRatio = bh / bw
try:
if aspectRatio > 1:
k = IMG_SIZE / bh
wCal = max(1, math.ceil(k * bw))
imgResize = cv2.resize(imgCrop, (wCal, IMG_SIZE))
wGap = (IMG_SIZE - wCal) // 2
imgWhite[:, wGap:wGap + wCal] = imgResize
else:
k = IMG_SIZE / bw
hCal = max(1, math.ceil(k * bh))
imgResize = cv2.resize(imgCrop, (IMG_SIZE, hCal))
hGap = (IMG_SIZE - hCal) // 2
imgWhite[hGap:hGap + hCal, :] = imgResize
except Exception:
return jsonify({"gesture": None, "confidence": 0})
# ---- Classification ----
try:
prediction, index = classifier.getPrediction(imgWhite, draw=False)
index = int(index)
if index < 0 or index >= len(labels):
return jsonify({"gesture": None, "confidence": 0})
confidence = float(prediction[index])
confidence = max(0.0, min(confidence, 1.0))
gesture = labels[index]
except Exception:
return jsonify({"gesture": None, "confidence": 0})
# ---- Stability logic ----
if gesture == stable_gesture:
stable_count += 1
else:
stable_gesture = gesture
stable_count = 1
if stable_count >= STABILITY_THRESHOLD and confidence >= CONFIDENCE_THRESHOLD:
return jsonify({
"gesture": gesture,
"confidence": confidence
})
return jsonify({"gesture": None, "confidence": 0})
# ---------------- ENTRY ----------------
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860)
|