update readme

This commit is contained in:
Mathieu Broillet 2024-08-04 18:41:20 +02:00
parent 224d566d65
commit 8bc5187d5e
Signed by: mathieu
GPG Key ID: C4A6176ABC6B2DFC
5 changed files with 95 additions and 31 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

116
README.md
View File

@ -1,31 +1,48 @@
# Easy local ALPR (Automatic License Plate Recognition) ![logo](static/logo_black.webp)
![ALPR](.git-assets/preview-webui.webp)
![ALPR](preview-webui.webp) # Easy Local ALPR (Automatic License Plate Recognition)
This project is a simple local ALPR (Automatic License Plate Recognition) server that uses the [ultimateALPR-SDK](https://github.com/DoubangoTelecom/ultimateALPR-SDK) to
process images and return the license plate information found in the image while focusing on being:
- **Fast** *(~100ms per image on decent CPU)*
- **Lightweight** *(~100MB of RAM)*
- **Easy to use** *(REST API)*
- **Easy to setup** *(one command setup)*
- **Offline** *(no internet connection required)*
This script is a REST API server that uses [ultimateALPR-SDK](https://github.com/DoubangoTelecom/ultimateALPR-SDK) to process images and return the license plate
information. The server is created using Flask and the ultimateALPR SDK is used to process the images.
This script is intended to be used as a faster local alternative to the large and resource heavy [CodeProject AI](https://www.codeproject.com/AI/docs) software.
> [!IMPORTANT] > [!IMPORTANT]
> The ultimateALPR SDK is a lightweight and much faster alternative (on CPU and GPU) to the CodeProject AI software but it has **a few limitations** with it's free version: > This project relies on the [ultimateALPR-SDK](https://github.com/DoubangoTelecom/ultimateALPR-SDK), which is a commercial product but has a free version with a few limitations.
> - The last character of the license plate is masked with an asterisk > For any commercial use, you will need to take a look at their licensing terms.
> - The SDK supposedly has a limit of requests per program execution *(never encountered yet)* **but I have implemented a workaround for this by restarting the SDK after 3000 requests just in case.** > **I am not affiliated with ultimateALPR-SDK in any way, and I am not responsible for any misuse of the software.**
> [!NOTE]
> The [ultimateALPR-SDK](https://github.com/DoubangoTelecom/ultimateALPR-SDK) is a lightweight and much faster alternative (on CPU and GPU) to existing solutions like
> [CodeProject AI](https://www.codeproject.com/AI/docs/index.html) but it has **one important restriction** with it's free version:
> - The last character of the license plate is masked with an asterisk *(e.g. ``ABC1234`` -> ``ABC123*``)*
## Usage ## Usage
The server listens on port 5000 and has a few endpoints (see below), the most important one being ``/v1/image/alpr``.
The server listens on port 5000 and has a few endpoints documented below, the most important one being [``/v1/image/alpr``](#v1visionalpr).
### /v1/vision/alpr ### /v1/vision/alpr
> POST: http://localhost:5000/v1/vision/alpr > POST: http://localhost:5000/v1/vision/alpr
**Description** **Description**
This endpoint processes an image and returns the license plate information (if any) found in the image. This endpoint processes an image and returns the license plate information (if any) found in the image.
This endpoint follows the [CodeProject AI ALPR API](https://www.codeproject.com/AI/docs/api/api_reference.html#license-plate-reader) format *(example below)* so it can be used as a **drop-in replacement** for the CodeProject AI software. This endpoint follows
the [CodeProject AI ALPR API](https://www.codeproject.com/AI/docs/api/api_reference.html#license-plate-reader) format *(
example below)* so it can be used as a **drop-in replacement** for the CodeProject AI software.
**Parameters** **Parameters**
- upload: (File) The image file to process. *(see [Pillow.Image.open()](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.open) for supported formats, almost any image format is supported)*
- grid_size: (Integer, optional) Size of grid to divide the image into and retry on each cell when no match have been found on the whole image *(default: 4)* **[(more info)](#more-information-about-the-grid-parameter)** - upload: (File) The image file to process. *(
- wanted_cells: (String, optional) The cells you want to process *(default: all cells)* **[(see here)](#v1visionalpr_grid_debug)** see [Pillow.Image.open()](https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.open) for supported
formats, almost any image format is supported)*
- grid_size: (Integer, optional) Size of grid to divide the image into and retry on each cell when no match have been
found on the whole image *(default: 3)* **[(more info)](#more-information-about-the-grid-parameter)**
- wanted_cells: (String, optional) The cells you want to process *(default: all cells)* *
*[(see here)](#v1visionalpr_grid_debug)**
- format: ``1,2,3,4,...`` *(comma separated list of integers, max: grid_size^2)* - format: ``1,2,3,4,...`` *(comma separated list of integers, max: grid_size^2)*
- *Example for a grid_size of 3:* - *Example for a grid_size of 3:*
``` ```
@ -34,9 +51,9 @@ This endpoint follows the [CodeProject AI ALPR API](https://www.codeproject.com/
7 | 8 | 9 7 | 8 | 9
``` ```
**Response**
**Response** ```jsonc
```json
{ {
"success": (Boolean) // True if successful. "success": (Boolean) // True if successful.
"message": (String) // A summary of the inference operation. "message": (String) // A summary of the inference operation.
@ -47,6 +64,7 @@ This endpoint follows the [CodeProject AI ALPR API](https://www.codeproject.com/
``` ```
### /v1/vision/alpr_grid_debug ### /v1/vision/alpr_grid_debug
> POST: http://localhost:5000/v1/vision/alpr_grid_debug > POST: http://localhost:5000/v1/vision/alpr_grid_debug
**Description** **Description**
@ -56,32 +74,71 @@ It is intended to be used for debugging purposes to see which cells are being pr
**Parameters** **Parameters**
*same as [v1/vision/alpr](#v1visionalpr)* *same as [v1/vision/alpr](#v1visionalpr)*
**Response** **Response**
```json
```jsonc
{ {
"image": (Base64) // The image with the grid and cell numbers drawn on it. "image": (Base64) // The image with the grid and cell numbers drawn on it.
} }
``` ```
## More information about the grid parameter ## More information about the grid parameter
*To write*
When you send an image to the server, sometimes the ALPR software cannot find any plate because the image is too big or
the plate is too small in the image.
To solve this problem, if no plate is found on the whole image, the server will divide the image into a grid of cells
and retry the ALPR software on each cell.
You can specify the size of the grid with the ``grid_size`` parameter in each of your requests.
> [!CAUTION]
> The higher the grid size, the longer the processing time will be. It is recommended to keep the grid size between 3
> and 4.
> Note: The processing time is in no way multiplied by the grid size (usually takes 2x the time)
You can speed up the processing time by specifying the ``wanted_cells`` parameter. This parameter allows you to specify
which cells you want to run plate detection on.
This can be useful if you know the plates can only be in certain areas of the image.
> [!TIP]
> You can use the [``/v1/vision/alpr_grid_debug`` endpoint](#v1visionalpr_grid_debug) to see the grid and cell numbers
> overlaid on your image.
> You can then specify the ``wanted_cells`` parameter to only process the cells you want.
**If you wish not to use the grid, you can set the ``grid_size`` parameter to
0 *(and leave the ``wanted_cells`` parameter empty)*.**
### Example
Let's say your driveway camera looks something like this:
![Driveway camera](.git-assets/example_grid.webp)
If you set the ``grid_size`` parameter to 2, the image will be divided into a 2x2 grid like this:
![Driveway camera grid](.git-assets/example_grid_2.webp)
You can see that cell 1 and 2 are empty and cells 3 and 4 might contain license plates.
You can then set the ``wanted_cells`` parameter to ``3,4`` to only process cells 3 and 4, reducing the processing time
as only half the image will be processed.
## Included models in built executable ## Included models in built executable
When using the built executable, only the **latin** charset models are bundled by default. If you want to use a different
charset, you need to set the charset in the JSON_CONFIG variable and rebuild the executable with the according When using the built executable, only the **latin** charset models are bundled by default. If you want to use a
models found [here](https://github.com/DoubangoTelecom/ultimateALPR-SDK/tree/master/assets) different charset, you need to set the charset in the JSON_CONFIG variable and rebuild the executable with the
To build the executable, you can use the ``build_alpr_api.sh`` script, which will create an executable named ``alpr_api`` in according models found [here](https://github.com/DoubangoTelecom/ultimateALPR-SDK/tree/master/assets)
the ``dist`` folder. To build the executable, you can use the ``build_alpr_api.sh`` script, which will create an executable
named ``alpr_api`` in the ``dist`` folder.
## Setup development environment ## Setup development environment
### Use automatic setup script ### Use automatic setup script
You can use the ``build_and_setup_ultimatealvr.sh`` script to automatically install the necessary packages and build the ultimateALPR SDK wheel, copy the assets and the libs.
> [!IMPORTANT] > [!IMPORTANT]
> Make sure to install the package python3-dev (APT) python3-devel (RPM) before running the build and setup script. > Make sure to install the package python3-dev (APT) python3-devel (RPM) before running the build and setup script.
> You can use the ``build_and_setup_ultimatealvr.sh`` script to automatically install the necessary packages and build
> the
> ultimateALPR SDK wheel, copy the assets and the libs.
The end structure should look like this: The end structure should look like this:
```bash ```bash
. .
├── alpr_api.py ├── alpr_api.py
@ -96,16 +153,23 @@ The end structure should look like this:
``` ```
### Important notes ### Important notes
When running, building or developing the script, make sure to set the ``LD_LIBRARY_PATH`` environment variable to the libs folder
When running, building or developing the script, make sure to set the ``LD_LIBRARY_PATH`` environment variable to the
libs folder
*(limitation of the ultimateALPR SDK)*. *(limitation of the ultimateALPR SDK)*.
```bash ```bash
export LD_LIBRARY_PATH=libs:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=libs:$LD_LIBRARY_PATH
``` ```
### Error handling ### Error handling
#### GLIBC_ABI_DT_RELR not found #### GLIBC_ABI_DT_RELR not found
If you encounter an error like this: If you encounter an error like this:
```bash ```bash
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_ABI_DT_RELR' not found /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_ABI_DT_RELR' not found
``` ```
Then make sure your GLIBC version is >= 2.36 Then make sure your GLIBC version is >= 2.36

View File

@ -148,7 +148,7 @@ def create_rest_server_flask():
Parameters: Parameters:
- upload: The image to be processed - upload: The image to be processed
- grid_size: The number of cells to split the image into (e.g. 4) - grid_size: The number of cells to split the image into (e.g. 3)
- wanted_cells: The cells to process in the grid separated by commas (e.g. 1,2,3,4) (max: grid_size²) - wanted_cells: The cells to process in the grid separated by commas (e.g. 1,2,3,4) (max: grid_size²)
""" """
interference = time.time() interference = time.time()
@ -197,7 +197,7 @@ def create_rest_server_flask():
Parameters: Parameters:
- upload: The image to be processed - upload: The image to be processed
- grid_size: The number of cells to split the image into (e.g. 4) - grid_size: The number of cells to split the image into (e.g. 3)
- wanted_cells: The cells to process in the grid separated by commas (e.g. 1,2,3,4) (max: grid_size²) - wanted_cells: The cells to process in the grid separated by commas (e.g. 1,2,3,4) (max: grid_size²)
Returns: Returns: