File size: 3,497 Bytes
e735bf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2f6f454
 
 
 
 
 
 
 
 
 
 
e735bf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3271545
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
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)