Convert to Gradio and add complete ALPR OCR system
Browse files- .gitignore +50 -0
- Dockerfile +31 -0
- LICENSE +21 -0
- Makefile +39 -0
- README.md +53 -7
- app.py +167 -0
- deploy.sh +51 -0
- docker-compose.yml +12 -0
- packages.txt +6 -0
- pyproject.toml +88 -0
- requirements.txt +5 -0
- runtime.txt +1 -0
- setup.py +45 -0
- tests/__init__.py +1 -0
- tests/test_app.py +35 -0
.gitignore
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 4 |
+
*$py.class
|
| 5 |
+
*.so
|
| 6 |
+
.Python
|
| 7 |
+
build/
|
| 8 |
+
develop-eggs/
|
| 9 |
+
dist/
|
| 10 |
+
downloads/
|
| 11 |
+
eggs/
|
| 12 |
+
.eggs/
|
| 13 |
+
lib/
|
| 14 |
+
lib64/
|
| 15 |
+
parts/
|
| 16 |
+
sdist/
|
| 17 |
+
var/
|
| 18 |
+
wheels/
|
| 19 |
+
*.egg-info/
|
| 20 |
+
.installed.cfg
|
| 21 |
+
*.egg
|
| 22 |
+
MANIFEST
|
| 23 |
+
|
| 24 |
+
# Virtual environments
|
| 25 |
+
venv/
|
| 26 |
+
env/
|
| 27 |
+
ENV/
|
| 28 |
+
.venv/
|
| 29 |
+
.env/
|
| 30 |
+
|
| 31 |
+
# IDE
|
| 32 |
+
.vscode/
|
| 33 |
+
.idea/
|
| 34 |
+
*.swp
|
| 35 |
+
*.swo
|
| 36 |
+
*~
|
| 37 |
+
|
| 38 |
+
# OS
|
| 39 |
+
.DS_Store
|
| 40 |
+
Thumbs.db
|
| 41 |
+
|
| 42 |
+
# Streamlit
|
| 43 |
+
.streamlit/
|
| 44 |
+
|
| 45 |
+
# Logs
|
| 46 |
+
*.log
|
| 47 |
+
|
| 48 |
+
# Temporary files
|
| 49 |
+
*.tmp
|
| 50 |
+
*.temp
|
Dockerfile
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.9-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
# Install system dependencies
|
| 6 |
+
RUN apt-get update && apt-get install -y \
|
| 7 |
+
libgl1-mesa-glx \
|
| 8 |
+
libglib2.0-0 \
|
| 9 |
+
libsm6 \
|
| 10 |
+
libxext6 \
|
| 11 |
+
libxrender-dev \
|
| 12 |
+
libgomp1 \
|
| 13 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 14 |
+
|
| 15 |
+
# Copy requirements and install Python dependencies
|
| 16 |
+
COPY requirements.txt .
|
| 17 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 18 |
+
|
| 19 |
+
# Copy application code
|
| 20 |
+
COPY . .
|
| 21 |
+
|
| 22 |
+
# Expose port
|
| 23 |
+
EXPOSE 8501
|
| 24 |
+
|
| 25 |
+
# Set environment variables
|
| 26 |
+
ENV PYTHONPATH=/app
|
| 27 |
+
ENV STREAMLIT_SERVER_PORT=8501
|
| 28 |
+
ENV STREAMLIT_SERVER_ADDRESS=0.0.0.0
|
| 29 |
+
|
| 30 |
+
# Run the application
|
| 31 |
+
CMD ["python", "app.py"]
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2024 Japhari
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
Makefile
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.PHONY: help install test clean build run docker-build docker-run deploy
|
| 2 |
+
|
| 3 |
+
help: ## Show this help message
|
| 4 |
+
@echo 'Usage: make [target]'
|
| 5 |
+
@echo ''
|
| 6 |
+
@echo 'Targets:'
|
| 7 |
+
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
| 8 |
+
|
| 9 |
+
install: ## Install dependencies
|
| 10 |
+
pip install -r requirements.txt
|
| 11 |
+
|
| 12 |
+
test: ## Run tests
|
| 13 |
+
python -m pytest tests/ -v
|
| 14 |
+
|
| 15 |
+
clean: ## Clean up build artifacts
|
| 16 |
+
rm -rf build/
|
| 17 |
+
rm -rf dist/
|
| 18 |
+
rm -rf *.egg-info/
|
| 19 |
+
find . -type d -name __pycache__ -delete
|
| 20 |
+
find . -type f -name "*.pyc" -delete
|
| 21 |
+
|
| 22 |
+
build: ## Build the package
|
| 23 |
+
python setup.py sdist bdist_wheel
|
| 24 |
+
|
| 25 |
+
run: ## Run the Gradio app locally
|
| 26 |
+
python app.py
|
| 27 |
+
|
| 28 |
+
docker-build: ## Build Docker image
|
| 29 |
+
docker build -t alpr-ocr .
|
| 30 |
+
|
| 31 |
+
docker-run: ## Run Docker container
|
| 32 |
+
docker run -p 7860:7860 alpr-ocr
|
| 33 |
+
|
| 34 |
+
deploy: ## Deploy to Hugging Face Spaces
|
| 35 |
+
@echo "Deploying to Hugging Face Spaces..."
|
| 36 |
+
@echo "1. Make sure you have git-lfs installed"
|
| 37 |
+
@echo "2. Run: git add . && git commit -m 'Update ALPR OCR system'"
|
| 38 |
+
@echo "3. Run: git push origin main"
|
| 39 |
+
@echo "4. Your Space will be automatically updated at: https://huggingface.co/spaces/Japhari/alpr-ocr"
|
README.md
CHANGED
|
@@ -1,13 +1,59 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
colorTo: blue
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
app_file: app.py
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Automatic License Plate Recognition
|
| 3 |
+
emoji: 🔍
|
| 4 |
+
colorFrom: green
|
| 5 |
colorTo: blue
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 4.44.0
|
| 8 |
app_file: app.py
|
| 9 |
+
tags:
|
| 10 |
+
- computer-vision
|
| 11 |
+
- license-plate
|
| 12 |
+
- alpr
|
| 13 |
+
- license-plate-recognition
|
| 14 |
+
- object-detection
|
| 15 |
+
- license-plate-detection
|
| 16 |
+
- gradio
|
| 17 |
+
- ocr
|
| 18 |
+
- yolo
|
| 19 |
+
- onnx
|
| 20 |
+
- real-time
|
| 21 |
+
pinned: true
|
| 22 |
+
license: mit
|
| 23 |
+
short_description: Automatic License Plate Recognition
|
| 24 |
---
|
| 25 |
|
| 26 |
+
# Automatic License Plate Recognition (ALPR)
|
| 27 |
+
|
| 28 |
+
An automatic license plate recognition (ALPR) system with customizable detector and OCR models. This system uses the FastALPR library to detect and recognize license plates in images.
|
| 29 |
+
|
| 30 |
+
## Features
|
| 31 |
+
|
| 32 |
+
- **Multiple Detector Models**: Choose from various plate detection models
|
| 33 |
+
- **Customizable OCR Models**: Select different OCR models for text recognition
|
| 34 |
+
- **Real-time Processing**: Upload images and get instant results
|
| 35 |
+
- **Visual Annotations**: See detected plates highlighted on the image
|
| 36 |
+
- **Confidence Scores**: Get confidence levels for each detection
|
| 37 |
+
|
| 38 |
+
## Usage
|
| 39 |
+
|
| 40 |
+
1. Upload an image containing a vehicle with a license plate
|
| 41 |
+
2. Select your preferred detector and OCR models from the sidebar
|
| 42 |
+
3. View the processed results with annotations
|
| 43 |
+
4. See detailed OCR text and confidence scores
|
| 44 |
+
|
| 45 |
+
## Models
|
| 46 |
+
|
| 47 |
+
The system supports multiple detector and OCR models from the FastALPR library, including:
|
| 48 |
+
|
| 49 |
+
- Various YOLO-based detection models
|
| 50 |
+
- CCT OCR models for text recognition
|
| 51 |
+
- Global and specialized models for different use cases
|
| 52 |
+
|
| 53 |
+
## Requirements
|
| 54 |
+
|
| 55 |
+
- Python 3.8+
|
| 56 |
+
- FastALPR library
|
| 57 |
+
- Streamlit
|
| 58 |
+
- OpenCV
|
| 59 |
+
- PIL/Pillow
|
app.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import cv2
|
| 3 |
+
import numpy as np
|
| 4 |
+
from PIL import Image
|
| 5 |
+
from typing import get_args
|
| 6 |
+
|
| 7 |
+
from fast_alpr import ALPR
|
| 8 |
+
from fast_alpr.default_detector import PlateDetectorModel
|
| 9 |
+
from fast_alpr.default_ocr import OcrModel
|
| 10 |
+
|
| 11 |
+
# Default models
|
| 12 |
+
DETECTOR_MODELS = list(get_args(PlateDetectorModel))
|
| 13 |
+
OCR_MODELS = list(get_args(OcrModel))
|
| 14 |
+
# Put global OCR first
|
| 15 |
+
OCR_MODELS.remove("cct-s-v1-global-model")
|
| 16 |
+
OCR_MODELS.insert(0, "cct-s-v1-global-model")
|
| 17 |
+
|
| 18 |
+
def process_image(image, detector_model, ocr_model):
|
| 19 |
+
"""
|
| 20 |
+
Process an image with ALPR system
|
| 21 |
+
|
| 22 |
+
Args:
|
| 23 |
+
image: PIL Image or numpy array
|
| 24 |
+
detector_model: Selected detector model
|
| 25 |
+
ocr_model: Selected OCR model
|
| 26 |
+
|
| 27 |
+
Returns:
|
| 28 |
+
tuple: (annotated_image, results_text)
|
| 29 |
+
"""
|
| 30 |
+
if image is None:
|
| 31 |
+
return None, "Please upload an image to continue."
|
| 32 |
+
|
| 33 |
+
try:
|
| 34 |
+
# Convert image to numpy array if it's a PIL Image
|
| 35 |
+
if isinstance(image, Image.Image):
|
| 36 |
+
img_array = np.array(image.convert("RGB"))
|
| 37 |
+
else:
|
| 38 |
+
img_array = image
|
| 39 |
+
|
| 40 |
+
# Initialize ALPR with selected models
|
| 41 |
+
alpr = ALPR(detector_model=detector_model, ocr_model=ocr_model)
|
| 42 |
+
|
| 43 |
+
# Run ALPR on the image
|
| 44 |
+
results = alpr.predict(img_array)
|
| 45 |
+
|
| 46 |
+
# Draw predictions on the image
|
| 47 |
+
annotated_img_array = alpr.draw_predictions(img_array)
|
| 48 |
+
|
| 49 |
+
# Convert back to PIL Image for Gradio
|
| 50 |
+
annotated_img = Image.fromarray(annotated_img_array)
|
| 51 |
+
|
| 52 |
+
# Format results text
|
| 53 |
+
if results:
|
| 54 |
+
results_text = "**OCR Results:**\n"
|
| 55 |
+
for i, result in enumerate(results):
|
| 56 |
+
plate_text = result.ocr.text if result.ocr else "N/A"
|
| 57 |
+
plate_confidence = result.ocr.confidence if result.ocr else 0.0
|
| 58 |
+
results_text += f"{i+1}. Detected Plate: `{plate_text}` with confidence `{plate_confidence:.2f}`\n"
|
| 59 |
+
else:
|
| 60 |
+
results_text = "No license plate detected 😔."
|
| 61 |
+
|
| 62 |
+
return annotated_img, results_text
|
| 63 |
+
|
| 64 |
+
except Exception as e:
|
| 65 |
+
return None, f"Error processing image: {str(e)}"
|
| 66 |
+
|
| 67 |
+
# Create Gradio interface
|
| 68 |
+
with gr.Blocks(
|
| 69 |
+
title="Automatic License Plate Recognition (ALPR)",
|
| 70 |
+
theme=gr.themes.Soft(
|
| 71 |
+
primary_hue="green",
|
| 72 |
+
secondary_hue="blue",
|
| 73 |
+
neutral_hue="slate"
|
| 74 |
+
)
|
| 75 |
+
) as demo:
|
| 76 |
+
|
| 77 |
+
gr.Markdown("""
|
| 78 |
+
# 🔍 Automatic License Plate Recognition (ALPR)
|
| 79 |
+
|
| 80 |
+
An automatic license plate recognition (ALPR) system with customizable detector and OCR models.
|
| 81 |
+
|
| 82 |
+
This system uses the FastALPR library to detect and recognize license plates in images.
|
| 83 |
+
""")
|
| 84 |
+
|
| 85 |
+
with gr.Row():
|
| 86 |
+
with gr.Column(scale=1):
|
| 87 |
+
gr.Markdown("### Model Selection")
|
| 88 |
+
detector_dropdown = gr.Dropdown(
|
| 89 |
+
choices=DETECTOR_MODELS,
|
| 90 |
+
value=DETECTOR_MODELS[0],
|
| 91 |
+
label="Choose Detector Model",
|
| 92 |
+
info="Select the model for license plate detection"
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
ocr_dropdown = gr.Dropdown(
|
| 96 |
+
choices=OCR_MODELS,
|
| 97 |
+
value=OCR_MODELS[0],
|
| 98 |
+
label="Choose OCR Model",
|
| 99 |
+
info="Select the model for text recognition"
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
gr.Markdown("### Upload Image")
|
| 103 |
+
image_input = gr.Image(
|
| 104 |
+
label="Upload an image of a vehicle with a license plate",
|
| 105 |
+
type="pil",
|
| 106 |
+
height=300
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
process_btn = gr.Button(
|
| 110 |
+
"🚀 Process Image",
|
| 111 |
+
variant="primary",
|
| 112 |
+
size="lg"
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
with gr.Column(scale=1):
|
| 116 |
+
gr.Markdown("### Results")
|
| 117 |
+
image_output = gr.Image(
|
| 118 |
+
label="Annotated Image with OCR Results",
|
| 119 |
+
height=300
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
text_output = gr.Markdown(
|
| 123 |
+
label="OCR Results",
|
| 124 |
+
value="Upload an image and click 'Process Image' to see results."
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
# Add some examples
|
| 128 |
+
gr.Markdown("### 📸 Example Images")
|
| 129 |
+
gr.Examples(
|
| 130 |
+
examples=[],
|
| 131 |
+
inputs=image_input,
|
| 132 |
+
label="Try with these examples (if available)"
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
# Connect the interface
|
| 136 |
+
process_btn.click(
|
| 137 |
+
fn=process_image,
|
| 138 |
+
inputs=[image_input, detector_dropdown, ocr_dropdown],
|
| 139 |
+
outputs=[image_output, text_output]
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
gr.Markdown("""
|
| 143 |
+
---
|
| 144 |
+
### 🚀 How to Use
|
| 145 |
+
|
| 146 |
+
1. **Select Models**: Choose your preferred detector and OCR models from the dropdowns
|
| 147 |
+
2. **Upload Image**: Upload an image containing a vehicle with a license plate
|
| 148 |
+
3. **Process**: Click the "Process Image" button to run ALPR
|
| 149 |
+
4. **View Results**: See the annotated image and OCR text results
|
| 150 |
+
|
| 151 |
+
### 🔧 Supported Models
|
| 152 |
+
|
| 153 |
+
- **Detector Models**: Various YOLO-based detection models
|
| 154 |
+
- **OCR Models**: CCT OCR models for text recognition including global and specialized models
|
| 155 |
+
|
| 156 |
+
### 📊 Features
|
| 157 |
+
|
| 158 |
+
- Real-time license plate detection
|
| 159 |
+
- Customizable model selection
|
| 160 |
+
- Visual annotations with bounding boxes
|
| 161 |
+
- Confidence scores for OCR results
|
| 162 |
+
- Support for multiple image formats
|
| 163 |
+
""")
|
| 164 |
+
|
| 165 |
+
# Launch the app
|
| 166 |
+
if __name__ == "__main__":
|
| 167 |
+
demo.launch(share=False)
|
deploy.sh
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Deploy script for Hugging Face Spaces
|
| 4 |
+
# This script helps deploy the ALPR OCR system to Hugging Face
|
| 5 |
+
|
| 6 |
+
set -e
|
| 7 |
+
|
| 8 |
+
echo "🚀 Starting deployment to Hugging Face Spaces..."
|
| 9 |
+
|
| 10 |
+
# Check if git is initialized
|
| 11 |
+
if [ ! -d ".git" ]; then
|
| 12 |
+
echo "📁 Initializing git repository..."
|
| 13 |
+
git init
|
| 14 |
+
git remote add origin https://huggingface.co/spaces/Japhari/alpr-ocr
|
| 15 |
+
fi
|
| 16 |
+
|
| 17 |
+
# Check if git-lfs is installed
|
| 18 |
+
if ! command -v git-lfs &> /dev/null; then
|
| 19 |
+
echo "⚠️ git-lfs is not installed. Please install it first:"
|
| 20 |
+
echo " macOS: brew install git-lfs"
|
| 21 |
+
echo " Ubuntu: sudo apt-get install git-lfs"
|
| 22 |
+
echo " Windows: https://git-lfs.github.com/"
|
| 23 |
+
exit 1
|
| 24 |
+
fi
|
| 25 |
+
|
| 26 |
+
# Setup git-lfs
|
| 27 |
+
echo "🔧 Setting up git-lfs..."
|
| 28 |
+
git lfs install
|
| 29 |
+
git lfs track "*.py"
|
| 30 |
+
git lfs track "*.md"
|
| 31 |
+
git lfs track "*.txt"
|
| 32 |
+
git lfs track "*.toml"
|
| 33 |
+
git lfs track "*.yml"
|
| 34 |
+
git lfs track "*.yaml"
|
| 35 |
+
git lfs track "*.sh"
|
| 36 |
+
|
| 37 |
+
# Add all files
|
| 38 |
+
echo "📝 Adding files to git..."
|
| 39 |
+
git add .
|
| 40 |
+
|
| 41 |
+
# Commit changes
|
| 42 |
+
echo "💾 Committing changes..."
|
| 43 |
+
git commit -m "Update ALPR OCR system - $(date)"
|
| 44 |
+
|
| 45 |
+
# Push to Hugging Face
|
| 46 |
+
echo "🚀 Pushing to Hugging Face Spaces..."
|
| 47 |
+
git push origin main
|
| 48 |
+
|
| 49 |
+
echo "✅ Deployment completed successfully!"
|
| 50 |
+
echo "🌐 Your Space is available at: https://huggingface.co/spaces/Japhari/alpr-ocr"
|
| 51 |
+
echo "⏳ It may take a few minutes for the changes to appear."
|
docker-compose.yml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: '3.8'
|
| 2 |
+
|
| 3 |
+
services:
|
| 4 |
+
alpr-app:
|
| 5 |
+
build: .
|
| 6 |
+
ports:
|
| 7 |
+
- "7860:7860"
|
| 8 |
+
volumes:
|
| 9 |
+
- .:/app
|
| 10 |
+
environment:
|
| 11 |
+
- PYTHONPATH=/app
|
| 12 |
+
restart: unless-stopped
|
packages.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
libgl1-mesa-glx
|
| 2 |
+
libglib2.0-0
|
| 3 |
+
libsm6
|
| 4 |
+
libxext6
|
| 5 |
+
libxrender-dev
|
| 6 |
+
libgomp1
|
pyproject.toml
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[build-system]
|
| 2 |
+
requires = ["setuptools>=45", "wheel", "setuptools_scm[toml]>=6.2"]
|
| 3 |
+
build-backend = "setuptools.build_meta"
|
| 4 |
+
|
| 5 |
+
[project]
|
| 6 |
+
name = "alpr-ocr"
|
| 7 |
+
dynamic = ["version"]
|
| 8 |
+
description = "Automatic License Plate Recognition (ALPR) system with customizable detector and OCR models"
|
| 9 |
+
readme = "README.md"
|
| 10 |
+
license = {text = "MIT"}
|
| 11 |
+
authors = [
|
| 12 |
+
{name = "Japhari", email = ""}
|
| 13 |
+
]
|
| 14 |
+
maintainers = [
|
| 15 |
+
{name = "Japhari", email = ""}
|
| 16 |
+
]
|
| 17 |
+
keywords = ["alpr", "ocr", "license-plate", "computer-vision", "gradio"]
|
| 18 |
+
classifiers = [
|
| 19 |
+
"Development Status :: 3 - Alpha",
|
| 20 |
+
"Intended Audience :: Developers",
|
| 21 |
+
"Intended Audience :: Science/Research",
|
| 22 |
+
"License :: OSI Approved :: MIT License",
|
| 23 |
+
"Operating System :: OS Independent",
|
| 24 |
+
"Programming Language :: Python :: 3",
|
| 25 |
+
"Programming Language :: Python :: 3.9",
|
| 26 |
+
"Programming Language :: Python :: 3.10",
|
| 27 |
+
"Programming Language :: Python :: 3.11",
|
| 28 |
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
| 29 |
+
"Topic :: Scientific/Engineering :: Image Recognition",
|
| 30 |
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
| 31 |
+
]
|
| 32 |
+
requires-python = ">=3.9"
|
| 33 |
+
dependencies = [
|
| 34 |
+
"fast-alpr[onnx]>=0.2.0",
|
| 35 |
+
"gradio>=4.44.0",
|
| 36 |
+
"opencv-python-headless",
|
| 37 |
+
"pillow",
|
| 38 |
+
"numpy",
|
| 39 |
+
]
|
| 40 |
+
|
| 41 |
+
[project.optional-dependencies]
|
| 42 |
+
dev = [
|
| 43 |
+
"pytest",
|
| 44 |
+
"black",
|
| 45 |
+
"flake8",
|
| 46 |
+
"mypy",
|
| 47 |
+
"pre-commit",
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
[project.urls]
|
| 51 |
+
Homepage = "https://huggingface.co/spaces/Japhari/alpr-ocr"
|
| 52 |
+
Repository = "https://huggingface.co/spaces/Japhari/alpr-ocr"
|
| 53 |
+
Documentation = "https://huggingface.co/spaces/Japhari/alpr-ocr"
|
| 54 |
+
Issues = "https://huggingface.co/spaces/Japhari/alpr-ocr"
|
| 55 |
+
|
| 56 |
+
[project.scripts]
|
| 57 |
+
alpr-ocr = "app:main"
|
| 58 |
+
|
| 59 |
+
[tool.setuptools]
|
| 60 |
+
packages = ["app"]
|
| 61 |
+
|
| 62 |
+
[tool.setuptools.package-data]
|
| 63 |
+
"*" = ["*.md", "*.txt", "*.toml"]
|
| 64 |
+
|
| 65 |
+
[tool.black]
|
| 66 |
+
line-length = 88
|
| 67 |
+
target-version = ['py39']
|
| 68 |
+
include = '\.pyi?$'
|
| 69 |
+
extend-exclude = '''
|
| 70 |
+
/(
|
| 71 |
+
# directories
|
| 72 |
+
\.eggs
|
| 73 |
+
| \.git
|
| 74 |
+
| \.hg
|
| 75 |
+
| \.mypy_cache
|
| 76 |
+
| \.tox
|
| 77 |
+
| \.venv
|
| 78 |
+
| build
|
| 79 |
+
| dist
|
| 80 |
+
)/
|
| 81 |
+
'''
|
| 82 |
+
|
| 83 |
+
[tool.pytest.ini_options]
|
| 84 |
+
testpaths = ["tests"]
|
| 85 |
+
python_files = ["test_*.py"]
|
| 86 |
+
python_classes = ["Test*"]
|
| 87 |
+
python_functions = ["test_*"]
|
| 88 |
+
addopts = "-v --tb=short"
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fast-alpr[onnx]>=0.2.0
|
| 2 |
+
gradio>=4.44.0
|
| 3 |
+
opencv-python-headless
|
| 4 |
+
pillow
|
| 5 |
+
numpy
|
runtime.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
python-3.9
|
setup.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from setuptools import setup, find_packages
|
| 2 |
+
|
| 3 |
+
with open("README.md", "r", encoding="utf-8") as fh:
|
| 4 |
+
long_description = fh.read()
|
| 5 |
+
|
| 6 |
+
with open("requirements.txt", "r", encoding="utf-8") as fh:
|
| 7 |
+
requirements = [line.strip() for line in fh if line.strip() and not line.startswith("#")]
|
| 8 |
+
|
| 9 |
+
setup(
|
| 10 |
+
name="alpr-ocr",
|
| 11 |
+
version="0.1.0",
|
| 12 |
+
author="Japhari",
|
| 13 |
+
author_email="",
|
| 14 |
+
description="Automatic License Plate Recognition (ALPR) system with customizable detector and OCR models",
|
| 15 |
+
long_description=long_description,
|
| 16 |
+
long_description_content_type="text/markdown",
|
| 17 |
+
url="https://huggingface.co/spaces/Japhari/alpr-ocr",
|
| 18 |
+
packages=find_packages(),
|
| 19 |
+
classifiers=[
|
| 20 |
+
"Development Status :: 3 - Alpha",
|
| 21 |
+
"Intended Audience :: Developers",
|
| 22 |
+
"Intended Audience :: Science/Research",
|
| 23 |
+
"License :: OSI Approved :: MIT License",
|
| 24 |
+
"Operating System :: OS Independent",
|
| 25 |
+
"Programming Language :: Python :: 3",
|
| 26 |
+
"Programming Language :: Python :: 3.9",
|
| 27 |
+
"Programming Language :: Python :: 3.10",
|
| 28 |
+
"Programming Language :: Python :: 3.11",
|
| 29 |
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
| 30 |
+
"Topic :: Scientific/Engineering :: Image Recognition",
|
| 31 |
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
| 32 |
+
],
|
| 33 |
+
python_requires=">=3.9",
|
| 34 |
+
install_requires=requirements,
|
| 35 |
+
extras_require={
|
| 36 |
+
"dev": [
|
| 37 |
+
"pytest",
|
| 38 |
+
"black",
|
| 39 |
+
"flake8",
|
| 40 |
+
"mypy",
|
| 41 |
+
],
|
| 42 |
+
},
|
| 43 |
+
include_package_data=True,
|
| 44 |
+
zip_safe=False,
|
| 45 |
+
)
|
tests/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# Tests package for ALPR OCR system
|
tests/test_app.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
import numpy as np
|
| 3 |
+
from PIL import Image
|
| 4 |
+
import gradio as gr
|
| 5 |
+
|
| 6 |
+
# Mock test for the ALPR system
|
| 7 |
+
def test_requirements_import():
|
| 8 |
+
"""Test that all required packages can be imported"""
|
| 9 |
+
try:
|
| 10 |
+
import cv2
|
| 11 |
+
import numpy as np
|
| 12 |
+
import gradio as gr
|
| 13 |
+
from PIL import Image
|
| 14 |
+
from fast_alpr import ALPR
|
| 15 |
+
assert True
|
| 16 |
+
except ImportError as e:
|
| 17 |
+
pytest.fail(f"Failed to import required package: {e}")
|
| 18 |
+
|
| 19 |
+
def test_image_processing():
|
| 20 |
+
"""Test basic image processing functionality"""
|
| 21 |
+
# Create a dummy image
|
| 22 |
+
dummy_img = np.random.randint(0, 255, (100, 100, 3), dtype=np.uint8)
|
| 23 |
+
|
| 24 |
+
# Test PIL conversion
|
| 25 |
+
pil_img = Image.fromarray(dummy_img)
|
| 26 |
+
assert pil_img.size == (100, 100)
|
| 27 |
+
|
| 28 |
+
# Test numpy conversion back
|
| 29 |
+
img_array = np.array(pil_img)
|
| 30 |
+
assert img_array.shape == (100, 100, 3)
|
| 31 |
+
|
| 32 |
+
def test_streamlit_components():
|
| 33 |
+
"""Test that Streamlit components can be created"""
|
| 34 |
+
# This is a basic test to ensure the app structure is valid
|
| 35 |
+
assert True
|