Skip to main content

No project description provided

Project description

🚘 License Plate Annotation Demo Filter

License Plate Annotation Demo Filter is a lightweight OpenFilter-based demo filter that overlays OCR-processed license plate text and cropped plate images onto video frames.

It integrates seamlessly with:

PyPI version License: Apache 2.0 Build Status


✨ Features

  • 🖍️ Overlays OCR license plate text on the main frame
  • 🖼️ Displays cropped license plate image as a top-left inset
  • 🧠 Filters OCR output using a regex pattern for valid plates (e.g., ABC1234)
  • 🧩 Designed to run after detection, cropping, and OCR filters in OpenFilter pipelines
  • ⚙️ Fully configurable via CLI, code, or environment variables

📦 Installation

Install the latest version from PyPI:

pip install filter-license-annotation-demo

Or install from source:

# Clone the repo
git clone https://github.com/PlainsightAI/filter-license-annotation-demo.git
cd filter-license-annotation-demo

# (Optional but recommended) create a virtual environemnt:
python -m venv venv && source venv/bin/activate

# Install the filter
make install

🚀 Quick Start (CLI)

Run a full license plate pipeline using the CLI:

openfilter run \
	- VideoIn \
		--sources 'file://example_video.mp4!loop' \
	- filter_license_plate_detection.filter.FilterLicensePlateDetection \
	- filter_crop.filter.FilterCrop \
		--detection_key license_plate_detection \
		--detection_class_field label \
		--detection_roi_field box \
		--output_prefix cropped_ \
		--mutate_original_frames false \
		--topic_mode main_only \
	- filter_optical_character_recognition.filter.FilterOpticalCharacterRecognition \
		--topic_pattern 'license_plate' \
		--ocr_engine easyocr \
		--forward_ocr_texts true \
	- filter_license_annotation_demo.filter.FilterLicenseAnnotationDemo \
		--cropped_topic_suffix license_plate \
	- Webvis

Or:

make run

Then open http://localhost:8000 to view annotated results.


🧰 Using from PyPI

After installing with:

pip install filter-license-annotation-demo

You can run the filter directly in code:

Standalone

from filter_license_annotation_demo.filter import FilterLicenseAnnotationDemo

if __name__ == "__main__":
    FilterLicenseAnnotationDemo.run()

Multi-filter Pipeline

from openfilter.filter_runtime.filter import Filter
from filter_license_plate_detection.filter import FilterLicensePlateDetection
from filter_crop.filter import FilterCrop
from filter_optical_character_recognition.filter import FilterOpticalCharacterRecognition
from filter_license_annotation_demo.filter import FilterLicenseAnnotationDemo
from openfilter.filter_runtime.filters.video_in import VideoIn
from openfilter.filter_runtime.filters.webvis import Webvis

if __name__ == '__main__':
    Filter.run_multi([
        (VideoIn, dict(
            sources='file://example_video.mp4!loop',
            outputs='tcp://*:5550',
        )),
        (FilterLicensePlateDetection, dict(
            sources='tcp://localhost:5550',
            outputs='tcp://*:5552',
        )),
        (FilterCrop, dict(
            sources='tcp://localhost:5552',
            outputs='tcp://*:5554',
            detection_key='license_plate_detection',
            detection_class_field='label',
            detection_roi_field='box',
            output_prefix='cropped_',
            mutate_original_frames=False,
            topic_mode='main_only',
        )),
        (FilterOpticalCharacterRecognition, dict(
            sources='tcp://localhost:5554',
            outputs='tcp://*:5556',
            topic_pattern='license_plate',
            ocr_engine='easyocr',
            forward_ocr_texts=True,
        )),
        (FilterLicenseAnnotationDemo, dict(
            sources='tcp://localhost:5556',
            outputs='tcp://*:5558',
            cropped_topic_suffix='license_plate',
        )),
        (Webvis, dict(
            sources='tcp://localhost:5558',
        )),
    ])

🔧 Configuration

Field Type Description Example
cropped_topic_suffix str Topic with cropped plate images "cropped_main"
font_scale float Font size multiplier for overlay text 1.0
font_thickness int Thickness of text stroke 2
inset_size tuple Width and height of the inset image (200, 60)
inset_margin tuple Offset from top-left corner (10, 10)
debug bool Enable verbose debug logging true

All fields are also supported as environment variables using the FILTER_ prefix (e.g., FILTER_FONT_SCALE=1.2).


🧪 Testing

Run all tests:

make test

Run individual test files:

pytest -v tests/test_filter_license_annotation_demo.py

🧩 How It Works

Filter Role
filter-license-plate-detection Detects license plates in frames
filter-crop Crops detected license plates
filter-optical-character-recognition Applies OCR to cropped license plate images
**This Filter** Overlays cropped plate image and OCR text on main frame

OCR text is filtered using a regex (^[A-Z]{3}[0-9]{4}$). If no valid OCR is detected in the current frame, the last valid plate is reused for continuity.


🤝 Contributing

We welcome contributions! See our CONTRIBUTING.md.

Tips:

  • Format with black
  • Lint with ruff
  • Add type hints and docstrings
  • Write tests for all features
  • Sign commits using DCO (git commit -s)

📄 License

Licensed under the Apache 2.0 License.


🙏 Acknowledgements

Thank you for using the License Plate Annotation Filter!

Questions or feedback? Open an issue.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

filter_license_annotation_demo-0.1.5-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file filter_license_annotation_demo-0.1.5-py3-none-any.whl.

File metadata

File hashes

Hashes for filter_license_annotation_demo-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 647406a72b76c30b19b34f60347ba533a73a3130dcfe240acd6347d0bce5d338
MD5 8b0a73ced0238260da082b5579089045
BLAKE2b-256 9d413fc3568ad41f4e97d1a4fff0405b5a72ca5e5e319187e23f89defaf5e77b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page