|
|
@@ -98,6 +98,21 @@ overlay_colors = {
|
|
|
}
|
|
|
|
|
|
# Helper to reset results when files change or engine switches
|
|
|
+def get_color(class_name):
|
|
|
+ """Robust color lookup for consistent across models."""
|
|
|
+ # Normalize: "Under-ripe" -> "underripe", "Empty Bunch" -> "emptybunch"
|
|
|
+ norm_name = class_name.lower().replace("-", "").replace("_", "").replace(" ", "")
|
|
|
+
|
|
|
+ # Map normalized names to your MPOB standard colors
|
|
|
+ color_map = {k.lower().replace("_", ""): v for k, v in overlay_colors.items()}
|
|
|
+
|
|
|
+ if norm_name in color_map:
|
|
|
+ return color_map[norm_name]
|
|
|
+
|
|
|
+ # Fallback: Generate a consistent unique color for benchmark-only classes
|
|
|
+ import hashlib
|
|
|
+ return f"#{hashlib.md5(class_name.encode()).hexdigest()[:6]}"
|
|
|
+
|
|
|
def reset_single_results():
|
|
|
st.session_state.last_detection = None
|
|
|
|
|
|
@@ -212,7 +227,9 @@ def display_interactive_results(image, detections, key=None):
|
|
|
x1, y1, x2, y2 = det['box']
|
|
|
# Plotly y-axis is inverted relative to PIL, so we flip y
|
|
|
y_top, y_bottom = img_height - y1, img_height - y2
|
|
|
- color = overlay_colors.get(det['class'], "#9ca3af") # Fallback to neutral gray
|
|
|
+
|
|
|
+ color = get_color(det['class'])
|
|
|
+ is_bench = (st.session_state.get('engine_choice') == "Sawit-TBS (Benchmark)")
|
|
|
|
|
|
# The 'Hover' shape
|
|
|
bunch_id = det.get('bunch_id', i+1)
|
|
|
@@ -221,9 +238,9 @@ def display_interactive_results(image, detections, key=None):
|
|
|
y=[y_top, y_top, y_bottom, y_bottom, y_top],
|
|
|
fill="toself",
|
|
|
fillcolor=color,
|
|
|
- opacity=0.3, # Semi-transparent until hover
|
|
|
+ opacity=0.5 if is_bench else 0.3, # Stronger highlight for benchmark
|
|
|
mode='lines',
|
|
|
- line=dict(color=color, width=3),
|
|
|
+ line=dict(color=color, width=5 if is_bench else 3, dash='dot' if is_bench else 'solid'),
|
|
|
name=f"ID: #{bunch_id}", # Unified ID Tag
|
|
|
text=f"<b>ID: #{bunch_id}</b><br>Grade: {det['class']}<br>Score: {det['confidence']:.2f}<br>Alert: {det['is_health_alert']}",
|
|
|
hoverinfo="text"
|
|
|
@@ -257,10 +274,11 @@ def annotate_image(image, detections):
|
|
|
cls = det['class']
|
|
|
conf = det['confidence']
|
|
|
bunch_id = det.get('bunch_id', '?')
|
|
|
- color = overlay_colors.get(cls, '#9ca3af') # Fallback to neutral gray
|
|
|
+ color = get_color(cls)
|
|
|
+ is_bench = (st.session_state.get('engine_choice') == "Sawit-TBS (Benchmark)")
|
|
|
|
|
|
# 2. Draw Heavy-Duty Bounding Box
|
|
|
- line_width = max(4, image.width // 150)
|
|
|
+ line_width = max(6 if is_bench else 4, image.width // (80 if is_bench else 150))
|
|
|
draw.rectangle(box, outline=color, width=line_width)
|
|
|
|
|
|
# 3. Draw 'Plated Label' (Background Shaded)
|
|
|
@@ -432,6 +450,9 @@ with tab1:
|
|
|
data = st.session_state.last_detection
|
|
|
st.divider()
|
|
|
|
|
|
+ if model_type == "benchmark":
|
|
|
+ st.info("💡 **Benchmark Mode**: Labels and colors are determined by the external model's architecture. Some labels may not match standard MPOB categories.")
|
|
|
+
|
|
|
st.write("### 📈 Manager's Dashboard")
|
|
|
m_col1, m_col2, m_col3, m_col4 = st.columns(4)
|
|
|
with m_col1:
|