SQLite Dog Monitoring Database Module
SQLite Dog Monitoring Database Module
# MODULE: database_manager.py
# SQLite Database Management Module
# ============================================
"""
SQLite Database Module
Handles all database operations for dog monitoring system
Provides persistent storage, querying, and reporting capabilities
"""
import sqlite3
import json
import pickle
import base64
from datetime import datetime
from typing import Dict, List, Tuple, Optional, Any
import numpy as np
from contextlib import contextmanager
import logging
from dataclasses import dataclass, asdict
[Link](level=[Link])
logger = [Link](__name__)
@dataclass
class DogRecord:
"""Dog record structure for database"""
dog_id: int
first_seen: str
last_seen: str
total_sightings: int
size_category: str
primary_fur_color: str
fur_pattern: str
average_health_score: float
average_confidence: float
signature_data: bytes # Pickled signature
thumbnail: str # Base64 image
status: str # active, lost, adopted, etc.
notes: str
class SQLiteDatabase:
"""
Comprehensive SQLite database manager for dog monitoring system
Handles all CRUD operations and complex queries
"""
Args:
db_path: Path to SQLite database file
"""
self.db_path = db_path
self._create_tables()
[Link](f"Database initialized at {db_path}")
@contextmanager
def get_connection(self):
"""Context manager for database connections"""
conn = [Link](self.db_path)
conn.row_factory = [Link] # Enable column access by name
try:
yield conn
[Link]()
except Exception as e:
[Link]()
[Link](f"Database error: {e}")
raise
finally:
[Link]()
def _create_tables(self):
"""Create all necessary database tables"""
with self.get_connection() as conn:
cursor = [Link]()
# ============================================
# DOG MANAGEMENT
# ============================================
Args:
dog_id: Unique dog identifier
signature_data: Dog signature object (will be pickled)
size_category: Size classification
fur_color: Primary fur color
thumbnail: Base64 encoded thumbnail image
Returns:
Success status
"""
try:
# Pickle signature data
signature_blob = [Link](signature_data)
except [Link]:
[Link](f"Dog {dog_id} already exists")
return False
except Exception as e:
[Link](f"Error registering dog: {e}")
return False
Args:
dog_id: Dog identifier
**kwargs: Fields to update
Returns:
Success status
"""
try:
# Build update query dynamically
valid_fields = ['last_seen', 'total_sightings', 'size_category',
'primary_fur_color', 'fur_pattern', 'average_health_score',
'average_confidence', 'thumbnail', 'status', 'notes']
updates = []
values = []
for field, value in [Link]():
if field in valid_fields:
[Link](f"{field} = ?")
[Link](value)
if not updates:
return False
# Add updated_at
[Link]("updated_at = ?")
[Link]([Link]())
[Link](dog_id)
except Exception as e:
[Link](f"Error updating dog {dog_id}: {e}")
return False
Args:
dog_id: Dog identifier
Returns:
Dog information dictionary or None
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
[Link]('SELECT * FROM dogs WHERE dog_id = ?', (dog_id,))
row = [Link]()
if row:
return dict(row)
return None
except Exception as e:
[Link](f"Error fetching dog {dog_id}: {e}")
return None
Args:
status: Filter by status (active, lost, adopted)
Returns:
List of dog dictionaries
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
if status:
[Link]('SELECT * FROM dogs WHERE status = ?', (status,))
else:
[Link]('SELECT * FROM dogs')
except Exception as e:
[Link](f"Error fetching dogs: {e}")
return []
Args:
dog_id: Dog identifier
Returns:
Unpickled signature object or None
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
[Link]('SELECT signature_data FROM dogs WHERE dog_id = ?', (dog_id,))
row = [Link]()
except Exception as e:
[Link](f"Error fetching signature for dog {dog_id}: {e}")
return None
# ============================================
# SIGHTINGS MANAGEMENT
# ============================================
Args:
dog_id: Dog identifier
video_file: Source video filename
frame_number: Frame where dog was detected
confidence: Detection confidence
bbox: Bounding box [x1, y1, x2, y2]
location: Optional location information
Returns:
Success status
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
[Link]('''
INSERT INTO sightings (
dog_id, video_file, frame_number, confidence,
bbox_x1, bbox_y1, bbox_x2, bbox_y2, location
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (dog_id, video_file, frame_number, confidence,
bbox[0], bbox[1], bbox[2], bbox[3], location))
return True
except Exception as e:
[Link](f"Error adding sighting: {e}")
return False
Args:
dog_id: Dog identifier
limit: Maximum number of sightings to return
Returns:
List of sighting records
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
[Link]('''
SELECT * FROM sightings
WHERE dog_id = ?
ORDER BY timestamp DESC
LIMIT ?
''', (dog_id, limit))
except Exception as e:
[Link](f"Error fetching sightings: {e}")
return []
# ============================================
# HEALTH MANAGEMENT
# ============================================
Args:
dog_id: Dog identifier
overall_score: Health score (0-10)
body_condition: Body condition description
activity_level: Activity level description
coat_condition: Coat condition description
alerts: List of health alerts
Returns:
Success status
"""
try:
alerts_json = [Link](alerts) if alerts else '[]'
return True
except Exception as e:
[Link](f"Error adding health assessment: {e}")
return False
Args:
dog_id: Dog identifier
limit: Maximum number of assessments to return
Returns:
List of health assessments
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
[Link]('''
SELECT * FROM health_assessments
WHERE dog_id = ?
ORDER BY timestamp DESC
LIMIT ?
''', (dog_id, limit))
results = []
for row in [Link]():
assessment = dict(row)
assessment['alerts'] = [Link]([Link]('alerts', '[]'))
[Link](assessment)
return results
except Exception as e:
[Link](f"Error fetching health history: {e}")
return []
Args:
health_threshold: Health score threshold
Returns:
List of dogs needing attention
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
[Link]('''
SELECT d.*,
(SELECT overall_score FROM health_assessments
WHERE dog_id = d.dog_id
ORDER BY timestamp DESC LIMIT 1) as latest_health_score
FROM dogs d
WHERE d.average_health_score < ?
OR EXISTS (
SELECT 1 FROM health_assessments h
WHERE h.dog_id = d.dog_id
AND h.overall_score < ?
AND [Link] > datetime('now', '-7 days')
)
ORDER BY d.average_health_score ASC
''', (health_threshold, health_threshold))
except Exception as e:
[Link](f"Error fetching dogs needing attention: {e}")
return []
# ============================================
# FEATURES MANAGEMENT (for Re-ID)
# ============================================
def add_features(self, dog_id: int, color_histogram: [Link] = None,
texture_features: [Link] = None, deep_features: [Link] = None,
size_features: Dict = None, shape_features: Dict = None) -> bool:
"""
Store feature vectors for re-identification
Args:
dog_id: Dog identifier
color_histogram: Color histogram array
texture_features: Texture feature array
deep_features: Deep learning feature array
size_features: Size feature dictionary
shape_features: Shape feature dictionary
Returns:
Success status
"""
try:
# Serialize numpy arrays
color_blob = [Link](color_histogram) if color_histogram is not None else None
texture_blob = [Link](texture_features) if texture_features is not None else None
deep_blob = [Link](deep_features) if deep_features is not None else None
return True
except Exception as e:
[Link](f"Error adding features: {e}")
return False
def get_latest_features(self, dog_id: int) -> Optional[Dict]:
"""
Get latest feature set for a dog
Args:
dog_id: Dog identifier
Returns:
Dictionary of features or None
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
[Link]('''
SELECT * FROM features
WHERE dog_id = ?
ORDER BY timestamp DESC
LIMIT 1
''', (dog_id,))
row = [Link]()
if row:
features = dict(row)
# Unpickle arrays
if features['color_histogram']:
features['color_histogram'] = [Link](features['color_histogram'])
if features['texture_features']:
features['texture_features'] = [Link](features['texture_features'])
if features['deep_features']:
features['deep_features'] = [Link](features['deep_features'])
# Parse JSON
if features['size_features']:
features['size_features'] = [Link](features['size_features'])
if features['shape_features']:
features['shape_features'] = [Link](features['shape_features'])
return features
return None
except Exception as e:
[Link](f"Error fetching features: {e}")
return None
# ============================================
# VIDEO TRACKING
# ============================================
Args:
filename: Video filename
total_frames: Total frames processed
dogs_detected: Number of dogs detected
processing_time: Processing time in seconds
quality_score: Video quality score
quality_level: Quality level description
Returns:
Success status
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
[Link]('''
INSERT INTO processed_videos (
filename, total_frames, dogs_detected,
processing_time, quality_score, quality_level
) VALUES (?, ?, ?, ?, ?, ?)
''', (filename, total_frames, dogs_detected,
processing_time, quality_score, quality_level))
return True
except Exception as e:
[Link](f"Error adding processed video: {e}")
return False
# ============================================
# STATISTICS AND REPORTING
# ============================================
stats = {}
# Total dogs
[Link]('SELECT COUNT(*) as total FROM dogs')
stats['total_dogs'] = [Link]()['total']
# Active dogs
[Link]('SELECT COUNT(*) as active FROM dogs WHERE status = "active"')
stats['active_dogs'] = [Link]()['active']
# Total sightings
[Link]('SELECT COUNT(*) as total FROM sightings')
stats['total_sightings'] = [Link]()['total']
# Videos processed
[Link]('SELECT COUNT(*) as total FROM processed_videos')
stats['videos_processed'] = [Link]()['total']
# Size distribution
[Link]('''
SELECT size_category, COUNT(*) as count
FROM dogs
GROUP BY size_category
''')
stats['size_distribution'] = {row['size_category']: row['count']
for row in [Link]()}
return stats
except Exception as e:
[Link](f"Error fetching statistics: {e}")
return {}
Args:
hours: Number of hours to look back
Returns:
List of recent activities
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
# Recent sightings
[Link]('''
SELECT s.*, d.primary_fur_color, d.size_category
FROM sightings s
JOIN dogs d ON s.dog_id = d.dog_id
WHERE [Link] > datetime('now', '-{} hours')
ORDER BY [Link] DESC
'''.format(hours))
Args:
dog_id: Dog identifier
Returns:
Complete dog data dictionary
"""
try:
data = {}
# Basic info
data['info'] = self.get_dog(dog_id)
# Sightings
data['sightings'] = self.get_dog_sightings(dog_id)
# Health history
data['health_history'] = self.get_health_history(dog_id)
# Latest features
data['features'] = self.get_latest_features(dog_id)
return data
except Exception as e:
[Link](f"Error exporting dog data: {e}")
return {}
Args:
days: Remove data older than this many days
Returns:
Success status
"""
try:
with self.get_connection() as conn:
cursor = [Link]()
except Exception as e:
[Link](f"Error cleaning up data: {e}")
return False
# ============================================
# Integration with existing modules
# ============================================
Args:
db: SQLiteDatabase instance
id_system: PermanentIDSystem instance
"""
# Load all dogs from database into ID system
dogs = db.get_all_dogs(status='active')
if signature:
# Add to ID system's in-memory database
id_system.dog_database[dog_id] = signature
# Example usage
if __name__ == "__main__":
# Create database
db = SQLiteDatabase("dog_monitoring.db")
# Get statistics
stats = db.get_statistics()
print("Database Statistics:")
for key, value in [Link]():
print(f" {key}: {value}")
# Recent activity
recent = db.get_recent_activity(hours=24)
print(f"Recent sightings (24h): {len(recent)}")l
# ============================================
# MODULE 1: dog_detector.py
# Robust Dog Detection Module
# ============================================
"""
Dog Detection Module
Handles all detection operations using YOLOv8
Provides filtering, validation, and confidence scoring
"""
import cv2
import numpy as np
import torch
from ultralytics import YOLO
from typing import List, Dict, Tuple, Optional
from dataclasses import dataclass
import logging
[Link](level=[Link])
logger = [Link](__name__)
@dataclass
class DogDetection:
"""Single dog detection with all metadata"""
bbox: List[float] # [x1, y1, x2, y2]
confidence: float
class_id: int
class_name: str
image_crop: Optional[[Link]] = None
area: float = 0.0
center: Tuple[float, float] = (0, 0)
aspect_ratio: float = 1.0
class DogDetector:
"""
Robust dog detection system using YOLOv8
Handles detection, filtering, and validation
"""
Args:
model_path: Path to YOLO model
confidence_threshold: Minimum confidence for detection
device: 'cuda' or 'cpu', auto-detect if None
"""
[Link] = device or ('cuda' if [Link].is_available() else 'cpu')
[Link](f"Initializing Dog Detector on {[Link]}")
# Load model
[Link] = YOLO(model_path)
[Link]([Link])
self.confidence_threshold = confidence_threshold
# Statistics
[Link] = {
'total_detections': 0,
'dog_detections': 0,
'false_positives': 0,
'low_confidence_filtered': 0
}
Args:
frame: Input image/frame
filter_overlapping: Remove overlapping detections
size_filter: Filter by size constraints
Returns:
List of DogDetection objects
"""
if frame is None or [Link] == 0:
[Link]("Empty frame provided")
return []
detections = []
# Extract bbox
bbox = [Link][0].cpu().numpy().tolist()
x1, y1, x2, y2 = bbox
# Calculate metadata
width = x2 - x1
height = y2 - y1
area = width * height
center = ((x1 + x2) / 2, (y1 + y2) / 2)
aspect_ratio = width / (height + 1e-6)
[Link](detection)
[Link]['dog_detections'] += 1
[Link]['total_detections'] += len(detections)
Args:
detections: List of detections
iou_threshold: IoU threshold for filtering
Returns:
Filtered list of detections
"""
if not detections:
return detections
# Sort by confidence
[Link](key=lambda x: [Link], reverse=True)
keep = []
for i, det1 in enumerate(detections):
should_keep = True
if should_keep:
[Link](det1)
def reset_statistics(self):
"""Reset statistics counters"""
[Link] = {
'total_detections': 0,
'dog_detections': 0,
'false_positives': 0,
'low_confidence_filtered': 0
}
# ============================================
# MODULE 2: permanent_id_system.py
# Permanent Dog Identification System
# ============================================
"""
Permanent ID Assignment and Re-Identification Module
Handles dog signature creation, matching, and persistent storage
"""
import cv2
import numpy as np
import pickle
import os
from datetime import datetime
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass, field
import logging
import torch
import [Link] as nn
import [Link] as F
from [Link] import KMeans
logger = [Link](__name__)
@dataclass
class DogSignature:
"""Comprehensive signature for dog identification"""
dog_id: int
timestamp: datetime
# Visual features
color_histogram: [Link]
texture_features: [Link]
size_features: Dict
shape_features: Dict
# Deep learning features
embedding: Optional[[Link]] = None
# Metadata
confidence: float = 0.0
match_history: List[float] = field(default_factory=list)
sighting_count: int = 1
first_seen: datetime = field(default_factory=[Link])
last_seen: datetime = field(default_factory=[Link])
best_image: Optional[str] = None # Base64 encoded
class SimpleCNN([Link]):
"""Lightweight CNN for feature extraction"""
def __init__(self, embedding_size: int = 128):
super().__init__()
[Link] = [Link](
nn.Conv2d(3, 32, 3, padding=1),
[Link](),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 3, padding=1),
[Link](),
nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3, padding=1),
[Link](),
nn.AdaptiveAvgPool2d((1, 1))
)
[Link] = [Link](
[Link](128, embedding_size),
[Link](),
[Link](0.2),
[Link](embedding_size, embedding_size)
)
class PermanentIDSystem:
"""
Robust permanent ID assignment and re-identification system
Combines multiple features for accurate dog matching
"""
Args:
database_path: Path to save/load dog database
similarity_threshold: Threshold for ID matching
device: 'cuda' or 'cpu'
"""
[Link] = device or ('cuda' if [Link].is_available() else 'cpu')
self.database_path = database_path
self.similarity_threshold = similarity_threshold
def load_database(self):
"""Load existing database from disk"""
if [Link](self.database_path):
try:
with open(self.database_path, 'rb') as f:
data = [Link](f)
self.dog_database = [Link]('dogs', {})
self.next_id = [Link]('next_id', 1)
self.total_dogs_seen = [Link]('total_dogs', 0)
[Link](f"Loaded database with {len(self.dog_database)} dogs")
except Exception as e:
[Link](f"Error loading database: {e}")
self._create_new_database()
else:
self._create_new_database()
def _create_new_database(self):
"""Create new empty database"""
self.dog_database = {}
self.next_id = 1
self.total_dogs_seen = 0
[Link]("Created new dog database")
def save_database(self):
"""Save database to disk for persistence"""
try:
data = {
'dogs': self.dog_database,
'next_id': self.next_id,
'total_dogs': self.total_dogs_seen
}
with open(self.database_path, 'wb') as f:
[Link](data, f)
[Link](f"Saved database with {len(self.dog_database)} dogs")
except Exception as e:
[Link](f"Error saving database: {e}")
Args:
image: Dog crop image
bbox: Bounding box coordinates
frame_shape: Original frame dimensions
Returns:
DogSignature object
"""
if image is None or [Link] == 0:
return None
# Create signature
signature = DogSignature(
dog_id=0, # Will be assigned
timestamp=[Link](),
color_histogram=color_hist,
texture_features=texture_feat,
size_features=size_feat,
shape_features=shape_feat,
embedding=embedding,
confidence=1.0
)
return signature
# Calculate histograms
hist_h = [Link]([hsv], [0], None, [18], [0, 180])
hist_s = [Link]([hsv], [1], None, [8], [0, 256])
hist_l = [Link]([lab], [0], None, [8], [0, 256])
features = []
return [Link](features)
# Categorize
if norm_area < 0.005:
category = 'tiny'
elif norm_area < 0.015:
category = 'small'
elif norm_area < 0.04:
category = 'medium'
elif norm_area < 0.1:
category = 'large'
else:
category = 'giant'
return {
'normalized_area': norm_area,
'width': width,
'height': height,
'category': category
}
return {
'aspect_ratio': aspect_ratio,
'shape_type': 'normal' if 0.7 < aspect_ratio < 1.3 else 'elongated'
}
# Extract features
with torch.no_grad():
features = self.feature_extractor(img_tensor)
return [Link]().numpy().squeeze()
Args:
signature: Dog signature to match
Returns:
(dog_id, confidence, match_type)
match_type: 'new', 'definite', 'probable', 'possible'
"""
if not self.dog_database:
# First dog
return self._register_new_dog(signature), 1.0, 'new'
# Auto-save periodically
if len(self.dog_database) % 5 == 0:
self.save_database()
# Color similarity
color_sim = 1.0 - [Link]([Link](sig1.color_histogram - sig2.color_histogram)) / 2
scores['color'] = max(0, color_sim)
# Texture similarity
texture_sim = 1.0 - [Link]([Link](sig1.texture_features - sig2.texture_features))
scores['texture'] = max(0, texture_sim)
# Size similarity
size_diff = abs(sig1.size_features['normalized_area'] -
sig2.size_features['normalized_area'])
scores['size'] = max(0, 1.0 - size_diff * 20)
# Weighted combination
total_score = sum(scores[k] * self.feature_weights.get(k, 0.25)
for k in scores)
return total_score
signature.dog_id = dog_id
signature.first_seen = [Link]()
signature.last_seen = [Link]()
self.dog_database[dog_id] = signature
sig = self.dog_database[dog_id]
return {
'dog_id': dog_id,
'first_seen': sig.first_seen,
'last_seen': sig.last_seen,
'sighting_count': sig.sighting_count,
'size_category': sig.size_features['category'],
'average_confidence': [Link](sig.match_history) if sig.match_history else 0
}
def reset_database(self):
"""Reset the database (use with caution)"""
self._create_new_database()
self.save_database()
[Link]("Database has been reset")
# ============================================
# MODULE 3: gradio_interface.py
# Gradio Web Interface Module
# ============================================
"""
Gradio Interface Module
Handles MP4 video processing and web UI
"""
import gradio as gr
import cv2
import numpy as np
import tempfile
import os
from typing import Dict, List, Tuple
import pandas as pd
from datetime import datetime
import base64
from io import BytesIO
from PIL import Image
class GradioInterface:
"""
Complete Gradio interface for dog monitoring system
Processes MP4 videos only
"""
def __init__(self):
"""Initialize all system components"""
print("Initializing Gradio Interface...")
# Initialize modules
[Link] = DogDetector()
self.id_system = PermanentIDSystem()
self.health_assessor = HealthAssessment()
self.fur_detector = FurColorDetector()
self.quality_analyzer = VideoQualityAnalyzer()
# Processing statistics
self.current_stats = {
'frames_processed': 0,
'dogs_detected': 0,
'unique_dogs': 0,
'processing_time': 0
}
# Results storage
self.dog_registry = {}
self.processing_results = []
Args:
video_path: Path to MP4 file
detection_conf: Detection confidence threshold
reid_threshold: Re-ID similarity threshold
process_every_n_frames: Process every Nth frame for speed
Returns:
Tuple of (output_video_path, html_table, statistics)
"""
if not video_path or not video_path.endswith('.mp4'):
return None, "<p>Please upload an MP4 video file</p>", "No video processed"
# Update thresholds
[Link].update_confidence_threshold(detection_conf)
self.id_system.similarity_threshold = reid_threshold
start_time = [Link]()
# Open video
cap = [Link](video_path)
if not [Link]():
return None, "<p>Error opening video file</p>", "Failed to open video"
# Process video
frame_idx = 0
progress_interval = max(1, total_frames // 20)
while True:
ret, frame = [Link]()
if not ret:
break
# Write to output
[Link](processed_frame)
# Progress update
if frame_idx % progress_interval == 0:
progress = (frame_idx / total_frames) * 100
print(f"Processing: {progress:.1f}% ({frame_idx}/{total_frames} frames)")
frame_idx += 1
self.current_stats['frames_processed'] = frame_idx
# Cleanup
[Link]()
[Link]()
# Save ID database
self.id_system.save_database()
# Generate results
html_table = self._generate_html_table()
statistics = self._generate_statistics()
# Detect dogs
detections = [Link](frame)
# Create signature
signature = self.id_system.create_signature(
detection.image_crop,
[Link],
[Link]
)
if signature:
# Assign permanent ID
dog_id, confidence, match_type = self.id_system.assign_permanent_id(signature)
# Assess health
health_metrics = self.health_assessor.assess_health(
detection.image_crop,
[Link],
dog_id,
frame_idx
)
# Update registry
if dog_id not in self.dog_registry:
self.dog_registry[dog_id] = {
'first_frame': frame_idx,
'last_frame': frame_idx,
'detections': 1,
'health_scores': [health_metrics.overall_score],
'fur_color': fur_info['description'],
'size': signature.size_features['category'],
'confidence_scores': [confidence],
'image': self._image_to_base64(detection.image_crop)
}
else:
self.dog_registry[dog_id]['last_frame'] = frame_idx
self.dog_registry[dog_id]['detections'] += 1
self.dog_registry[dog_id]['health_scores'].append(health_metrics.overall_score)
self.dog_registry[dog_id]['confidence_scores'].append(confidence)
# Draw on frame
frame = self._draw_detection(frame, detection, dog_id,
health_metrics.overall_score,
confidence)
self.current_stats['dogs_detected'] = len(detections)
self.current_stats['unique_dogs'] = len(self.id_system.dog_database)
return frame
# Draw box
[Link](frame, (x1, y1), (x2, y2), color, 2)
# Create label
label = f"Dog #{dog_id} | H:{health_score:.1f}/10 | {confidence:.0%}"
return frame
html = """
<style>
.dog-table { width: 100%; border-collapse: collapse; }
.dog-table th { background-color: #4CAF50; color: white; padding: 10px; }
.dog-table td { border: 1px solid #ddd; padding: 8px; text-align: center; }
.dog-img { width: 100px; height: 100px; object-fit: cover; border-radius: 5px; }
.health-good { color: green; font-weight: bold; }
.health-warning { color: orange; font-weight: bold; }
.health-critical { color: red; font-weight: bold; }
</style>
<table class="dog-table">
<thead>
<tr>
<th>Image</th>
<th>ID</th>
<th>Fur Color</th>
<th>Size</th>
<th>Health</th>
<th>Detections</th>
<th>Confidence</th>
<th>First Seen</th>
<th>Last Seen</th>
</tr>
</thead>
<tbody>
"""
html += f"""
<tr>
<td><img src="data:image/png;base64,{info['image']}" class="dog-img"/></td>
<td><strong>#{dog_id}</strong></td>
<td>{info['fur_color']}</td>
<td>{info['size'].title()}</td>
<td class="{health_class}">{avg_health:.1f}/10</td>
<td>{info['detections']}</td>
<td>{avg_conf:.1%}</td>
<td>Frame {info['first_frame']}</td>
<td>Frame {info['last_frame']}</td>
</tr>
"""
html += "</tbody></table>"
return html
📊
stats = f"""
Processing Statistics
━━━━━━━━━━━━━━━━━━━━━━━
Video Processing:
• Frames Processed: {self.current_stats['frames_processed']}
• Processing Time: {self.current_stats['processing_time']:.1f} seconds
• FPS: {self.current_stats['frames_processed'] / max(1,
self.current_stats['processing_time']):.1f}
Detection Results:
• Total Detections: {[Link]['total_detections']}
• False Positives Filtered: {[Link]['false_positives']}
• Low Confidence Filtered: {[Link]['low_confidence_filtered']}
Identification:
• Unique Dogs in Video: {len(self.dog_registry)}
• Total Dogs in Database: {len(self.id_system.dog_database)}
• New Dogs Registered: {self.id_system.total_dogs_seen}
Database Status:
• Database Path: {self.id_system.database_path}
• Auto-saved: ✓
• Persistence: Enabled
"""
return stats
🐕
[Link]("""
# Stray Dog Detection & Permanent ID System
### Features:
- **Permanent IDs**: Dogs keep same ID across different videos
- **Health Assessment**: 0-10 health scoring
- **Fur Color Detection**: Automatic color classification
- **Size Categorization**: Tiny to Giant
- **Persistent Database**: IDs saved across sessions
with [Link]():
with [Link]():
video_input = [Link](label="Input Video (MP4 only)")
📋 Dog Registry")
# Results section
📊 Statistics", lines=20)
dog_table = [Link](label="
statistics = [Link](label="
# Wire up functions
process_btn.click(
fn=self.process_mp4_video,
inputs=[video_input, detection_conf, reid_threshold, frame_skip],
outputs=[output_video, dog_table, statistics]
)
clear_db_btn.click(
fn=lambda: (self.id_system.reset_database(),
"Database cleared",
"<p>Database has been reset</p>"),
outputs=[statistics, dog_table]
)
📝
[Link]("""
### Instructions:
1. Upload an MP4 video file
2. Adjust settings if needed (optional)
3. Click Process Video
4. Each dog will receive a permanent ID that persists across videos
5. View results in the table below
return interface
# ============================================
# MAIN APPLICATION
# ============================================
def main():
"""Main application entry point"""
# Create interface
interface = GradioInterface()
if __name__ == "__main__":
main()
# ============================================
# FILE: [Link]
# Configuration and constants
# ============================================
import torch
# Default thresholds
DEFAULT_DETECTION_CONF = 0.4
DEFAULT_REID_SIMILARITY = 0.65
# ============================================
# FILE: health_assessment.py
# Health detection and assessment module
# ============================================
import cv2
import numpy as np
from typing import Dict, Tuple, List
from dataclasses import dataclass
@dataclass
class HealthMetrics:
"""Health assessment metrics for a dog"""
overall_score: float # 0-10 scale
body_condition: str # thin, normal, overweight
activity_level: str # low, normal, high
posture_quality: str # poor, fair, good, excellent
coat_condition: str # poor, fair, good, excellent
movement_pattern: str # normal, limping, sluggish
alerts: List[str] # Health warnings
class HealthAssessment:
"""Assess dog health from visual features"""
def __init__(self):
self.movement_history = {} # Track movement patterns
self.posture_history = {} # Track posture over time
if dog_region.size == 0:
return HealthMetrics(5.0, "unknown", "unknown", "unknown",
"unknown", "unknown", [])
# Assess different health aspects
body_score = self._assess_body_condition(dog_region, bbox)
coat_score = self._assess_coat_condition(dog_region)
posture_score = self._assess_posture(bbox)
activity_score = self._assess_activity_level(dog_id, bbox, frame_idx)
if coat_score < 4:
[Link]("Poor coat condition - possible skin issues or malnutrition")
if posture_score < 4:
[Link]("Abnormal posture - possible injury or illness")
if activity_score < 3:
[Link]("Very low activity - possible health issue")
return HealthMetrics(
overall_score=overall_score,
body_condition=body_condition,
activity_level=activity_level,
posture_quality=posture_quality,
coat_condition=coat_condition,
movement_pattern=movement_pattern,
alerts=alerts
)
# Calculate movement
if len(self.movement_history[dog_id]) < 5:
return 5.0 # Not enough data
positions = self.movement_history[dog_id]
total_movement = 0
for i in range(1, len(positions)):
dx = positions[i][1] - positions[i-1][1]
dy = positions[i][2] - positions[i-1][2]
total_movement += [Link](dx**2 + dy**2)
positions = self.movement_history[dog_id][-10:]
movement_var = [Link](movements)
if movement_var > 50:
return "limping"
return "normal"
# ============================================
# FILE: fur_detection.py
# Fur color and pattern detection module
# ============================================
import cv2
import numpy as np
from typing import Dict, List, Tuple
from [Link] import KMeans
class FurColorDetector:
"""Detect and classify dog fur colors and patterns"""
def __init__(self):
self.color_ranges = {
'black': {'lower': [Link]([0, 0, 0]), 'upper': [Link]([180, 255, 30])},
'white': {'lower': [Link]([0, 0, 200]), 'upper': [Link]([180, 30, 255])},
'brown': {'lower': [Link]([10, 50, 20]), 'upper': [Link]([20, 200, 200])},
'golden': {'lower': [Link]([20, 30, 100]), 'upper': [Link]([30, 255, 255])},
'gray': {'lower': [Link]([0, 0, 50]), 'upper': [Link]([180, 30, 200])},
'red': {'lower': [Link]([0, 50, 50]), 'upper': [Link]([10, 255, 255])}
}
# Combine results
fur_description = self._describe_fur(dominant_colors, color_percentages)
return fur_description
# K-means clustering
kmeans = KMeans(n_clusters=n_colors, random_state=42, n_init=10)
[Link](pixels)
# Sort by percentage
sorted_idx = [Link](color_percentages)[::-1]
dominant_colors = []
for idx in sorted_idx:
color = colors[idx]
percentage = color_percentages[idx]
color_name = self._classify_color(color)
dominant_colors.append((color_name, percentage, color))
return dominant_colors
color_percentages = {}
total_pixels = [Link][0] * [Link][1]
return color_percentages
# Primary color
primary_color = dominant_colors[0][0]
primary_percentage = dominant_colors[0][1]
# Determine pattern
pattern = self._determine_pattern(dominant_colors, primary_percentage)
# Build description
if secondary_color and secondary_color != primary_color:
color_description = f"{primary_color} and {secondary_color}"
else:
color_description = primary_color
return {
'primary': primary_color,
'secondary': secondary_color,
'pattern': pattern,
'description': color_description,
'percentages': {c[0]: c[1] for c in dominant_colors}
}
# ============================================
# FILE: quality_analyzer.py
# Video quality analysis and threshold suggestions
# ============================================
import cv2
import numpy as np
from typing import Dict, Tuple
class VideoQualityAnalyzer:
"""Analyze video quality and suggest optimal thresholds"""
return {
'metrics': quality_metrics,
'overall_quality': overall_quality,
'quality_level': self._get_quality_level(overall_quality),
'suggested_thresholds': suggested_thresholds
}
if noise < 5:
return 10.0
elif noise < 10:
return 7.0
elif noise < 20:
return 5.0
else:
return 3.0
if metrics['compression'] < 5:
suggestions['reid_similarity'] += 0.05
suggestions['notes'] = [Link]('notes', '') + " Higher threshold for compressed
video"
return suggestions
# ============================================
# FILE: main_app.py
# Main application with all modules integrated
# ============================================
import gradio as gr
import cv2
import numpy as np
import torch
import [Link] as nn
import [Link] as F
from ultralytics import YOLO
from collections import defaultdict, deque
from datetime import datetime
import pandas as pd
from typing import Dict, List, Tuple, Optional
import pickle
import tempfile
import os
from dataclasses import dataclass, field
import base64
from io import BytesIO
from PIL import Image
@dataclass
class Detection:
"""Single detection result"""
bbox: List[float]
confidence: float
track_id: Optional[int] = None
dog_id: Optional[int] = None
features: Optional[Dict] = None
image_crop: Optional[[Link]] = None
class DogMonitoringSystem:
"""Main system integrating all modules"""
def __init__(self):
print("Initializing Dog Monitoring System...")
# Initialize modules
self.reid_system = EnhancedDogReID(similarity_threshold=0.65)
self.health_assessor = HealthAssessment()
self.fur_detector = FurColorDetector()
self.quality_analyzer = VideoQualityAnalyzer()
[Link] = SimpleTracker()
# Statistics and registry
[Link] = {
'total_detections': 0,
'unique_dogs': 0,
'frames_processed': 0,
'false_positives_filtered': 0
}
self.dog_registry = {}
self.dog_images = {}
self.quality_metrics = None
detections = []
if len(results) > 0 and results[0].boxes is not None:
boxes = results[0].boxes
for i, box in enumerate(boxes):
# CRITICAL: Check if it's actually a dog (class 16)
class_id = int([Link][0].cpu().numpy())
return detections
# Detect dogs
detections = self.detect_dogs(frame)
[Link]['total_detections'] += len(detections)
# Update tracking
detections = [Link](detections)
# Analyze health
health_metrics = self.health_assessor.assess_health(
frame, [Link], dog_id, frame_idx
)
# Update registry
if dog_id not in self.dog_registry:
self.dog_registry[dog_id] = {
'first_seen': frame_idx,
'last_seen': frame_idx,
'total_sightings': 1,
'confidence_scores': [confidence],
'best_thumbnail': [Link],
'health_scores': [health_metrics.overall_score],
'fur_color': fur_info['description'],
'size_category': signature.size_features['size_category']
}
[Link]['unique_dogs'] = len(self.reid_system.dog_database)
else:
self.dog_registry[dog_id]['last_seen'] = frame_idx
self.dog_registry[dog_id]['total_sightings'] += 1
self.dog_registry[dog_id]['confidence_scores'].append(confidence)
self.dog_registry[dog_id]['health_scores'].append(health_metrics.overall_score)
# Update stats
[Link]['unique_dogs'] = len(self.reid_system.dog_database)
# Visualize results
viz_frame = self.visualize_detections(frame, detections)
# Prepare results
results = {
'frame_idx': frame_idx,
'num_dogs': len(detections),
'detections': detections,
'unique_dogs': [Link]['unique_dogs']
}
html = """
<style>
.dog-table { width: 100%; border-collapse: collapse; }
.dog-table th, .dog-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
.dog-table th { background-color: #4CAF50; color: white; }
.dog-table tr:nth-child(even) { background-color: #f2f2f2; }
.dog-img { width: 100px; height: 100px; object-fit: cover; border-radius: 5px; }
.health-good { color: green; font-weight: bold; }
.health-warning { color: orange; font-weight: bold; }
.health-critical { color: red; font-weight: bold; }
</style>
<table class="dog-table">
<thead>
<tr>
<th>Image</th>
<th>ID</th>
<th>Fur Color</th>
<th>Size</th>
<th>Health Score</th>
<th>Activity</th>
<th>Sightings</th>
<th>Confidence</th>
<th>Status</th>
</tr>
</thead>
<tbody>
"""
html += f"""
<tr>
<td><img src="data:image/png;base64,{thumbnail}" class="dog-img" alt="Dog
{dog_id}"/></td>
<td><strong>#{dog_id}</strong></td>
<td>{[Link]('fur_color', 'Unknown')}</td>
<td>{[Link]('size_category', 'Unknown')}</td>
<td class="{health_class}">{avg_health:.1f}/10</td>
<td>{[Link]('activity_level', 'Normal')}</td>
<td>{info['total_sightings']}</td>
<td>{avg_confidence:.1%}</td>
<td>{status}</td>
</tr>
"""
html += "</tbody></table>"
return html
# The rest of the code remains similar with Gradio interface updates to show health scores and
fur colors
if __name__ == "__main__":
# Create modular system
system = DogMonitoringSystem()
# ... rest of Gradio interface