├── .gitignore ├── images ├── placa1.jpg ├── placa2.jpg ├── placa3.JPG └── placa4.jpg ├── README.md ├── src ├── lib │ ├── format_output.py │ └── filters.py └── app.py └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .idea -------------------------------------------------------------------------------- /images/placa1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buemura/license-plate-recognition/HEAD/images/placa1.jpg -------------------------------------------------------------------------------- /images/placa2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buemura/license-plate-recognition/HEAD/images/placa2.jpg -------------------------------------------------------------------------------- /images/placa3.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buemura/license-plate-recognition/HEAD/images/placa3.JPG -------------------------------------------------------------------------------- /images/placa4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buemura/license-plate-recognition/HEAD/images/placa4.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CarPlate-Recognition 2 | Car Plate Recognition app using Python3 and cv2 library 3 | 4 | ## Technical Requirements 5 | In order to run this project, you will need to fulfill the following requirements. 6 | - Python 3 installation 7 | - Tesseract OCR installation 8 | - pip install cv2 9 | - pip install pytesseract 10 | - Import of numpy 11 | 12 | ## Setup 13 | Firstly you can clone by using the command below: 14 | 15 | ```bash 16 | git clone https://github.com/BrunoUemura/CarPlate-Recognition.git 17 | ``` 18 | 19 | Or download the zip file directly from [Github](https://github.com/BrunoUemura/CarPlate-Recognition.git) and unzip it. 20 | 21 | ### To run the project 22 | After the download is completed and the requirements are fulfilled, execute the file `./src/app.py`. 23 | -------------------------------------------------------------------------------- /src/lib/format_output.py: -------------------------------------------------------------------------------- 1 | import colorama 2 | from colorama import Fore, Style 3 | 4 | colorama.init() 5 | 6 | header = ['Image', 'Plate', 'Status'] 7 | 8 | 9 | def fixed_length(text, length): 10 | if len(text) > length: 11 | text = text[:length] 12 | elif len(text) < length: 13 | text = (text + " " * length)[:length] 14 | return text 15 | 16 | 17 | def format_output(data): 18 | print("━" * 70) 19 | print("┃", end=" ") 20 | for column in header: 21 | print(fixed_length(column, 20), end=" ┃ ") 22 | print() 23 | print("━" * 70) 24 | 25 | for row in data: 26 | print("┃", end=" ") 27 | for column in row: 28 | if column == 'AUTHORIZED': 29 | print(Fore.GREEN + fixed_length(column, 20) + Style.RESET_ALL, end=" ┃ ") 30 | elif column == 'NOT AUTHORIZED': 31 | print(Fore.RED + fixed_length(column, 20) + Style.RESET_ALL, end=" ┃ ") 32 | else: 33 | print(fixed_length(column, 20), end=" ┃ ") 34 | print() 35 | print("━" * 70) 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2021 Bruno Hideki Uemura 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /src/lib/filters.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import pytesseract 4 | 5 | try: 6 | from PIL import Image 7 | except ImportError: 8 | import Image 9 | pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract' 10 | 11 | 12 | # get grayscale image 13 | def get_grayscale(image): 14 | return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 15 | 16 | 17 | # noise removal 18 | def remove_noise(image): 19 | return cv2.medianBlur(image, 5) 20 | 21 | 22 | # thresholding 23 | def thresholding(image): 24 | return cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] 25 | 26 | 27 | # dilation 28 | def dilate(image): 29 | kernel = np.ones((5, 5), np.uint8) 30 | return cv2.dilate(image, kernel, iterations=1) 31 | 32 | 33 | # erosion 34 | def erode(image): 35 | kernel = np.ones((5, 5), np.uint8) 36 | return cv2.erode(image, kernel, iterations=1) 37 | 38 | 39 | # opening - erosion followed by dilation 40 | def opening(image): 41 | kernel = np.ones((5, 5), np.uint8) 42 | return cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel) 43 | 44 | 45 | # canny edge detection 46 | def canny(image): 47 | return cv2.Canny(image, 100, 200) 48 | -------------------------------------------------------------------------------- /src/app.py: -------------------------------------------------------------------------------- 1 | from os import walk 2 | import cv2 3 | from lib.filters import get_grayscale, thresholding, pytesseract 4 | from lib.format_output import format_output 5 | 6 | 7 | def apply_filter(plate): 8 | gray = get_grayscale(plate) 9 | thresh = thresholding(gray) 10 | return thresh 11 | 12 | 13 | def scan_plate(image): 14 | custom_config = r'-c tessedit_char_blacklist=abcdefghijklmnopqrstuvwxyz/ --psm 6' 15 | plate_number = (pytesseract.image_to_string(image, config=custom_config)) 16 | return plate_number[:-2] 17 | 18 | 19 | def validate_plate(plate_number, authorized_plate): 20 | if plate_number in authorized_plate: 21 | return 'AUTHORIZED' 22 | else: 23 | return 'NOT AUTHORIZED' 24 | 25 | 26 | def main(): 27 | authorized_plate = ['FUN-0972', 'BRA2E19'] 28 | 29 | images = [ 30 | '../images/placa1.jpg', 31 | '../images/placa2.jpg', 32 | '../images/placa3.jpg', 33 | '../images/placa4.jpg' 34 | ] 35 | 36 | plates = [] 37 | plates_filter_applied = [] 38 | plates_numbers = [] 39 | data = [] 40 | _, _, filenames = next(walk('../images/')) 41 | 42 | # Append the files name to list data 43 | for i in range(len(filenames)): 44 | data.append([]) 45 | data[i].append(filenames[i]) 46 | 47 | # Make an append to list plates 48 | for i in images: 49 | plates.append(cv2.imread(i)) 50 | 51 | # Calls the function apply_filter() passing the plate image 52 | for i in range(len(plates)): 53 | plates_filter_applied.append(apply_filter(plates[i])) 54 | 55 | # Calls the function scan_plate() passing the plate image with filter applied 56 | for i in range(len(plates_filter_applied)): 57 | plates_numbers.append(scan_plate(plates_filter_applied[i])) 58 | data[i].append(plates_numbers[i]) 59 | 60 | # Calls the function validate_plate() passing the plate number 61 | for i in range(len(plates_numbers)): 62 | data[i].append(validate_plate(plates_numbers[i], authorized_plate)) 63 | 64 | format_output(data) 65 | 66 | 67 | main() 68 | --------------------------------------------------------------------------------