Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
AtahanDuryaz authored Nov 6, 2024
1 parent 6076806 commit 6748a85
Show file tree
Hide file tree
Showing 6 changed files with 356 additions and 0 deletions.
Binary file added Database/ER Diagram.pdf
Binary file not shown.
82 changes: 82 additions & 0 deletions Database/car_park_management.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
DROP DATABASE car_park_management;

-- Create the Database
CREATE DATABASE IF NOT EXISTS car_park_management;
USE car_park_management;

-- Create Tables
CREATE TABLE IF NOT EXISTS cars (
car_plate VARCHAR(10) PRIMARY KEY,
is_staff BOOLEAN DEFAULT FALSE
);

CREATE TABLE IF NOT EXISTS car_entries (
id INT AUTO_INCREMENT PRIMARY KEY,
car_plate VARCHAR(10),
entry_time DATETIME NOT NULL,
exit_time DATETIME,
FOREIGN KEY (car_plate) REFERENCES cars(car_plate)
);

CREATE TABLE IF NOT EXISTS charges (
id INT AUTO_INCREMENT PRIMARY KEY,
car_plate VARCHAR(10),
entry_time DATETIME NOT NULL,
exit_time DATETIME NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (car_plate) REFERENCES cars(car_plate)
);

-- Insert Sample Data for Staff Cars
INSERT INTO cars (car_plate, is_staff) VALUES
('34ABC123', TRUE),
('34XYZ789', TRUE);

DROP PROCEDURE IF EXISTS log_entry;
DROP PROCEDURE IF EXISTS log_exit;

-- Procedures for Logging Entries and Exits and Calculating Charges
DELIMITER //

CREATE PROCEDURE log_entry(NEW_car_plate VARCHAR(10))
BEGIN
IF (SELECT COUNT(*) FROM cars WHERE car_plate = NEW_car_plate) = 0 THEN
INSERT INTO cars (car_plate) VALUES (NEW_car_plate);
END IF;
INSERT INTO car_entries (car_plate, entry_time) VALUES (NEW_car_plate, NOW());
END //

CREATE PROCEDURE log_exit(NEW_car_plate VARCHAR(10))
BEGIN
DECLARE entry_time DATETIME;
DECLARE is_staff BOOLEAN;
DECLARE total_hours INT;
DECLARE charge DECIMAL(10, 2);

SELECT entry_time INTO entry_time
FROM car_entries
WHERE car_plate = NEW_car_plate AND exit_time IS NULL
ORDER BY entry_time DESC LIMIT 1;

UPDATE car_entries
SET exit_time = NOW()
WHERE car_plate = NEW_car_plate AND exit_time IS NULL;

SELECT is_staff INTO is_staff
FROM cars
WHERE car_plate = NEW_car_plate;

IF is_staff = FALSE THEN
SET total_hours = TIMESTAMPDIFF(HOUR, entry_time, NOW());
IF total_hours = 0 THEN
SET charge = 50;
ELSE
SET charge = 50 + (total_hours * 20);
END IF;
INSERT INTO charges (car_plate, entry_time, exit_time, amount)
VALUES (NEW_car_plate, entry_time, NOW(), charge);
END IF;
END //


DELIMITER ;
211 changes: 211 additions & 0 deletions car_plate_inference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import requests
from PIL import Image
import pytesseract
import cv2
import numpy as np
import os
import re
from dotenv import load_dotenv
import mysql.connector
from mysql.connector import Error

load_dotenv() # Loads variables from .env file

# Roboflow API details
API_KEY = os.getenv('API_KEY')
PROJECT_ID = os.getenv('PROJECT_ID')
VERSION = os.getenv('VERSION')

def detect_car_plate(image_path):

# Detects car plate in an image using Roboflow API.

try:
with open(image_path, 'rb') as image_file:
response = requests.post(
f"https://detect.roboflow.com/{PROJECT_ID}/{VERSION}",
params={"api_key": API_KEY},
files={"file": image_file}
)
response.raise_for_status() # Raise an HTTPError if the response was unsuccessful
response_json = response.json()
return response_json
except requests.exceptions.RequestException as e:
print(f"Error during API request: {e}")
return None

def extract_plate_info(predictions):

# Extract bounding box information from predictions.

if not predictions:
print("No predictions found in the response.")
return None

for prediction in predictions:
x, y, width, height = (prediction['x'], prediction['y'], prediction['width'], prediction['height'])
print(f"Bounding Box - x: {x}, y: {y}, width: {width}, height: {height}")

# Adjusting the bounding box slightly to ensure the plate is fully captured
padding_x = 10 # Slight horizontal padding
padding_y = 5 # Slight vertical padding

x_min = int(x - width / 2) - padding_x
y_min = int(y - height / 2) - padding_y
x_max = int(x + width / 2) + padding_x
y_max = int(y + height / 2) + padding_y

return (x_min, y_min, x_max, y_max)

return None

def preprocess_image(image):

# Preprocess the image to enhance OCR accuracy.

try:
gray_image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
_, thresh_image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
return thresh_image
except Exception as e:
print(f"Error during image preprocessing: {e}")
return None

def crop_image(image_path, bounding_box):

# Crop the detected car plate area from the image.

try:
image = Image.open(image_path)
cropped_image = image.crop(bounding_box)
cropped_image.show()
return cropped_image
except Exception as e:
print(f"Error cropping image: {e}")
return None

def extract_plate_number(cropped_image):

# Apply OCR to extract the car plate number from the cropped image.

