├── LICENSE
├── README.md
├── assets
├── 1.jpeg
├── 2.jpeg
├── 3.jpeg
├── 4.jpeg
├── 5.jpeg
├── 6.jpeg
├── hero.png
├── mit_block_1.png
├── mit_block_2.png
├── mit_design_1.JPG
├── mit_design_2.JPG
└── ocr.JPG
├── error_log.log
└── run.py
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Boudhayan Dev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |  [](https://www.python.org/) [](https://github.com/Naereen/StrapDown.js/blob/master/LICENSE) 
3 |
4 | Automatic Parking System is a parking solution designed for the modern establishments that want to manage their parking lot without human assistance. The proposed system consists of fully automated toll gates that control the entry and exit of the vechicles into and from the parking lot. It also features the ability to restrict the entry of blacklisted cars. The live status of the parking slots can be viewed through a mobile application designed for the system admins. The number plates of the cars are recorded on their entry/exit using OCR. The timing of their entry/exit, number plates and the number of empty slots are recorded and stored in database on every operation of the toll gates.
5 |
6 |
7 | #### Dependencies
8 |
9 | - Python 3.
10 | - Google Cloud Platform - Vision API.
11 | - OpenCV.
12 | - Raspberry Pi 3.
13 | - PiCamera.
14 | - MG995 servo motors x2.
15 | - IR modules x2.
16 | - Thingspeak.
17 | - Companion App.
18 |
19 |
20 | #### Usage
21 |
22 | - Connect the sensors to Raspberry Pi as follows.
23 |
24 | 1. IR sensor 1
to GPIO 16
.
25 | 2. IR sensor 2
to GPIO 18
.
26 | 3. Connect the PCA9865 driver via I2C connection.
27 | 4. Motor 1
to Pin 0
of PCA9685.
28 | 5. Motor 2
to Pin 15
of PCA9685.
29 | 5. Connect the PiCamera.
30 |
31 |
32 |
33 | - Replace the following line in run.py
with the Vision API credentials.
34 |
35 | os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'GCP_SERVICE_ACCOUNT_CREDENTIALS.json'
36 |
37 |
38 | - Create a Thingspeak Account and create a new project with the following fields.
39 | number_plate , slots_remaining , status
40 |
41 | - Create new project in MIT App inventor and create the following blocks.
42 |
43 |
44 |
45 |
46 |
47 | Design View of Screen 1
48 | |
49 |
50 |
51 |
Block View of Screen 1
52 | |
53 |
54 |
55 |
56 |
57 |
Design View of Screen 2
58 | |
59 |
60 |
61 | Block View of Screen 2
62 | |
63 |
64 |
65 |
66 | - Run the script on Raspberry Pi as follows
67 | python3 run.py
68 |
69 |
70 | #### Demonstration
71 |
72 | - The follwoing image shows the OCR operation
73 |
74 |
75 |
76 | - The following images show the live monitoring from the companion app.
77 |
78 |
79 |
80 |
81 |
82 | 1. Installation.
83 | |
84 |
85 |
86 | 2. Home Page.
87 | |
88 |
89 |
90 | 3. After Login.
91 | |
92 |
93 |
94 |
95 |
96 | 4. Current parking slots available.
97 | |
98 |
99 |
100 | 5. Downloading database.
101 | |
102 |
103 |
104 | 6. Database in .xls format.
105 | |
106 |
107 |
108 |
109 | © All rights reserved.
--------------------------------------------------------------------------------
/assets/1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/1.jpeg
--------------------------------------------------------------------------------
/assets/2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/2.jpeg
--------------------------------------------------------------------------------
/assets/3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/3.jpeg
--------------------------------------------------------------------------------
/assets/4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/4.jpeg
--------------------------------------------------------------------------------
/assets/5.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/5.jpeg
--------------------------------------------------------------------------------
/assets/6.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/6.jpeg
--------------------------------------------------------------------------------
/assets/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/hero.png
--------------------------------------------------------------------------------
/assets/mit_block_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/mit_block_1.png
--------------------------------------------------------------------------------
/assets/mit_block_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/mit_block_2.png
--------------------------------------------------------------------------------
/assets/mit_design_1.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/mit_design_1.JPG
--------------------------------------------------------------------------------
/assets/mit_design_2.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/mit_design_2.JPG
--------------------------------------------------------------------------------
/assets/ocr.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/assets/ocr.JPG
--------------------------------------------------------------------------------
/error_log.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boudhayan-dev/Automatic-Parking-System/bf17db2a16714839c5ecd4e16219c95e26ad90eb/error_log.log
--------------------------------------------------------------------------------
/run.py:
--------------------------------------------------------------------------------
1 | '''
2 | The following dependencies are imported.
3 |
4 | google.cloud ---> provides support for OCR.
5 | cv2 ---> Image Processing.
6 | '''
7 |
8 | import RPi.GPIO as GPIO
9 | import numpy as np
10 | from google.cloud import vision
11 | from google.cloud.vision import types
12 | import os,sys,logging,time,cv2,requests,Adafruit_PCA9685
13 | from picamera import PiCamera
14 |
15 | # Google Vision OCR Json file settings
16 | os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'GCP_SERVICE_ACCOUNT_CREDENTIALS.json'
17 |
18 | #Camera settings
19 | camera=PiCamera()
20 | camera.resolution=(512,512)
21 | camera.awb_mode="fluorescent"
22 | camera.iso = 800
23 | camera.contrast=25
24 | camera.brightness=50
25 | camera.sharpness=100
26 |
27 | #Ir sensor settings
28 | GPIO.setwarnings(False)
29 | GPIO.setmode(GPIO.BOARD)
30 | GPIO.setup(16,GPIO.IN) # Bigger IR to pin 16 and it is exit control sensor. Use OUT1 pin only. DO NOT use OUT2 pin.
31 | GPIO.setup(18,GPIO.IN) # Smaller IR to pin 18 and it is entry control sensor.
32 |
33 | #PCA9685 settings
34 | pwm = Adafruit_PCA9685.PCA9685()
35 | pwm.set_pwm_freq(50)
36 |
37 | #creating logging file
38 | logging.basicConfig(filename="error_log.log",level=logging.DEBUG)
39 |
40 | # parking slots and car count initialization
41 | count=0 # universal counter to keep a track of the number of ocr operations.
42 | empty_slots=10 # empty parking slots counter.
43 |
44 | # Helper function to control the opening of the gates.
45 | def gateOpen(pin,intial,final):
46 | for i in range(intial,final,1):
47 | pwm.set_pwm(pin,0,i)
48 | time.sleep(0.01)
49 |
50 | # Helper function to control the closing of the gates.
51 | def gateClose(pin,intial,final):
52 | for i in range(intial,final,-1):
53 | pwm.set_pwm(pin,0,i)
54 | time.sleep(0.01)
55 |
56 | # Gate control related functions.
57 | def openGate1():
58 | gateOpen(0,90,180)
59 |
60 | def closeGate1():
61 | gateClose(0,180,90)
62 |
63 | def openGate2():
64 | gateOpen(15,90,180)
65 |
66 | def closeGate2():
67 | gateClose(15,180,90)
68 |
69 |
70 | ''' A global database for criminal/illegal cars is updated.
71 | blacklist --->updates the list of illegal cars to be denied entry into the parking lot.
72 | '''
73 | def updateCriminalDatabase(number_plate):
74 | blacklist=requests.get("https://api.thingspeak.com/update?api_key=QDYY29TD1PPNWDIK&field1="+str(number_plate))
75 | if blacklist.status_code==str(200):
76 | print("Successfully updated the blacklist database.")
77 | else:
78 | logging.error(number_plate+"failed to be added in the blacklist database.")
79 |
80 |
81 | ''' Criminal Database is checked prior to granting parking space.
82 | Returns True if number is blacklisted.
83 | blacklist ---> receives the updated list of illegal cars to be denied entry into the parking lot.
84 | number_plate ---> The car license number that needs to be checked in the database.
85 | '''
86 | def checkCriminalDatabse(number_plate):
87 | blacklist=requests.get("https://api.thingspeak.com/channels/482414/fields/1.json?")
88 | blacklist=yaml.load(blacklist.text)
89 | for i in blacklist['feeds']:
90 | if (str(i['field1'])).lower()==number_plate.lower():
91 | return True
92 | return False
93 |
94 |
95 | '''
96 | The following function updates the database after every entry/exit.
97 | This database stores ----> Number plate of car entered/exited, entry/exit status and the current slots available after entry/exit
98 | It also stores those blacklisted cars that to enter the parking lot.
99 | '''
100 | def updateParkingDatabase(number_plate,occupied_slots,status):
101 | data={"api_key":"8RZ3DCTHQ6995PIE","field1":number_plate,"field2":occupied_slots,"field3":status}
102 | req=requests.post("https://api.thingspeak.com/update.json",data=data)
103 | if req.status_code==str(200):
104 | print("Succesfully updated the parking database.")
105 | else:
106 | logging.error(number_plate+"failed to be added in the parking database.")
107 |
108 |
109 | # The following function uses Raspberry Pi camera to capture the number Plate.
110 | def captureNumberPlate(filename):
111 | camera.start_preview()
112 | time.sleep(1)
113 | camera.capture(filename)
114 | camera.stop_preview()
115 | print("Captured number plate.")
116 |
117 | '''
118 | The following function is used to extract only the number plate from the image for better OCR response.
119 | Cannny edge detection is used to extract the image of the number plate from the car's body.
120 | Extracted number plate is saved as a new image and sent to Vision API for OCR detection.
121 | labels ---> receives the OCR output.
122 | '''
123 | def ocr(filename):
124 | captureNumberPlate(filename)
125 | client = vision.ImageAnnotatorClient()
126 | img = cv2.imread(filename)
127 |
128 | img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
129 | noise_removal = cv2.bilateralFilter(img_gray,7,85,85)
130 |
131 |
132 | ret,thresh_image = cv2.threshold(noise_removal,0,255,cv2.THRESH_OTSU+cv2.THRESH_BINARY)
133 | equalize= cv2.equalizeHist(thresh_image)
134 |
135 | canny_image = cv2.Canny(equalize,250,255)
136 | canny_image = cv2.convertScaleAbs(canny_image)
137 |
138 | kernel = np.ones((3,3), np.uint8)
139 | dilated_image = cv2.dilate(canny_image,kernel,iterations=3)
140 |
141 | new,contours, hierarchy = cv2.findContours(dilated_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
142 | contours= sorted(contours, key = cv2.contourArea, reverse = True)[:10]
143 |
144 | screenCnt = None
145 | for c in contours:
146 | peri = cv2.arcLength(c, True)
147 | approx = cv2.approxPolyDP(c, 0.06 * peri, True)
148 | if len(approx) == 4:
149 | screenCnt = approx
150 | break
151 | final = cv2.drawContours(img, [screenCnt], -1, (0, 255, 0), 3)
152 |
153 | mask = np.zeros(img_gray.shape,np.uint8)
154 | new_image = cv2.drawContours(mask,[screenCnt],0,255,-1,)
155 | new_image = cv2.bitwise_and(img,img,mask=mask)
156 |
157 | y,cr,cb = cv2.split(cv2.cvtColor(new_image,cv2.COLOR_RGB2YCrCb))
158 | y = cv2.equalizeHist(y)
159 | final_image = cv2.cvtColor(cv2.merge([y,cr,cb]),cv2.COLOR_YCrCb2RGB)
160 |
161 | cv2.imwrite("extracted"+filename,final_image)
162 |
163 | with open("extracted"+filename, 'rb') as image_file:
164 | content = image_file.read()
165 | print("Sending Image to OCR . . ")
166 |
167 | image = types.Image(content=content)
168 | response = client.document_text_detection(image=image)
169 | labels = response.full_text_annotation
170 |
171 | return labels.text # This returns the OCR number plates.
172 |
173 |
174 |
175 | # User prompt to update the blacklist databse on system start.
176 | updateBlacklist=input("Do you want to add a number to the blacklist database? Y/N : ")
177 | if updateBlacklist.lower()=="y" or updateBlacklist.lower()=="yes":
178 | blacklistNumber=str(input("Enter the blacklist number plate : ")).strip()
179 | updateCriminalDatabase(blacklistNumber)
180 |
181 | print("Total parking slots available ",str(empty_slots))
182 |
183 | '''
184 | GPIO 16 ---> IR connected to the exit gate.
185 | GPIO 18 ---> IR connected to the entry gate.
186 | The cars belonging to the criminal database are not allowed entry into the lot.
187 | '''
188 | try:
189 | while True:
190 | #exit control
191 | if(GPIO.input(16)==True) and empty_slots<10: # bigger IR signals True when object is near.
192 | count+=1
193 | filename="image"+str(count)+".jpg"
194 | empty_slots+=1
195 | openGate2() # open Gate 1 and let the car in if there are empty slots
196 | time.sleep(5)
197 | closeGate2()
198 | print("Processing number plate")
199 | text=str(ocr(filename)).strip()
200 | print("Detected car number - ",text)
201 | openGate1()
202 | time.sleep(5)
203 | closeGate1()
204 | print("Car exited succesfully to vehicle number - ",text)
205 | updateParkingDatabase(text,empty_slots,"exit") # updating thingspeak api with the data ---> Number plate , current slots in parking lot and extry/exit
206 | print("Remaining parking slots - "+str(empty_slots))
207 |
208 | #entry control
209 | if(GPIO.input(18)!=True) and empty_slots>0: # smaller IR signals false when object is near.
210 | openGate1()
211 | time.sleep(5)
212 | closeGate1()
213 | print("Processing number plate")
214 | count+=1
215 | filename="image"+str(count)+".jpg"
216 | text=str(ocr(filename)).strip()# ocr function will return the license plate as text
217 | print("Detected car number - ",text)
218 | if not checkCriminalDatabse(text):
219 | openGate2()
220 | time.sleep(5)
221 | closeGate2()
222 | print("Entry permitted succesfully to vehicle number - ",text)
223 | empty_slots-=1
224 | print("Reamaining slots -",str(empty_slots))
225 | updateParkingDatabase(text,empty_slots,"entry")
226 | print("Remaining parking slots - "+str(empty_slots))
227 | else:
228 | print("Sorry, this parking lot is only for law abiding citizens!")
229 | openGate1()
230 | time.sleep(5)
231 | closeGate1()
232 | print("Entry restricted succesfully to vehicle number - ",text)
233 | updateParkingDatabase(text,empty_slots,"rejected")
234 | print("Remaining parking slots - "+str(empty_slots))
235 | except Exception as e:
236 | print(e)
237 | GPIO.cleanup()
238 | print("Program ended.")
--------------------------------------------------------------------------------