EngSelf / verdict_logic.py
Andy0811's picture
Upload 5 files
53c1ff6 verified
"""
Verdict Logic Engine
Determines green/red verdict based on detected classes
"""
import json
from typing import List, Dict, Optional
import logging
logger = logging.getLogger(__name__)
class VerdictEngine:
"""
Engine to determine verdict (green/red) based on detected objects
"""
def __init__(
self,
green_classes: Optional[List[str]] = None,
red_classes: Optional[List[str]] = None,
rules_path: Optional[str] = None
):
"""
Initialize verdict engine
Args:
green_classes: List of class names that trigger green verdict
red_classes: List of class names that trigger red verdict
rules_path: Optional path to JSON file with custom rules
"""
self.green_classes = green_classes or []
self.red_classes = red_classes or []
self.custom_rules = {}
# Load custom rules if provided
if rules_path:
try:
self.load_rules(rules_path)
except FileNotFoundError:
logger.warning(f"Rules file not found: {rules_path}")
# Default configuration if no rules specified
if not self.green_classes and not self.red_classes and not self.custom_rules:
logger.info("No verdict rules specified. Using default configuration.")
self._setup_default_rules()
def _setup_default_rules(self):
"""
Setup default verdict rules
Customize this based on your specific use case
"""
# Example default rules:
# - If all 3 classes detected: GREEN
# - If only specific classes detected: RED
# - If no classes detected: RED
self.custom_rules = {
"all_classes_required": False, # Set to True if all 3 classes must be present for GREEN
"min_detections_for_green": 1, # Minimum detections needed for GREEN
"min_confidence_for_green": 0.5, # Minimum confidence for GREEN verdict
"priority": "red" # If both green and red classes detected, which takes priority
}
logger.info("Default verdict rules configured")
def load_rules(self, rules_path: str):
"""Load verdict rules from JSON file"""
with open(rules_path, 'r') as f:
rules = json.load(f)
self.green_classes = rules.get("green_classes", self.green_classes)
self.red_classes = rules.get("red_classes", self.red_classes)
self.custom_rules = rules.get("custom_rules", self.custom_rules)
logger.info(f"Loaded rules from {rules_path}")
logger.info(f"Green classes: {self.green_classes}")
logger.info(f"Red classes: {self.red_classes}")
def get_verdict(self, detections: List[Dict]) -> Dict:
"""
Determine verdict based on detections
New Logic:
- GREEN: All 3 labels present (jio jersey, jio logo, person) AND exactly 1 person
- RED: Any condition not met
Args:
detections: List of detection dictionaries from YOLO
Returns:
Dictionary with verdict, confidence, and message
"""
if len(detections) == 0:
return {
"verdict": "red",
"confidence": 1.0,
"message": "Image rejected. No objects detected in the image. Please ensure the image contains: Jio jersey, Jio logo, and exactly one person."
}
# Extract detected class names and confidences
detected_classes = [det["class_name"] for det in detections]
confidences = [det["confidence"] for det in detections]
avg_confidence = sum(confidences) / len(confidences)
# Check which required labels are present
unique_classes = set(detected_classes)
# Count number of persons detected
person_count = detected_classes.count("person")
# Check conditions
has_jio_jersey = "jio jersey" in unique_classes
has_jio_logo = "jio logo" in unique_classes
has_person = "person" in unique_classes
has_exactly_one_person = person_count == 1
# All conditions must be satisfied for GREEN
all_labels_present = has_jio_jersey and has_jio_logo and has_person
all_conditions_met = all_labels_present and has_exactly_one_person
logger.info(f"Detected classes: {detected_classes}")
logger.info(f"Unique classes: {unique_classes}")
logger.info(f"Person count: {person_count}")
logger.info(f"All conditions met: {all_conditions_met}")
# Build user-friendly message
if all_conditions_met:
message = "Image approved! All requirements met: Jio jersey found, Jio logo found, and exactly one person detected."
verdict = "green"
else:
# Build detailed explanation of what's missing or wrong
issues = []
if not has_jio_jersey:
issues.append("Jio jersey not detected")
if not has_jio_logo:
issues.append("Jio logo not detected")
if not has_person:
issues.append("No person detected")
elif person_count == 0:
issues.append("No person detected")
elif person_count > 1:
issues.append(f"Multiple people detected ({person_count} found, need exactly 1)")
# Build the message
if issues:
message = f"Image rejected. {'. '.join(issues)}. Requirements: Jio jersey, Jio logo, and exactly one person must be present."
else:
message = "Image rejected. Please ensure all requirements are met: Jio jersey, Jio logo, and exactly one person."
verdict = "red"
return {
"verdict": verdict,
"confidence": avg_confidence,
"message": message
}
def _apply_verdict_logic(
self,
detected_classes: List[str],
unique_classes: set,
num_unique_classes: int,
max_confidence: float,
avg_confidence: float,
num_detections: int
) -> tuple:
"""
Apply verdict logic based on detected classes
Returns:
Tuple of (verdict, message)
"""
# Strategy 1: Check if specific green/red classes are defined
if self.green_classes or self.red_classes:
return self._apply_class_based_logic(
detected_classes, unique_classes, avg_confidence
)
# Strategy 2: Use custom rules
if self.custom_rules:
return self._apply_custom_rules(
num_unique_classes, num_detections, avg_confidence
)
# Strategy 3: Default logic (customize based on your needs)
return self._apply_default_logic(
num_unique_classes, num_detections, avg_confidence
)
def _apply_class_based_logic(
self,
detected_classes: List[str],
unique_classes: set,
avg_confidence: float
) -> tuple:
"""Apply logic based on specific green/red class lists"""
# Check for red classes first (if priority is red)
priority = self.custom_rules.get("priority", "red")
if priority == "red" and self.red_classes:
red_detected = any(cls in self.red_classes for cls in detected_classes)
if red_detected:
return (
"red",
f"Detected prohibited object(s): {', '.join(unique_classes & set(self.red_classes))}"
)
# Check for green classes
if self.green_classes:
green_detected = any(cls in self.green_classes for cls in detected_classes)
if green_detected:
return (
"green",
f"Detected approved object(s): {', '.join(unique_classes & set(self.green_classes))}"
)
# Check for red classes (if priority is green)
if priority == "green" and self.red_classes:
red_detected = any(cls in self.red_classes for cls in detected_classes)
if red_detected:
return (
"red",
f"Detected prohibited object(s): {', '.join(unique_classes & set(self.red_classes))}"
)
# Default to red if no matching classes
return (
"red",
f"Detected objects do not match approved criteria: {', '.join(unique_classes)}"
)
def _apply_custom_rules(
self,
num_unique_classes: int,
num_detections: int,
avg_confidence: float
) -> tuple:
"""Apply custom rules from configuration"""
all_classes_required = self.custom_rules.get("all_classes_required", False)
min_detections = self.custom_rules.get("min_detections_for_green", 1)
min_confidence = self.custom_rules.get("min_confidence_for_green", 0.5)
# Check if all 3 classes are required
if all_classes_required:
if num_unique_classes == 3:
if avg_confidence >= min_confidence:
return (
"green",
f"All required classes detected with confidence {avg_confidence:.2%}"
)
else:
return (
"red",
f"All classes detected but confidence too low: {avg_confidence:.2%}"
)
else:
return (
"red",
f"Only {num_unique_classes}/3 required classes detected"
)
# Check minimum detections
if num_detections >= min_detections and avg_confidence >= min_confidence:
return (
"green",
f"Detected {num_detections} object(s) with confidence {avg_confidence:.2%}"
)
return (
"red",
f"Insufficient detections ({num_detections}) or confidence ({avg_confidence:.2%})"
)
def _apply_default_logic(
self,
num_unique_classes: int,
num_detections: int,
avg_confidence: float
) -> tuple:
"""
Apply default verdict logic
Default strategy:
- GREEN: If at least 1 class detected with good confidence
- RED: If no detections or low confidence
Customize this method based on your specific requirements
"""
# Example 1: Simple presence-based logic
if num_detections >= 1 and avg_confidence >= 0.5:
return (
"green",
f"Detected {num_detections} object(s) across {num_unique_classes} class(es)"
)
# Example 2: All classes must be present
# if num_unique_classes == 3 and avg_confidence >= 0.6:
# return ("green", "All 3 classes detected with high confidence")
# Example 3: Specific number of detections
# if num_detections >= 2 and avg_confidence >= 0.5:
# return ("green", f"Multiple objects detected ({num_detections})")
return (
"red",
f"Criteria not met: {num_detections} detection(s), {num_unique_classes} class(es)"
)
def set_green_classes(self, classes: List[str]):
"""Set classes that trigger green verdict"""
self.green_classes = classes
logger.info(f"Green classes set to: {classes}")
def set_red_classes(self, classes: List[str]):
"""Set classes that trigger red verdict"""
self.red_classes = classes
logger.info(f"Red classes set to: {classes}")
def update_rules(self, rules: Dict):
"""Update custom rules"""
self.custom_rules.update(rules)
logger.info(f"Custom rules updated: {self.custom_rules}")