try:
preprocessed_image = preprocess_image(cropped_image)
plate_number = pytesseract.image_to_string(preprocessed_image, config='--psm 7')
plate_number = plate_number.strip()

# Remove any non-alphanumeric characters (except spaces)
plate_number = ''.join(char if char.isalnum() or char.isspace() else '' for char in plate_number)

# Use regex to match the extracted plate number to one of the known Turkish plate patterns
plate_pattern = re.compile(r'''
^(\d{2})\s?([A-Z]{1,3})\s?(\d{2,5})$ # Matches all Turkish plate formats
''', re.VERBOSE)

match = plate_pattern.search(plate_number)
if match:
# Format the plate number consistently
formatted_plate = f"{match.group(1)} {match.group(2)} {match.group(3)}"
return formatted_plate
else:
# Attempt to fix common OCR errors
if len(plate_number) > 2 and not plate_number[:2].isdigit():
plate_number = plate_number[1:] # Remove the first character if it's incorrect

match = plate_pattern.search(plate_number)
if match:
formatted_plate = f"{match.group(1)} {match.group(2)} {match.group(3)}"
return formatted_plate
else:
print("No valid plate pattern detected. Returning the adjusted OCR output.")
return plate_number
except Exception as e:
print(f"Error during OCR extraction: {e}")
return None

def create_connection():

# Establish a connection to the MySQL database.

try:
connection = mysql.connector.connect(
host = os.getenv('HOST'),
database = os.getenv('DATABASE'),
user = os.getenv('ROOT'),
password = os.getenv('PASSWORD'),
port = os.getenv('PORT')
)
if connection.is_connected():
print("Connected to MySQL database")
return connection
except Error as e:
print(f"Error connecting to MySQL: {e}")
return None

def log_car_entry(connection, plate_number):

# Log the car entry into the database.

try:
cursor = connection.cursor()
cursor.callproc('log_entry', [plate_number])
connection.commit()
print(f"Logged entry for plate number: {plate_number}")
except Error as e:
print(f"Error logging car entry: {e}")

def log_car_exit(connection, plate_number):

# Log the car exit into the database.

try:
cursor = connection.cursor()
cursor.callproc('log_exit', [plate_number])
connection.commit()
print(f"Logged exit for plate number: {plate_number}")
except Error as e:
print(f"Error logging car exit: {e}")

def main(image_path):

# Main function to process the image and log the car entry or exit.

response_json = detect_car_plate(image_path)
if response_json and 'predictions' in response_json:
bounding_box = extract_plate_info(response_json['predictions'])
if bounding_box:
cropped_image = crop_image(image_path, bounding_box)
if cropped_image:
plate_number = extract_plate_number(cropped_image)
if plate_number:
print(f"Extracted Plate Number: {plate_number}")

# Establish database connection
connection = create_connection()
if connection:
cursor = connection.cursor()

# Check if the plate number already exists in car_entries with null exit_time
cursor.execute("SELECT COUNT(*) FROM car_entries WHERE car_plate = %s AND exit_time IS NULL", (plate_number,))
count = cursor.fetchone()[0]

if count > 0:
# If exit log
log_car_exit(connection, plate_number)
else:
# If entry log
log_car_entry(connection, plate_number)

connection.close()
else:
print("OCR failed to extract a plate number. The image might be too blurry or the plate might not be clearly visible.")
else:
print("Failed to crop the image. The bounding box might be incorrect.")
else:
print("No license plate detected in the image.")
else:
print("No predictions or invalid response from the API.")


if __name__ == "__main__":
IMAGE_PATH = "test3.jpg"
main(IMAGE_PATH)
28 changes: 28 additions & 0 deletions data_take.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import serial
import requests

# Serial setup
ser = serial.Serial('COM9', 9600) # Replace with your correct COM port

# PHP script URL
url = "http://localhost/insert_data.php" # Change to your actual URL

while True:
# Read data from serial port
data = ser.readline().decode('utf-8').strip()
print(f"Received: {data}")

# Parse spot name, distance, and parking status from the Arduino serial output
if "Spot Name" in data and "Distance" in data and "Parked" in data:
# Extract the values from the received data
parts = data.split(", ")
spot_name = parts[0].split(": ")[1] # Extract spot name
distance = parts[1].split(": ")[1].split(" ")[0] # Extract distance value
is_parked = parts[2].split(": ")[1] # Extract parked status (0 or 1)

# Send data to PHP script
payload = {'spot_name': spot_name, 'distance': distance, 'is_parked': is_parked}
response = requests.get(url, params=payload)

# Print response from PHP script
print(response.text)
34 changes: 34 additions & 0 deletions insert_data.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
$servername = "localhost";
$username = "root"; // MySQL kullanıcı adı
$password = ""; // MySQL şifresi
$dbname = "park_database"; // Veritabanı adı

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}

// Get data from the GET request
if (isset($_GET['spot_name']) && isset($_GET['distance']) && isset($_GET['is_parked'])) {
$spot_name = $_GET['spot_name'];
$distance = $_GET['distance'];
$isParked = $_GET['is_parked'];

// Insert data into MySQL database
$sql = "INSERT INTO parking_data (spot_name, distance, is_parked) VALUES ('$spot_name', '$distance', '$isParked')";

if ($conn->query($sql) === TRUE) {
echo "New record created successfully";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
} else {
echo "Data not received!";
}

$conn->close();
?>
1 change: 1 addition & 0 deletions tempCodeRunnerFile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
API_KEY = os.getenv('API_KEY')

0 comments on commit 6748a85

Please sign in to comment.