Update app.py
Browse files
app.py
CHANGED
|
@@ -14,7 +14,7 @@ app = Flask(__name__)
|
|
| 14 |
app.secret_key = 'your_secret_key' # Replace with a secure secret key
|
| 15 |
|
| 16 |
# Global dictionary to hold job progress and results
|
| 17 |
-
jobs = {} # jobs[job_id] = {"progress": int, "result": {
|
| 18 |
|
| 19 |
#########################################
|
| 20 |
# 1. Initialize the Models
|
|
@@ -75,11 +75,12 @@ def custom_nms(preds, iou_threshold=0.3):
|
|
| 75 |
filtered_preds.append(pred)
|
| 76 |
return filtered_preds
|
| 77 |
|
| 78 |
-
#
|
|
|
|
| 79 |
def process_image(job_id, image_path, object_type, multiplier):
|
| 80 |
try:
|
| 81 |
jobs[job_id]['progress'] = 10
|
| 82 |
-
# Load image
|
| 83 |
image = cv2.imread(image_path)
|
| 84 |
if image is None:
|
| 85 |
jobs[job_id]['progress'] = 100
|
|
@@ -97,18 +98,36 @@ def process_image(job_id, image_path, object_type, multiplier):
|
|
| 97 |
jobs[job_id]['progress'] = 100
|
| 98 |
jobs[job_id]['result'] = {"error": "Roboflow model not available."}
|
| 99 |
return
|
| 100 |
-
try:
|
| 101 |
-
results = box_model.predict(image_path, confidence=50, overlap=30).json()
|
| 102 |
-
predictions = results.get("predictions", [])
|
| 103 |
-
except Exception as e:
|
| 104 |
-
jobs[job_id]['progress'] = 100
|
| 105 |
-
jobs[job_id]['result'] = {"error": "Error during Roboflow prediction."}
|
| 106 |
-
return
|
| 107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
processed_preds = []
|
| 109 |
for prediction in predictions:
|
| 110 |
try:
|
| 111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
x1 = int(round(x - width / 2))
|
| 113 |
y1 = int(round(y - height / 2))
|
| 114 |
x2 = int(round(x + width / 2))
|
|
@@ -125,10 +144,11 @@ def process_image(job_id, image_path, object_type, multiplier):
|
|
| 125 |
except Exception as e:
|
| 126 |
continue
|
| 127 |
|
| 128 |
-
|
|
|
|
| 129 |
jobs[job_id]['progress'] = 60
|
| 130 |
|
| 131 |
-
# (
|
| 132 |
marker_real_width_cm = 5.0
|
| 133 |
try:
|
| 134 |
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
@@ -153,6 +173,7 @@ def process_image(job_id, image_path, object_type, multiplier):
|
|
| 153 |
except Exception as e:
|
| 154 |
conversion_factor = None
|
| 155 |
|
|
|
|
| 156 |
for pred in box_detections:
|
| 157 |
x1, y1, x2, y2 = pred["box"]
|
| 158 |
label = pred["class"]
|
|
@@ -180,6 +201,7 @@ def process_image(job_id, image_path, object_type, multiplier):
|
|
| 180 |
(text_width, text_height), baseline = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
|
| 181 |
cv2.rectangle(image, (x1, y1 - text_height - baseline - 5), (x1 + text_width, y1 - 5), (0, 255, 0), -1)
|
| 182 |
cv2.putText(image, text, (x1, y1 - 5 - baseline), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)
|
|
|
|
| 183 |
elif object_type in {"person", "car"}:
|
| 184 |
if yolov5_model is None:
|
| 185 |
jobs[job_id]['progress'] = 100
|
|
@@ -213,7 +235,7 @@ def process_image(job_id, image_path, object_type, multiplier):
|
|
| 213 |
jobs[job_id]['result'] = {"error": "Error during YOLOv5 inference."}
|
| 214 |
return
|
| 215 |
|
| 216 |
-
# Build summary text
|
| 217 |
detection_counts = Counter(det["class"] for det in detection_info)
|
| 218 |
if detection_counts:
|
| 219 |
top_text = ", ".join(f"{cls}: {count}" for cls, count in detection_counts.items())
|
|
@@ -500,7 +522,6 @@ def analyze():
|
|
| 500 |
object_type = request.form.get('object_type', '').lower()
|
| 501 |
if object_type not in {"person", "car", "box"}:
|
| 502 |
return jsonify({"error": "Invalid object type."}), 400
|
| 503 |
-
# Retrieve the multiplier sent from the client
|
| 504 |
try:
|
| 505 |
multiplier = int(request.form.get('multiplier', 1))
|
| 506 |
except ValueError:
|
|
|
|
| 14 |
app.secret_key = 'your_secret_key' # Replace with a secure secret key
|
| 15 |
|
| 16 |
# Global dictionary to hold job progress and results
|
| 17 |
+
jobs = {} # jobs[job_id] = {"progress": int, "result": {...}}
|
| 18 |
|
| 19 |
#########################################
|
| 20 |
# 1. Initialize the Models
|
|
|
|
| 75 |
filtered_preds.append(pred)
|
| 76 |
return filtered_preds
|
| 77 |
|
| 78 |
+
# The process_image function now merges the box detection code (from your first prompt)
|
| 79 |
+
# with the ArUco marker detection (and size measurement) exactly as in the code you provided now.
|
| 80 |
def process_image(job_id, image_path, object_type, multiplier):
|
| 81 |
try:
|
| 82 |
jobs[job_id]['progress'] = 10
|
| 83 |
+
# Load a fresh copy of the original image
|
| 84 |
image = cv2.imread(image_path)
|
| 85 |
if image is None:
|
| 86 |
jobs[job_id]['progress'] = 100
|
|
|
|
| 98 |
jobs[job_id]['progress'] = 100
|
| 99 |
jobs[job_id]['result'] = {"error": "Roboflow model not available."}
|
| 100 |
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
+
# --- BOX DETECTION (from your 1st prompt) ---
|
| 103 |
+
# Upscale the image if it is small to help detect small boxes.
|
| 104 |
+
scale_factor = 1
|
| 105 |
+
if img_width < 1000 or img_height < 1000:
|
| 106 |
+
scale_factor = 2
|
| 107 |
+
|
| 108 |
+
if scale_factor > 1:
|
| 109 |
+
upscaled_image = cv2.resize(image, None, fx=scale_factor, fy=scale_factor, interpolation=cv2.INTER_LINEAR)
|
| 110 |
+
temp_path = "upscaled.jpg"
|
| 111 |
+
cv2.imwrite(temp_path, upscaled_image)
|
| 112 |
+
results = box_model.predict(temp_path, confidence=30, overlap=20).json()
|
| 113 |
+
else:
|
| 114 |
+
results = box_model.predict(image_path, confidence=30, overlap=20).json()
|
| 115 |
+
|
| 116 |
+
predictions = results.get("predictions", [])
|
| 117 |
processed_preds = []
|
| 118 |
for prediction in predictions:
|
| 119 |
try:
|
| 120 |
+
if scale_factor > 1:
|
| 121 |
+
x = prediction["x"] / scale_factor
|
| 122 |
+
y = prediction["y"] / scale_factor
|
| 123 |
+
width = prediction["width"] / scale_factor
|
| 124 |
+
height = prediction["height"] / scale_factor
|
| 125 |
+
else:
|
| 126 |
+
x = prediction["x"]
|
| 127 |
+
y = prediction["y"]
|
| 128 |
+
width = prediction["width"]
|
| 129 |
+
height = prediction["height"]
|
| 130 |
+
|
| 131 |
x1 = int(round(x - width / 2))
|
| 132 |
y1 = int(round(y - height / 2))
|
| 133 |
x2 = int(round(x + width / 2))
|
|
|
|
| 144 |
except Exception as e:
|
| 145 |
continue
|
| 146 |
|
| 147 |
+
# Use a higher NMS IoU threshold to avoid merging valid nearby detections.
|
| 148 |
+
box_detections = custom_nms(processed_preds, iou_threshold=0.7)
|
| 149 |
jobs[job_id]['progress'] = 60
|
| 150 |
|
| 151 |
+
# --- ARUCO MARKER DETECTION (from the code you provided now) ---
|
| 152 |
marker_real_width_cm = 5.0
|
| 153 |
try:
|
| 154 |
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
|
|
| 173 |
except Exception as e:
|
| 174 |
conversion_factor = None
|
| 175 |
|
| 176 |
+
# --- Draw boxes and compute measurements ---
|
| 177 |
for pred in box_detections:
|
| 178 |
x1, y1, x2, y2 = pred["box"]
|
| 179 |
label = pred["class"]
|
|
|
|
| 201 |
(text_width, text_height), baseline = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
|
| 202 |
cv2.rectangle(image, (x1, y1 - text_height - baseline - 5), (x1 + text_width, y1 - 5), (0, 255, 0), -1)
|
| 203 |
cv2.putText(image, text, (x1, y1 - 5 - baseline), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)
|
| 204 |
+
|
| 205 |
elif object_type in {"person", "car"}:
|
| 206 |
if yolov5_model is None:
|
| 207 |
jobs[job_id]['progress'] = 100
|
|
|
|
| 235 |
jobs[job_id]['result'] = {"error": "Error during YOLOv5 inference."}
|
| 236 |
return
|
| 237 |
|
| 238 |
+
# Build summary text drawn on the image
|
| 239 |
detection_counts = Counter(det["class"] for det in detection_info)
|
| 240 |
if detection_counts:
|
| 241 |
top_text = ", ".join(f"{cls}: {count}" for cls, count in detection_counts.items())
|
|
|
|
| 522 |
object_type = request.form.get('object_type', '').lower()
|
| 523 |
if object_type not in {"person", "car", "box"}:
|
| 524 |
return jsonify({"error": "Invalid object type."}), 400
|
|
|
|
| 525 |
try:
|
| 526 |
multiplier = int(request.form.get('multiplier', 1))
|
| 527 |
except ValueError:
|