Japhari commited on
Commit
726a8a2
·
1 Parent(s): ef78e84

Convert to Gradio and add complete ALPR OCR system

Browse files
Files changed (15) hide show
  1. .gitignore +50 -0
  2. Dockerfile +31 -0
  3. LICENSE +21 -0
  4. Makefile +39 -0
  5. README.md +53 -7
  6. app.py +167 -0
  7. deploy.sh +51 -0
  8. docker-compose.yml +12 -0
  9. packages.txt +6 -0
  10. pyproject.toml +88 -0
  11. requirements.txt +5 -0
  12. runtime.txt +1 -0
  13. setup.py +45 -0
  14. tests/__init__.py +1 -0
  15. 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: Alpr Ocr
3
- emoji: 🌖
4
- colorFrom: gray
5
  colorTo: blue
6
  sdk: gradio
7
- sdk_version: 5.44.1
8
  app_file: app.py
9
- pinned: false
10
- short_description: Automatic License Number Recognition
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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