Muhammed Sezer
commited on
Commit
·
34d2ee5
1
Parent(s):
c1d380f
first try
Browse files- .kiro/specs/yolov8-gradio-app/design.md +176 -0
- .kiro/specs/yolov8-gradio-app/requirements.md +77 -0
- .kiro/specs/yolov8-gradio-app/tasks.md +36 -0
- __pycache__/app.cpython-313.pyc +0 -0
- annotated_result.jpg +0 -0
- app.py +310 -0
- requirements.txt +6 -0
- test_detection.py +72 -0
- test_error_handling.py +75 -0
- test_gradio_interface.py +0 -0
- test_image.jpg +0 -0
- yolov8n.pt +3 -0
.kiro/specs/yolov8-gradio-app/design.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Design Document
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
The YOLOv8 Gradio Object Detection application is a web-based tool that provides real-time object detection capabilities through an intuitive user interface. The system leverages the Ultralytics YOLOv8 model for state-of-the-art object detection and Gradio for creating an interactive web interface. The application follows a simple pipeline: image upload → detection processing → dual output (annotated image + structured data table).
|
| 6 |
+
|
| 7 |
+
## Architecture
|
| 8 |
+
|
| 9 |
+
The application follows a single-file architecture with clear separation of concerns:
|
| 10 |
+
|
| 11 |
+
```
|
| 12 |
+
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
| 13 |
+
│ Gradio UI │───▶│ Detection Core │───▶│ Output Layer │
|
| 14 |
+
│ │ │ │ │ │
|
| 15 |
+
│ - Image Upload │ │ - YOLOv8 Model │ │ - Annotated Img │
|
| 16 |
+
│ - File Handling │ │ - Preprocessing │ │ - Data Table │
|
| 17 |
+
│ - Display │ │ - Postprocessing │ │ - Error Display │
|
| 18 |
+
└─────────────────┘ └──────────────────┘ └─────────────────┘
|
| 19 |
+
```
|
| 20 |
+
|
| 21 |
+
### Key Design Decisions
|
| 22 |
+
|
| 23 |
+
1. **Single-file Architecture**: Keeps the application simple and self-contained for easy deployment
|
| 24 |
+
2. **Pretrained Model**: Uses YOLOv8n for balance between speed and accuracy
|
| 25 |
+
3. **Dual Output**: Provides both visual and structured data outputs to serve different user needs
|
| 26 |
+
4. **PIL/NumPy Integration**: Ensures compatibility between Gradio, OpenCV, and YOLOv8 image formats
|
| 27 |
+
|
| 28 |
+
## Components and Interfaces
|
| 29 |
+
|
| 30 |
+
### 1. Model Management Component
|
| 31 |
+
|
| 32 |
+
**Purpose**: Handle YOLOv8 model loading and initialization
|
| 33 |
+
|
| 34 |
+
```python
|
| 35 |
+
# Interface
|
| 36 |
+
model = YOLO("yolov8n.pt") # Global model instance
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
**Responsibilities**:
|
| 40 |
+
- Load pretrained YOLOv8 model on application startup
|
| 41 |
+
- Handle model loading errors and fallbacks
|
| 42 |
+
- Provide access to model class names mapping
|
| 43 |
+
|
| 44 |
+
### 2. Image Processing Component
|
| 45 |
+
|
| 46 |
+
**Purpose**: Handle image format conversions and preprocessing
|
| 47 |
+
|
| 48 |
+
```python
|
| 49 |
+
# Interface
|
| 50 |
+
def preprocess_image(image: Image.Image) -> np.ndarray
|
| 51 |
+
def postprocess_results(results, original_image) -> tuple
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
**Responsibilities**:
|
| 55 |
+
- Convert PIL Image to NumPy array for YOLOv8 processing
|
| 56 |
+
- Handle image format validation
|
| 57 |
+
- Maintain image aspect ratios during processing
|
| 58 |
+
|
| 59 |
+
### 3. Detection Engine Component
|
| 60 |
+
|
| 61 |
+
**Purpose**: Core object detection logic
|
| 62 |
+
|
| 63 |
+
```python
|
| 64 |
+
# Interface
|
| 65 |
+
def detect_objects(image: Image.Image) -> tuple[Image.Image, pd.DataFrame]
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
**Responsibilities**:
|
| 69 |
+
- Execute YOLOv8 inference on input images
|
| 70 |
+
- Parse detection results (boxes, classes, confidence scores)
|
| 71 |
+
- Generate annotated output images
|
| 72 |
+
- Create structured data output
|
| 73 |
+
|
| 74 |
+
### 4. Gradio Interface Component
|
| 75 |
+
|
| 76 |
+
**Purpose**: Web UI creation and event handling
|
| 77 |
+
|
| 78 |
+
```python
|
| 79 |
+
# Interface
|
| 80 |
+
demo = gr.Interface(
|
| 81 |
+
fn=detect_objects,
|
| 82 |
+
inputs=gr.Image(type="pil", label="Upload Image"),
|
| 83 |
+
outputs=[gr.Image(type="pil"), gr.Dataframe()]
|
| 84 |
+
)
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
**Responsibilities**:
|
| 88 |
+
- Create responsive web interface
|
| 89 |
+
- Handle file uploads and validation
|
| 90 |
+
- Display results in appropriate formats
|
| 91 |
+
- Manage user interactions
|
| 92 |
+
|
| 93 |
+
## Data Models
|
| 94 |
+
|
| 95 |
+
### Detection Result Model
|
| 96 |
+
|
| 97 |
+
```python
|
| 98 |
+
{
|
| 99 |
+
"class": str, # Object class name (e.g., "person", "car")
|
| 100 |
+
"confidence": float, # Confidence score (0.0-1.0, rounded to 3 decimals)
|
| 101 |
+
"x1": float, # Top-left x coordinate (rounded to 1 decimal)
|
| 102 |
+
"y1": float, # Top-left y coordinate (rounded to 1 decimal)
|
| 103 |
+
"x2": float, # Bottom-right x coordinate (rounded to 1 decimal)
|
| 104 |
+
"y2": float # Bottom-right y coordinate (rounded to 1 decimal)
|
| 105 |
+
}
|
| 106 |
+
```
|
| 107 |
+
|
| 108 |
+
### Image Processing Pipeline
|
| 109 |
+
|
| 110 |
+
```
|
| 111 |
+
Input: PIL Image → NumPy Array → YOLOv8 Processing → Results Object →
|
| 112 |
+
Output: Annotated PIL Image + Pandas DataFrame
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
## Error Handling
|
| 116 |
+
|
| 117 |
+
### Model Loading Errors
|
| 118 |
+
- **Issue**: YOLOv8 model file not found or corrupted
|
| 119 |
+
- **Handling**: Display clear error message, suggest model download
|
| 120 |
+
- **Fallback**: Graceful degradation with error display in UI
|
| 121 |
+
|
| 122 |
+
### Image Processing Errors
|
| 123 |
+
- **Issue**: Invalid image format or corrupted file
|
| 124 |
+
- **Handling**: Validate file type before processing
|
| 125 |
+
- **Fallback**: Display user-friendly error message
|
| 126 |
+
|
| 127 |
+
### Detection Processing Errors
|
| 128 |
+
- **Issue**: YOLOv8 inference failures
|
| 129 |
+
- **Handling**: Catch exceptions during model inference
|
| 130 |
+
- **Fallback**: Return empty results with error notification
|
| 131 |
+
|
| 132 |
+
### Memory Management
|
| 133 |
+
- **Issue**: Large image files causing memory issues
|
| 134 |
+
- **Handling**: Implement image size validation and resizing if needed
|
| 135 |
+
- **Fallback**: Display memory limitation warnings
|
| 136 |
+
|
| 137 |
+
## Testing Strategy
|
| 138 |
+
|
| 139 |
+
### Unit Testing
|
| 140 |
+
- **Model Loading**: Test YOLOv8 model initialization and error handling
|
| 141 |
+
- **Image Processing**: Test format conversions and preprocessing functions
|
| 142 |
+
- **Detection Logic**: Test detection result parsing and data structure creation
|
| 143 |
+
- **Data Formatting**: Test confidence score and coordinate rounding
|
| 144 |
+
|
| 145 |
+
### Integration Testing
|
| 146 |
+
- **End-to-End Pipeline**: Test complete image upload → detection → output flow
|
| 147 |
+
- **UI Components**: Test Gradio interface functionality and responsiveness
|
| 148 |
+
- **Error Scenarios**: Test various error conditions and fallback behaviors
|
| 149 |
+
|
| 150 |
+
### Performance Testing
|
| 151 |
+
- **Inference Speed**: Measure detection processing time for various image sizes
|
| 152 |
+
- **Memory Usage**: Monitor memory consumption during processing
|
| 153 |
+
- **Concurrent Users**: Test application behavior with multiple simultaneous users
|
| 154 |
+
|
| 155 |
+
### User Acceptance Testing
|
| 156 |
+
- **Image Format Support**: Test with various image formats (JPG, PNG, JPEG)
|
| 157 |
+
- **Detection Accuracy**: Validate detection results against known test images
|
| 158 |
+
- **UI Usability**: Test interface responsiveness and user experience
|
| 159 |
+
- **Output Quality**: Verify annotated images and data table accuracy
|
| 160 |
+
|
| 161 |
+
## Deployment Considerations
|
| 162 |
+
|
| 163 |
+
### Dependencies
|
| 164 |
+
- **Core**: gradio, ultralytics, opencv-python, pillow, numpy, pandas
|
| 165 |
+
- **Model**: Automatic YOLOv8n.pt download on first run
|
| 166 |
+
- **Python Version**: 3.8+ recommended for compatibility
|
| 167 |
+
|
| 168 |
+
### Performance Optimization
|
| 169 |
+
- **Model Caching**: Keep model loaded in memory to avoid reload overhead
|
| 170 |
+
- **Image Resizing**: Implement intelligent resizing for very large images
|
| 171 |
+
- **Batch Processing**: Consider batch processing for multiple images (future enhancement)
|
| 172 |
+
|
| 173 |
+
### Security
|
| 174 |
+
- **File Upload Validation**: Strict image format validation
|
| 175 |
+
- **File Size Limits**: Implement reasonable file size restrictions
|
| 176 |
+
- **Input Sanitization**: Validate all user inputs before processing
|
.kiro/specs/yolov8-gradio-app/requirements.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Requirements Document
|
| 2 |
+
|
| 3 |
+
## Introduction
|
| 4 |
+
|
| 5 |
+
This feature implements a web-based object detection application using YOLOv8 and Gradio. The application allows users to upload images and receive real-time object detection results with visual annotations and structured data output. The system leverages a pretrained YOLOv8 model to identify and classify objects in uploaded images, providing both visual feedback through bounding boxes and detailed detection information in a tabular format.
|
| 6 |
+
|
| 7 |
+
## Requirements
|
| 8 |
+
|
| 9 |
+
### Requirement 1
|
| 10 |
+
|
| 11 |
+
**User Story:** As a user, I want to upload an image to the web application, so that I can get object detection results for analysis.
|
| 12 |
+
|
| 13 |
+
#### Acceptance Criteria
|
| 14 |
+
|
| 15 |
+
1. WHEN a user accesses the web application THEN the system SHALL display an image upload interface
|
| 16 |
+
2. WHEN a user selects an image file THEN the system SHALL accept common image formats (JPG, PNG, JPEG)
|
| 17 |
+
3. WHEN an image is uploaded THEN the system SHALL process the image and display it in the interface
|
| 18 |
+
4. IF the uploaded file is not a valid image format THEN the system SHALL display an appropriate error message
|
| 19 |
+
|
| 20 |
+
### Requirement 2
|
| 21 |
+
|
| 22 |
+
**User Story:** As a user, I want the system to detect objects in my uploaded image, so that I can identify what objects are present.
|
| 23 |
+
|
| 24 |
+
#### Acceptance Criteria
|
| 25 |
+
|
| 26 |
+
1. WHEN an image is uploaded THEN the system SHALL run YOLOv8 object detection on the image
|
| 27 |
+
2. WHEN objects are detected THEN the system SHALL identify object classes using the pretrained model
|
| 28 |
+
3. WHEN detection is complete THEN the system SHALL calculate confidence scores for each detection
|
| 29 |
+
4. WHEN detection is complete THEN the system SHALL determine bounding box coordinates for each object
|
| 30 |
+
5. IF no objects are detected THEN the system SHALL return an empty results set
|
| 31 |
+
|
| 32 |
+
### Requirement 3
|
| 33 |
+
|
| 34 |
+
**User Story:** As a user, I want to see visual annotations on my image, so that I can easily identify where objects were detected.
|
| 35 |
+
|
| 36 |
+
#### Acceptance Criteria
|
| 37 |
+
|
| 38 |
+
1. WHEN objects are detected THEN the system SHALL draw bounding boxes around detected objects
|
| 39 |
+
2. WHEN bounding boxes are drawn THEN the system SHALL include class labels on each box
|
| 40 |
+
3. WHEN bounding boxes are drawn THEN the system SHALL include confidence scores on each box
|
| 41 |
+
4. WHEN annotations are complete THEN the system SHALL display the annotated image to the user
|
| 42 |
+
5. WHEN displaying results THEN the system SHALL maintain the original image aspect ratio
|
| 43 |
+
|
| 44 |
+
### Requirement 4
|
| 45 |
+
|
| 46 |
+
**User Story:** As a user, I want to see detection results in a structured table format, so that I can analyze the data programmatically.
|
| 47 |
+
|
| 48 |
+
#### Acceptance Criteria
|
| 49 |
+
|
| 50 |
+
1. WHEN objects are detected THEN the system SHALL generate a structured data table
|
| 51 |
+
2. WHEN creating the table THEN the system SHALL include object class names
|
| 52 |
+
3. WHEN creating the table THEN the system SHALL include confidence scores rounded to 3 decimal places
|
| 53 |
+
4. WHEN creating the table THEN the system SHALL include bounding box coordinates (x1, y1, x2, y2) rounded to 1 decimal place
|
| 54 |
+
5. WHEN displaying the table THEN the system SHALL present data in a user-friendly tabular format
|
| 55 |
+
|
| 56 |
+
### Requirement 5
|
| 57 |
+
|
| 58 |
+
**User Story:** As a developer, I want the application to use a pretrained YOLOv8 model, so that I don't need to train a custom model.
|
| 59 |
+
|
| 60 |
+
#### Acceptance Criteria
|
| 61 |
+
|
| 62 |
+
1. WHEN the application starts THEN the system SHALL load a pretrained YOLOv8 model (yolov8n.pt)
|
| 63 |
+
2. WHEN loading the model THEN the system SHALL handle model loading errors gracefully
|
| 64 |
+
3. WHEN using the model THEN the system SHALL utilize the built-in class name mappings
|
| 65 |
+
4. IF the model file is missing THEN the system SHALL download it automatically or display an appropriate error
|
| 66 |
+
|
| 67 |
+
### Requirement 6
|
| 68 |
+
|
| 69 |
+
**User Story:** As a user, I want the web interface to be intuitive and responsive, so that I can easily use the application.
|
| 70 |
+
|
| 71 |
+
#### Acceptance Criteria
|
| 72 |
+
|
| 73 |
+
1. WHEN the application launches THEN the system SHALL display a clear title and description
|
| 74 |
+
2. WHEN the interface loads THEN the system SHALL provide clear labels for input and output sections
|
| 75 |
+
3. WHEN processing an image THEN the system SHALL provide visual feedback during processing
|
| 76 |
+
4. WHEN results are ready THEN the system SHALL display both the annotated image and data table simultaneously
|
| 77 |
+
5. WHEN the application is accessed THEN the system SHALL be responsive across different screen sizes
|
.kiro/specs/yolov8-gradio-app/tasks.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Implementation Plan
|
| 2 |
+
|
| 3 |
+
- [x] 1. Set up project structure and implement YOLOv8 model loading
|
| 4 |
+
|
| 5 |
+
- Create project directory structure with app.py and requirements.txt
|
| 6 |
+
- Install dependencies (gradio, ultralytics, opencv-python, pillow, numpy, pandas)
|
| 7 |
+
- Implement YOLOv8 model initialization with error handling and validation
|
| 8 |
+
- Create basic image preprocessing utilities for PIL to NumPy conversion
|
| 9 |
+
- _Requirements: 5.1, 5.2, 5.3, 1.2, 1.4, 2.1_
|
| 10 |
+
|
| 11 |
+
- [x] 2. Implement core object detection and result processing
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
- Write the main detect_objects function that processes images through YOLOv8
|
| 15 |
+
- Implement detection result parsing to extract classes, confidence scores, and bounding boxes
|
| 16 |
+
- Create structured data formatting with proper rounding (confidence to 3 decimals, coordinates to 1 decimal)
|
| 17 |
+
- Add comprehensive error handling for detection failures and edge cases
|
| 18 |
+
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 4.1, 4.2, 4.3, 4.4_
|
| 19 |
+
-
|
| 20 |
+
|
| 21 |
+
- [ ] 3. Create image annotation and Gradio interface
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
- Implement annotated image generation using YOLOv8's plot() method with bounding boxes and labels
|
| 26 |
+
- Create Gradio Interface with image upload input and dual output (annotated image + data table)
|
| 27 |
+
- Add appropriate UI labels, descriptions, and user-friendly formatting
|
| 28 |
+
- Ensure proper aspect ratio maintenance and responsive display
|
| 29 |
+
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 1.1, 1.3, 4.5, 6.1, 6.2, 6.4_
|
| 30 |
+
|
| 31 |
+
- [ ] 4. Integrate components and finalize application
|
| 32 |
+
- Wire together all components into complete app.py with proper error handling
|
| 33 |
+
- Implement application launcher with demo.launch() and configuration options
|
| 34 |
+
- Add comprehensive validation for file uploads and user inputs
|
| 35 |
+
- Create end-to-end testing and deployment documentation
|
| 36 |
+
- _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5, 1.4, 5.4_
|
__pycache__/app.cpython-313.pyc
ADDED
|
Binary file (8.82 kB). View file
|
|
|
annotated_result.jpg
ADDED
|
app.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
YOLOv8 Gradio Object Detection Application
|
| 3 |
+
|
| 4 |
+
This application provides a web-based interface for object detection using YOLOv8.
|
| 5 |
+
Users can upload images and receive real-time object detection results with
|
| 6 |
+
visual annotations and structured data output.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import logging
|
| 10 |
+
import sys
|
| 11 |
+
from typing import Tuple, Optional
|
| 12 |
+
|
| 13 |
+
import cv2
|
| 14 |
+
import gradio as gr
|
| 15 |
+
import numpy as np
|
| 16 |
+
import pandas as pd
|
| 17 |
+
from PIL import Image
|
| 18 |
+
from ultralytics import YOLO
|
| 19 |
+
|
| 20 |
+
# Configure logging
|
| 21 |
+
logging.basicConfig(level=logging.INFO)
|
| 22 |
+
logger = logging.getLogger(__name__)
|
| 23 |
+
|
| 24 |
+
# Global model instance
|
| 25 |
+
model: Optional[YOLO] = None
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def initialize_model() -> bool:
|
| 29 |
+
"""
|
| 30 |
+
Initialize YOLOv8 model with error handling and validation.
|
| 31 |
+
|
| 32 |
+
Returns:
|
| 33 |
+
bool: True if model loaded successfully, False otherwise
|
| 34 |
+
"""
|
| 35 |
+
global model
|
| 36 |
+
try:
|
| 37 |
+
logger.info("Loading YOLOv8 model...")
|
| 38 |
+
model = YOLO("yolov8n.pt")
|
| 39 |
+
logger.info("YOLOv8 model loaded successfully")
|
| 40 |
+
return True
|
| 41 |
+
except Exception as e:
|
| 42 |
+
logger.error("Failed to load YOLOv8 model: %s", str(e))
|
| 43 |
+
model = None
|
| 44 |
+
return False
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def preprocess_image(image: Image.Image) -> np.ndarray:
|
| 48 |
+
"""
|
| 49 |
+
Convert PIL Image to NumPy array for YOLOv8 processing.
|
| 50 |
+
|
| 51 |
+
Args:
|
| 52 |
+
image (Image.Image): PIL Image object
|
| 53 |
+
|
| 54 |
+
Returns:
|
| 55 |
+
np.ndarray: NumPy array in RGB format
|
| 56 |
+
"""
|
| 57 |
+
try:
|
| 58 |
+
# Convert PIL Image to RGB if not already
|
| 59 |
+
if image.mode != 'RGB':
|
| 60 |
+
image = image.convert('RGB')
|
| 61 |
+
|
| 62 |
+
# Convert to NumPy array
|
| 63 |
+
image_array = np.array(image)
|
| 64 |
+
|
| 65 |
+
logger.info("Image preprocessed: shape %s", image_array.shape)
|
| 66 |
+
return image_array
|
| 67 |
+
|
| 68 |
+
except Exception as e:
|
| 69 |
+
logger.error("Error preprocessing image: %s", str(e))
|
| 70 |
+
raise
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def detect_objects(image: Image.Image) -> Tuple[Image.Image, pd.DataFrame]:
|
| 74 |
+
"""
|
| 75 |
+
Main object detection function that processes images through YOLOv8.
|
| 76 |
+
|
| 77 |
+
Args:
|
| 78 |
+
image (Image.Image): PIL Image object to process
|
| 79 |
+
|
| 80 |
+
Returns:
|
| 81 |
+
Tuple[Image.Image, pd.DataFrame]: Annotated image and detection results table
|
| 82 |
+
"""
|
| 83 |
+
if model is None:
|
| 84 |
+
logger.error("YOLOv8 model not loaded")
|
| 85 |
+
# Return original image and empty dataframe
|
| 86 |
+
empty_df = pd.DataFrame(columns=['class', 'confidence', 'x1', 'y1', 'x2', 'y2'])
|
| 87 |
+
return image, empty_df
|
| 88 |
+
|
| 89 |
+
try:
|
| 90 |
+
# Preprocess the image
|
| 91 |
+
logger.info("Starting object detection...")
|
| 92 |
+
processed_image = preprocess_image(image)
|
| 93 |
+
|
| 94 |
+
# Run YOLOv8 inference
|
| 95 |
+
results = model(processed_image)
|
| 96 |
+
|
| 97 |
+
# Parse detection results
|
| 98 |
+
annotated_image, detection_data = parse_detection_results(results[0], image)
|
| 99 |
+
|
| 100 |
+
logger.info("Object detection completed successfully")
|
| 101 |
+
return annotated_image, detection_data
|
| 102 |
+
|
| 103 |
+
except Exception as e:
|
| 104 |
+
logger.error("Error during object detection: %s", str(e))
|
| 105 |
+
# Return original image and empty dataframe on error
|
| 106 |
+
empty_df = pd.DataFrame(columns=['class', 'confidence', 'x1', 'y1', 'x2', 'y2'])
|
| 107 |
+
return image, empty_df
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def parse_detection_results(results, original_image: Image.Image) -> Tuple[Image.Image, pd.DataFrame]:
|
| 111 |
+
"""
|
| 112 |
+
Parse YOLOv8 detection results to extract classes, confidence scores, and bounding boxes.
|
| 113 |
+
|
| 114 |
+
Args:
|
| 115 |
+
results: YOLOv8 detection results object
|
| 116 |
+
original_image (Image.Image): Original PIL image for annotation
|
| 117 |
+
|
| 118 |
+
Returns:
|
| 119 |
+
Tuple[Image.Image, pd.DataFrame]: Annotated image and structured detection data
|
| 120 |
+
"""
|
| 121 |
+
try:
|
| 122 |
+
# Extract detection data
|
| 123 |
+
detection_list = []
|
| 124 |
+
|
| 125 |
+
# Check if any detections were found
|
| 126 |
+
if results.boxes is not None and len(results.boxes) > 0:
|
| 127 |
+
# Get class names from the model
|
| 128 |
+
class_names = results.names
|
| 129 |
+
|
| 130 |
+
# Extract boxes, classes, and confidence scores
|
| 131 |
+
boxes = results.boxes.xyxy.cpu().numpy() # x1, y1, x2, y2 format
|
| 132 |
+
classes = results.boxes.cls.cpu().numpy()
|
| 133 |
+
confidences = results.boxes.conf.cpu().numpy()
|
| 134 |
+
|
| 135 |
+
# Process each detection
|
| 136 |
+
for i in range(len(boxes)):
|
| 137 |
+
class_id = int(classes[i])
|
| 138 |
+
class_name = class_names[class_id]
|
| 139 |
+
confidence = float(confidences[i])
|
| 140 |
+
x1, y1, x2, y2 = boxes[i]
|
| 141 |
+
|
| 142 |
+
# Create detection record with proper rounding
|
| 143 |
+
detection_record = {
|
| 144 |
+
'class': class_name,
|
| 145 |
+
'confidence': round(confidence, 3), # Round to 3 decimal places
|
| 146 |
+
'x1': round(float(x1), 1), # Round to 1 decimal place
|
| 147 |
+
'y1': round(float(y1), 1),
|
| 148 |
+
'x2': round(float(x2), 1),
|
| 149 |
+
'y2': round(float(y2), 1)
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
detection_list.append(detection_record)
|
| 153 |
+
|
| 154 |
+
logger.info("Parsed %d detections", len(detection_list))
|
| 155 |
+
else:
|
| 156 |
+
logger.info("No objects detected in the image")
|
| 157 |
+
|
| 158 |
+
# Create DataFrame from detection list with proper columns
|
| 159 |
+
if detection_list:
|
| 160 |
+
detection_df = pd.DataFrame(detection_list)
|
| 161 |
+
else:
|
| 162 |
+
# Create empty DataFrame with correct columns
|
| 163 |
+
detection_df = pd.DataFrame(columns=['class', 'confidence', 'x1', 'y1', 'x2', 'y2'])
|
| 164 |
+
|
| 165 |
+
# Generate annotated image using YOLOv8's built-in plotting
|
| 166 |
+
annotated_image = generate_annotated_image(results, original_image)
|
| 167 |
+
|
| 168 |
+
return annotated_image, detection_df
|
| 169 |
+
|
| 170 |
+
except Exception as e:
|
| 171 |
+
logger.error("Error parsing detection results: %s", str(e))
|
| 172 |
+
# Return original image and empty dataframe on error
|
| 173 |
+
empty_df = pd.DataFrame(columns=['class', 'confidence', 'x1', 'y1', 'x2', 'y2'])
|
| 174 |
+
return original_image, empty_df
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def generate_annotated_image(results, original_image: Image.Image) -> Image.Image:
|
| 178 |
+
"""
|
| 179 |
+
Generate annotated image with bounding boxes and labels using YOLOv8's plot method.
|
| 180 |
+
|
| 181 |
+
Args:
|
| 182 |
+
results: YOLOv8 detection results object
|
| 183 |
+
original_image (Image.Image): Original PIL image
|
| 184 |
+
|
| 185 |
+
Returns:
|
| 186 |
+
Image.Image: Annotated PIL image with bounding boxes and labels
|
| 187 |
+
"""
|
| 188 |
+
try:
|
| 189 |
+
# Use YOLOv8's built-in plot method to generate annotations
|
| 190 |
+
# This automatically adds bounding boxes, class labels, and confidence scores
|
| 191 |
+
annotated_array = results.plot(
|
| 192 |
+
conf=True, # Show confidence scores
|
| 193 |
+
labels=True, # Show class labels
|
| 194 |
+
boxes=True, # Show bounding boxes
|
| 195 |
+
line_width=2, # Line width for bounding boxes
|
| 196 |
+
font_size=12 # Font size for labels
|
| 197 |
+
)
|
| 198 |
+
|
| 199 |
+
# Convert BGR to RGB (YOLOv8 plot returns BGR format)
|
| 200 |
+
annotated_rgb = cv2.cvtColor(annotated_array, cv2.COLOR_BGR2RGB)
|
| 201 |
+
|
| 202 |
+
# Convert NumPy array back to PIL Image
|
| 203 |
+
annotated_image = Image.fromarray(annotated_rgb)
|
| 204 |
+
|
| 205 |
+
# Ensure the annotated image maintains aspect ratio
|
| 206 |
+
# The YOLOv8 plot method should preserve the original dimensions
|
| 207 |
+
logger.info("Generated annotated image successfully with dimensions: %s",
|
| 208 |
+
annotated_image.size)
|
| 209 |
+
return annotated_image
|
| 210 |
+
|
| 211 |
+
except Exception as e:
|
| 212 |
+
logger.error("Error generating annotated image: %s", str(e))
|
| 213 |
+
# Return original image on error to maintain aspect ratio
|
| 214 |
+
return original_image
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
def create_gradio_interface():
|
| 218 |
+
"""
|
| 219 |
+
Create Gradio Interface with image upload input and dual output.
|
| 220 |
+
|
| 221 |
+
Returns:
|
| 222 |
+
gr.Interface: Configured Gradio interface
|
| 223 |
+
"""
|
| 224 |
+
# Create the Gradio interface
|
| 225 |
+
demo = gr.Interface(
|
| 226 |
+
fn=detect_objects,
|
| 227 |
+
inputs=gr.Image(
|
| 228 |
+
type="pil",
|
| 229 |
+
label="Upload Image for Object Detection",
|
| 230 |
+
sources=["upload", "clipboard"],
|
| 231 |
+
height=400
|
| 232 |
+
),
|
| 233 |
+
outputs=[
|
| 234 |
+
gr.Image(
|
| 235 |
+
type="pil",
|
| 236 |
+
label="Annotated Image with Detections",
|
| 237 |
+
height=400,
|
| 238 |
+
show_label=True
|
| 239 |
+
),
|
| 240 |
+
gr.Dataframe(
|
| 241 |
+
label="Detection Results",
|
| 242 |
+
headers=["Class", "Confidence", "X1", "Y1", "X2", "Y2"],
|
| 243 |
+
datatype=["str", "number", "number", "number", "number", "number"],
|
| 244 |
+
col_count=(6, "fixed"),
|
| 245 |
+
row_count=(10, "dynamic"),
|
| 246 |
+
interactive=False
|
| 247 |
+
)
|
| 248 |
+
],
|
| 249 |
+
title="🎯 YOLOv8 Object Detection",
|
| 250 |
+
description="""
|
| 251 |
+
**Upload an image to detect objects using YOLOv8!**
|
| 252 |
+
|
| 253 |
+
This application uses a pretrained YOLOv8 model to identify and locate objects in your images.
|
| 254 |
+
You'll get both a visual representation with bounding boxes and a detailed data table.
|
| 255 |
+
|
| 256 |
+
**Supported formats:** JPG, PNG, JPEG
|
| 257 |
+
""",
|
| 258 |
+
article="""
|
| 259 |
+
### How it works:
|
| 260 |
+
1. **Upload** an image using the interface above
|
| 261 |
+
2. **View** the annotated image with bounding boxes and labels
|
| 262 |
+
3. **Analyze** the detection data in the table with confidence scores and coordinates
|
| 263 |
+
|
| 264 |
+
The confidence scores are rounded to 3 decimal places, and coordinates to 1 decimal place for clarity.
|
| 265 |
+
""",
|
| 266 |
+
theme=gr.themes.Soft(),
|
| 267 |
+
css="""
|
| 268 |
+
.gradio-container {
|
| 269 |
+
max-width: 1200px !important;
|
| 270 |
+
}
|
| 271 |
+
.output-image {
|
| 272 |
+
height: 400px !important;
|
| 273 |
+
}
|
| 274 |
+
""",
|
| 275 |
+
examples=[
|
| 276 |
+
# Add example images if available
|
| 277 |
+
],
|
| 278 |
+
cache_examples=False,
|
| 279 |
+
allow_flagging="never"
|
| 280 |
+
)
|
| 281 |
+
|
| 282 |
+
return demo
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
if __name__ == "__main__":
|
| 286 |
+
# Initialize model on startup
|
| 287 |
+
if not initialize_model():
|
| 288 |
+
logger.error("Failed to initialize YOLOv8 model. Application cannot start.")
|
| 289 |
+
sys.exit(1)
|
| 290 |
+
|
| 291 |
+
logger.info("YOLOv8 model initialized successfully")
|
| 292 |
+
|
| 293 |
+
# Create and launch Gradio interface
|
| 294 |
+
try:
|
| 295 |
+
demo = create_gradio_interface()
|
| 296 |
+
logger.info("Gradio interface created successfully")
|
| 297 |
+
|
| 298 |
+
# Launch the application
|
| 299 |
+
demo.launch(
|
| 300 |
+
server_name="0.0.0.0",
|
| 301 |
+
server_port=7860,
|
| 302 |
+
share=False,
|
| 303 |
+
debug=False,
|
| 304 |
+
show_error=True,
|
| 305 |
+
quiet=False
|
| 306 |
+
)
|
| 307 |
+
|
| 308 |
+
except Exception as e:
|
| 309 |
+
logger.error("Error launching Gradio interface: %s", str(e))
|
| 310 |
+
sys.exit(1)
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio>=4.0.0
|
| 2 |
+
ultralytics>=8.0.0
|
| 3 |
+
opencv-python>=4.8.0
|
| 4 |
+
pillow>=10.0.0
|
| 5 |
+
numpy>=1.24.0
|
| 6 |
+
pandas>=2.0.0
|
test_detection.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Test script to verify the object detection functionality with a sample image.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import sys
|
| 6 |
+
from PIL import Image, ImageDraw
|
| 7 |
+
import pandas as pd
|
| 8 |
+
|
| 9 |
+
# Import our detection functions
|
| 10 |
+
from app import initialize_model, detect_objects
|
| 11 |
+
|
| 12 |
+
def create_test_image():
|
| 13 |
+
"""Create a simple test image with some basic shapes."""
|
| 14 |
+
# Create a white background
|
| 15 |
+
img = Image.new('RGB', (640, 480), 'white')
|
| 16 |
+
draw = ImageDraw.Draw(img)
|
| 17 |
+
|
| 18 |
+
# Draw some simple shapes that might be detected as objects
|
| 19 |
+
# Rectangle (might be detected as a book or similar)
|
| 20 |
+
draw.rectangle([100, 100, 300, 200], fill='blue', outline='black', width=3)
|
| 21 |
+
|
| 22 |
+
# Circle (might be detected as a ball or similar)
|
| 23 |
+
draw.ellipse([400, 150, 500, 250], fill='red', outline='black', width=3)
|
| 24 |
+
|
| 25 |
+
# Another rectangle
|
| 26 |
+
draw.rectangle([200, 300, 400, 400], fill='green', outline='black', width=3)
|
| 27 |
+
|
| 28 |
+
return img
|
| 29 |
+
|
| 30 |
+
def main():
|
| 31 |
+
print("Testing YOLOv8 object detection...")
|
| 32 |
+
|
| 33 |
+
# Initialize model
|
| 34 |
+
if not initialize_model():
|
| 35 |
+
print("Failed to initialize model")
|
| 36 |
+
return
|
| 37 |
+
|
| 38 |
+
# Create test image
|
| 39 |
+
test_img = create_test_image()
|
| 40 |
+
test_img.save("test_image.jpg")
|
| 41 |
+
print("Created test image: test_image.jpg")
|
| 42 |
+
|
| 43 |
+
# Run detection
|
| 44 |
+
annotated_img, detection_df = detect_objects(test_img)
|
| 45 |
+
|
| 46 |
+
# Save results
|
| 47 |
+
annotated_img.save("annotated_result.jpg")
|
| 48 |
+
print("Saved annotated result: annotated_result.jpg")
|
| 49 |
+
|
| 50 |
+
# Print detection results
|
| 51 |
+
print(f"\nDetection Results:")
|
| 52 |
+
print(f"Number of detections: {len(detection_df)}")
|
| 53 |
+
|
| 54 |
+
if len(detection_df) > 0:
|
| 55 |
+
print("\nDetailed results:")
|
| 56 |
+
print(detection_df.to_string(index=False))
|
| 57 |
+
|
| 58 |
+
# Verify data formatting
|
| 59 |
+
print("\nData formatting verification:")
|
| 60 |
+
for _, row in detection_df.iterrows():
|
| 61 |
+
print(f"Class: {row['class']}")
|
| 62 |
+
print(f"Confidence: {row['confidence']} (type: {type(row['confidence'])})")
|
| 63 |
+
print(f"Coordinates: ({row['x1']}, {row['y1']}, {row['x2']}, {row['y2']})")
|
| 64 |
+
print(f"Coordinate types: {type(row['x1'])}, {type(row['y1'])}, {type(row['x2'])}, {type(row['y2'])}")
|
| 65 |
+
print("---")
|
| 66 |
+
else:
|
| 67 |
+
print("No objects detected")
|
| 68 |
+
|
| 69 |
+
print("\nTest completed successfully!")
|
| 70 |
+
|
| 71 |
+
if __name__ == "__main__":
|
| 72 |
+
main()
|
test_error_handling.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Test script to verify error handling in the object detection functionality.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from PIL import Image
|
| 6 |
+
import pandas as pd
|
| 7 |
+
import app
|
| 8 |
+
from app import detect_objects, initialize_model
|
| 9 |
+
|
| 10 |
+
def test_with_none_model():
|
| 11 |
+
"""Test detection when model is None."""
|
| 12 |
+
print("Testing with None model...")
|
| 13 |
+
|
| 14 |
+
# Temporarily set model to None
|
| 15 |
+
original_model = app.model
|
| 16 |
+
app.model = None
|
| 17 |
+
|
| 18 |
+
# Create test image
|
| 19 |
+
test_img = Image.new('RGB', (100, 100), 'white')
|
| 20 |
+
|
| 21 |
+
# Run detection
|
| 22 |
+
annotated_img, detection_df = detect_objects(test_img)
|
| 23 |
+
|
| 24 |
+
# Verify results
|
| 25 |
+
print(f"Returned image type: {type(annotated_img)}")
|
| 26 |
+
print(f"Returned DataFrame shape: {detection_df.shape}")
|
| 27 |
+
print(f"DataFrame columns: {list(detection_df.columns)}")
|
| 28 |
+
print(f"DataFrame empty: {detection_df.empty}")
|
| 29 |
+
|
| 30 |
+
# Restore original model
|
| 31 |
+
app.model = original_model
|
| 32 |
+
print("Model restored\n")
|
| 33 |
+
|
| 34 |
+
def test_with_corrupted_image():
|
| 35 |
+
"""Test detection with edge case images."""
|
| 36 |
+
print("Testing with very small image...")
|
| 37 |
+
|
| 38 |
+
# Create very small image
|
| 39 |
+
tiny_img = Image.new('RGB', (1, 1), 'black')
|
| 40 |
+
|
| 41 |
+
# Run detection
|
| 42 |
+
annotated_img, detection_df = detect_objects(tiny_img)
|
| 43 |
+
|
| 44 |
+
print(f"Small image - Detections: {len(detection_df)}")
|
| 45 |
+
expected_columns = ['class', 'confidence', 'x1', 'y1', 'x2', 'y2']
|
| 46 |
+
print(f"Small image - DataFrame columns: {list(detection_df.columns)}")
|
| 47 |
+
print(f"Small image - DataFrame columns correct: {list(detection_df.columns) == expected_columns}")
|
| 48 |
+
|
| 49 |
+
print("Testing with large image...")
|
| 50 |
+
|
| 51 |
+
# Create large image
|
| 52 |
+
large_img = Image.new('RGB', (2000, 2000), 'blue')
|
| 53 |
+
|
| 54 |
+
# Run detection
|
| 55 |
+
annotated_img, detection_df = detect_objects(large_img)
|
| 56 |
+
|
| 57 |
+
print(f"Large image - Detections: {len(detection_df)}")
|
| 58 |
+
print(f"Large image - DataFrame columns: {list(detection_df.columns)}")
|
| 59 |
+
print(f"Large image - DataFrame columns correct: {list(detection_df.columns) == expected_columns}")
|
| 60 |
+
|
| 61 |
+
def main():
|
| 62 |
+
print("Testing error handling scenarios...\n")
|
| 63 |
+
|
| 64 |
+
# Initialize model first
|
| 65 |
+
if not initialize_model():
|
| 66 |
+
print("Failed to initialize model for testing")
|
| 67 |
+
return
|
| 68 |
+
|
| 69 |
+
test_with_none_model()
|
| 70 |
+
test_with_corrupted_image()
|
| 71 |
+
|
| 72 |
+
print("Error handling tests completed!")
|
| 73 |
+
|
| 74 |
+
if __name__ == "__main__":
|
| 75 |
+
main()
|
test_gradio_interface.py
ADDED
|
File without changes
|
test_image.jpg
ADDED
|
yolov8n.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f59b3d833e2ff32e194b5bb8e08d211dc7c5bdf144b90d2c8412c47ccfc83b36
|
| 3 |
+
size 6549796
|