Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions article-license-plate-number-detection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# License Plate Number Detection

## Article Summary

This article explores the foundational stage of License Plate Recognition (LPR) systems, focusing specifically on License Plate Number Detection (LPND)—the process of identifying the location and boundaries of a vehicle’s license plate within an image. It introduces several classic detection techniques, such as object contour analysis, segmented boundary analysis, and histogram-based methods, outlining their strengths, limitations, and use cases.

Furthermore, the article emphasizes the critical role of hardware quality (e.g., camera resolution and frame clarity) in ensuring reliable detection, before delving into a practical Python implementation. Although Optical Character Recognition (OCR) is mentioned as a later step in the LPR pipeline, the focus remains strictly on the detection phase.

By the end, readers gain both theoretical knowledge and hands-on tools to begin experimenting with LPND themselves.



## Getting Started

For this project, we will be using Python 3.11.4. Follow these steps to get started:

1. **Install Requirements**: Install the required packages from the `requirements.txt` file using the following command:

```sh
pip install -r requirements.txt
```

2. **Run the executable file**: Run the `main1.py` and `main2.py` files in your code editor to see the examples in action.

## Source Code Explanation

The code provided in this project demonstrates basic examples of traditional techniques used for **License Plate Number Detection (LPND)**. Here's a breakdown of the key components:

- `src/main1.py` and `src/main2.py`: These scripts contain test implementations of LPND methods discussed in the article.

- `img/testing/`: This directory holds the test images used to evaluate the detection algorithms.

363 changes: 363 additions & 0 deletions article-license-plate-number-detection/article.md

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions article-license-plate-number-detection/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
contourpy==1.3.2
cycler==0.12.1
fonttools==4.57.0
imutils==0.5.4
kiwisolver==1.4.8
matplotlib==3.10.1
numpy==2.2.5
opencv-python==4.11.0.86
packaging==25.0
pillow==11.2.1
pyparsing==3.2.3
python-dateutil==2.9.0.post0
six==1.17.0
67 changes: 67 additions & 0 deletions article-license-plate-number-detection/src/main1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import cv2
import matplotlib.pyplot as plt
import os
import imutils
import numpy as np


def main(img_path):

if not os.path.exists(img_path):
print(f"Error: File not found at {img_path}")
return
img = cv2.imread(img_path)
fig, axs = plt.subplots(3, 2, figsize=(8, 5))
fig.canvas.manager.set_window_title("License Plate Number Detection")

axs[0, 0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axs[0, 0].set_title("Original Image")
axs[0, 0].axis("off")

gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
bfilter = cv2.bilateralFilter(gray, 11, 17, 17)
axs[0, 1].imshow(cv2.cvtColor(bfilter, cv2.COLOR_BGR2RGB))
axs[0, 1].set_title("Processed Image")
axs[0, 1].axis("off")

edged = cv2.Canny(bfilter, 30, 200)
axs[1, 0].imshow(cv2.cvtColor(edged, cv2.COLOR_BGR2RGB))
axs[1, 0].set_title("Edge Detection")
axs[1, 0].axis("off")

keypoints = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(keypoints)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
location = None
for contour in contours:
approx = cv2.approxPolyDP(contour, 10, True)
if len(approx) == 4:
location = approx
break

else:
return

mask = np.zeros(gray.shape, np.uint8)
new_image = cv2.drawContours(mask, [location], 0, 255, -1)
# new_image = cv2.bitwise_and(img, img, mask=mask)

axs[1, 1].imshow(cv2.cvtColor(new_image, cv2.COLOR_BGR2RGB))
axs[1, 1].set_title("Masked Image")
axs[1, 1].axis("off")

x, y = np.where(mask == 255)
x1, y1 = (np.min(x), np.min(y))
x2, y2 = (np.max(x), np.max(y))
cropped_image = gray[x1 : x2 + 1, y1 : y2 + 1]

axs[2, 0].imshow(cv2.cvtColor(cropped_image, cv2.COLOR_BGR2RGB))
axs[2, 0].set_title("Cropped Image")
axs[2, 0].axis("off")
axs[2, 1].remove()

plt.show()


if __name__ == "__main__":
main(img_path="img/testing/img5.jpg")
77 changes: 77 additions & 0 deletions article-license-plate-number-detection/src/main2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import imutils

image_path = "img/testing/img5.jpg" # Drumul către fișierul cu imagine
image = cv2.imread(image_path)

image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

bilateral_filter = cv2.bilateralFilter(gray, 11, 17, 17)

# Convertăm iarăși din BGR în RGb rezultatul primit
bilateral_filter_rgb = cv2.cvtColor(bilateral_filter, cv2.COLOR_BGR2RGB)

plt.imshow(bilateral_filter_rgb)
plt.title("Bilateral Filter") # Setăm numele la grafic
plt.show() # Afișăm fereastra cu grafic


image_edged = cv2.Canny(bilateral_filter, 30, 200)

image_edged_rgb = cv2.cvtColor(image_edged, cv2.COLOR_BGR2RGB)

plt.imshow(image_edged_rgb)
plt.title("Edge Detection")
plt.show()


keypoints = cv2.findContours(image_edged, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(keypoints)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]

location = None # Locația la dreptunghi, dacă va fi detectat
for contour in contours:
approx = cv2.approxPolyDP(contour, 10, True)

if len(approx) == 4:
location = approx
break

print(location) # Afișăm locația detectată


mask = np.zeros(gray.shape, np.uint8)
image_masked = cv2.drawContours(mask, [location], 0, 255, -1)
image_masked = cv2.bitwise_and(image, image, mask=mask)

image_masked_rgb = cv2.cvtColor(image_masked, cv2.COLOR_BGR2RGB)

plt.imshow(image_masked_rgb)
plt.title("Masked Image")
plt.show()


x, y = np.where(
mask == 255
) # Extragem coordonatele care sunt de nuanța albă din imaginea mascată și le sepăram în x și y
x1, y1 = (
np.min(x),
np.min(y),
) # Selectăm coordonatele cu valorea minimă pentru a detecta un colț a dreptupunghiului
x2, y2 = (
np.max(x),
np.max(y),
) # Selectăm coordonatele cu valorea maximă pentru a detecta un colț a dreptupunghiului

image_cropped = gray[x1 : x2 + 1, y1 : y2 + 1]

image_cropped_rgb = cv2.cvtColor(image_cropped, cv2.COLOR_BGR2RGB)

plt.imshow(image_cropped_rgb)
plt.title("Cropped Image")
plt.show()