sol9x-sagar's picture
route
2f6f454
from flask import Flask, request, jsonify
import numpy as np
import cv2
# import your existing code
from main import FingerQualityAssessor # or wherever the class lives
from quality_analyzer import QualityConfig
app = Flask(__name__)
# Create once (so model/config not recreated per request)
CONFIG = QualityConfig(
target_width=640,
blur_min=60.0,
illum_min=50.0,
illum_max=200.0,
coverage_min=0.10,
orientation_max_deviation=45.0,
vertical_expected=True,
overall_quality_threshold=0.70,
)
ASSESSOR = FingerQualityAssessor(CONFIG)
def _decode_uploaded_image(file_storage):
# file_storage is a Werkzeug FileStorage from request.files
data = file_storage.read()
if not data:
raise ValueError("Empty file")
nparr = np.frombuffer(data, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) # BGR image
if img is None:
raise ValueError("Could not decode image (invalid/unsupported format)")
return img
@app.get("/")
def root():
return jsonify({
"status": "ok",
"message": "Finger Quality API is running",
"endpoints": ["/api/v1/finger-quality"]
}), 200
@app.get("/health")
def health():
return "OK", 200
@app.post("/api/v1/finger-quality")
def finger_quality():
"""
Expects: multipart/form-data with file field name 'image'
Returns: JSON with result + feedback
"""
if "image" not in request.files:
return jsonify({"error": "Missing file field 'image'"}), 400 # jsonify returns application/json response [web:7]
try:
bgr = _decode_uploaded_image(request.files["image"])
result, feedback, _debug = ASSESSOR.assess(bgr, draw_debug=False)
# Build JSON-safe dict (do not return numpy types/tuples blindly)
payload = {
"result": {
"blur_score": float(result.blur_score),
"illumination_score": float(result.illumination_score),
"coverage_ratio": float(result.coverage_ratio),
"orientation_angle_deg": float(result.orientation_angle_deg),
"blur_pass": bool(result.blur_pass),
"illumination_pass": bool(result.illumination_pass),
"coverage_pass": bool(result.coverage_pass),
"orientation_pass": bool(result.orientation_pass),
"quality_score": float(result.quality_score),
"overall_pass": bool(result.overall_pass),
"bbox": list(result.bbox) if result.bbox is not None else None,
"contour_area": float(result.contour_area),
},
"feedback": {
"is_acceptable": bool(feedback.is_acceptable),
"messages": [
{
"severity": m.severity,
"category": m.category,
"message": m.message,
}
for m in (feedback.messages or [])
],
},
}
return jsonify(payload), 200 # jsonify formats JSON response conveniently [web:7]
except ValueError as e:
return jsonify({"error": str(e)}), 400 # jsonify is fine for structured errors [web:7]
except Exception as e:
# avoid leaking internals in production; log e server-side
return jsonify({"error": "Internal server error"}), 500 # jsonify response [web:7]
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860)