crack-detection / app.py
calcent's picture
Deploy crack detection app
cd0d068 verified
Raw
History Blame Contribute Delete
2.87 kB
"""Flask web app for crack detection and measurement."""
from __future__ import annotations
import base64
import io
import os
import cv2
import numpy as np
from flask import Flask, jsonify, render_template, request, send_file
from PIL import Image
import aruco_scale
import crack_pipeline
app = Flask(__name__)
app.config["MAX_CONTENT_LENGTH"] = 25 * 1024 * 1024 # 25 MB upload cap
def _read_image(file_storage) -> np.ndarray:
"""Decode an uploaded file into an RGB numpy array."""
image = Image.open(io.BytesIO(file_storage.read())).convert("RGB")
return np.array(image)
def _encode_png(image_rgb: np.ndarray) -> str:
"""Encode an RGB array as a base64 PNG data URI."""
bgr = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)
ok, buf = cv2.imencode(".png", bgr)
if not ok:
raise RuntimeError("PNG encoding failed")
return "data:image/png;base64," + base64.b64encode(buf).decode("ascii")
@app.route("/")
def index():
return render_template("index.html")
@app.route("/health")
def health():
return jsonify(status="ok")
@app.route("/marker")
def marker():
"""Serve the printable ArUco marker PDF (generated by make_marker.py)."""
size = int(aruco_scale.DEFAULT_MARKER_LENGTH_MM)
pdf = os.path.join(os.path.dirname(__file__), f"aruco_marker_{size}mm_A4.pdf")
if not os.path.exists(pdf):
return jsonify(error="Marker PDF missing - run: python make_marker.py"), 404
return send_file(pdf, mimetype="application/pdf")
@app.route("/analyze", methods=["POST"])
def analyze():
"""Analyse an upload and return only the computer-vision result.
Scale always comes from the ArUco marker (no manual options); the model
threshold is fixed. The response carries the CV overlay and the CV
measurement (intensity-based, refined within the ML-detected region).
"""
if "image" not in request.files or request.files["image"].filename == "":
return jsonify(error="No image uploaded"), 400
try:
image_rgb = _read_image(request.files["image"])
except Exception:
return jsonify(error="Could not read the uploaded image"), 400
result = crack_pipeline.analyze(
image_rgb, use_aruco=True,
marker_length_mm=aruco_scale.DEFAULT_MARKER_LENGTH_MM,
)
overlay = result["overlay"]
return jsonify(
overlay=_encode_png(overlay),
measurements=result["measurements"],
aruco=result["aruco"],
image_size={"width": overlay.shape[1], "height": overlay.shape[0]},
)
if __name__ == "__main__":
# Port 5000 is taken by macOS AirPlay Receiver, so default to 5001.
port = int(os.environ.get("PORT", 5001))
print("Loading crack segmentation model...")
crack_pipeline.get_model()
print(f"Model ready. Open http://127.0.0.1:{port}")
app.run(host="127.0.0.1", port=port, debug=False)