-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update carspeed.py #14
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,38 @@ | ||
# CarSpeed Version 2.0 | ||
# Speed Version 2.0 | ||
|
||
#changes by KirkLoeten (GITHUB) | ||
# paramter for function [cv2.findContours ] form 3 to 2 - cnts, _ | ||
# Functions: | ||
# Selector image 0 - off, 0 > speedlimit | ||
# Selector csv 0 - off, 0 > speedlimit | ||
# Selector of units m / ft -> kmh / mph | ||
# read setup monitored area by setup.txt file, write a new file by use 'c' in setup | ||
# Generate new CSV at new Day | ||
# generate folders per Day | ||
# Nice to have: set central text color for all images | ||
|
||
# import the necessary packages | ||
from picamera.array import PiRGBArray | ||
from picamera import PiCamera | ||
import time | ||
import math | ||
import datetime | ||
import cv2 | ||
import os | ||
import cv2 # sudo apt-get install libopencv-dev python-opencv | ||
|
||
# place a prompt on the displayed image | ||
def prompt_on_image(txt): | ||
global image | ||
cv2.putText(image, txt, (10, 35), | ||
cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1) | ||
cv2.putText(image, txt, (10, 35), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 255, 127, 1)) | ||
|
||
# calculate speed from pixels and time | ||
def get_speed(pixels, ftperpixel, secs): | ||
if secs > 0.0: | ||
return ((pixels * ftperpixel)/ secs) * 0.681818 | ||
if SPEED_UNIT == "mph": | ||
return ((pixels * unit_perpixel)/ secs) * 0.681818 | ||
else: | ||
#m/s to km/h | ||
return ((pixels * unit_perpixel)/ (secs) ) * 3.6 | ||
else: | ||
return 0.0 | ||
|
||
|
@@ -54,34 +69,43 @@ def draw_rectangle(event,x,y,flags,param): | |
prompt_on_image(prompt) | ||
cv2.rectangle(image,(ix,iy),(fx,fy),(0,255,0),2) | ||
|
||
# define some constants | ||
DISTANCE = 76 #<---- enter your distance-to-road value here | ||
MIN_SPEED = 0 #<---- enter the minimum speed for saving images | ||
SAVE_CSV = False #<---- record the results in .csv format in carspeed_(date).csv | ||
# define some constants, selectors | ||
DISTANCE = 10 #<---- enter your distance-to-road value here | ||
SAVE_CSV = 25 #0 is off, >0 is the speedlimit, record the results in .csv format in speed_(date).csv | ||
SAVE_IMAGE = 25 #0 is off, >0 is the speedlimit, no image as privaty setup | ||
LEN_UNIT = "m" # "ft" or "m" (mph or km/h is selected automaticly by this constant) | ||
|
||
THRESHOLD = 15 | ||
MIN_AREA = 175 | ||
#picture and difference parameter | ||
THRESHOLD = 50 #15 | ||
MIN_AREA = 175 | ||
BLURSIZE = (15,15) | ||
IMAGEWIDTH = 640 | ||
IMAGEHEIGHT = 480 | ||
RESOLUTION = [IMAGEWIDTH,IMAGEHEIGHT] | ||
FOV = 53.5 #<---- Field of view | ||
FPS = 30 | ||
SHOW_BOUNDS = True | ||
SHOW_IMAGE = True | ||
SHOW_BOUNDS = False | ||
SHOW_IMAGE = False | ||
|
||
if LEN_UNIT.upper() == "ft".upper(): #ignore case, compare string upper letters | ||
SPEED_UNIT = "mph" | ||
else: | ||
SPEED_UNIT = "km/h" | ||
|
||
# the following enumerated values are used to make the program more readable | ||
# state | ||
WAITING = 0 | ||
TRACKING = 1 | ||
SAVING = 2 | ||
# dicection | ||
UNKNOWN = 0 | ||
LEFT_TO_RIGHT = 1 | ||
RIGHT_TO_LEFT = 2 | ||
|
||
# calculate the the width of the image at the distance specified | ||
frame_width_ft = 2*(math.tan(math.radians(FOV*0.5))*DISTANCE) | ||
ftperpixel = frame_width_ft / float(IMAGEWIDTH) | ||
print("Image width in feet {} at {} from camera".format("%.0f" % frame_width_ft,"%.0f" % DISTANCE)) | ||
frame_width_unit = 2*(math.tan(math.radians(FOV*0.5))*DISTANCE) | ||
unit_perpixel = frame_width_unit / float(IMAGEWIDTH) | ||
print("Image width in {} {} at {} {} from camera".format( "%.0f" % frame_width_unit, LEN_UNIT, "%.0f" % DISTANCE, LEN_UNIT)) | ||
|
||
# state maintains the state of the speed computation process | ||
# if starts as WAITING | ||
|
@@ -105,16 +129,15 @@ def draw_rectangle(event,x,y,flags,param): | |
#-- other values used in program | ||
base_image = None | ||
abs_chg = 0 | ||
mph = 0 | ||
speed = 0 | ||
secs = 0.0 | ||
ix,iy = -1,-1 | ||
fx,fy = -1,-1 | ||
drawing = False | ||
setup_complete = False | ||
tracking = False | ||
text_on_image = 'No cars' | ||
text_on_image = 'No motions' | ||
prompt = '' | ||
|
||
# initialize the camera. Adjust vflip and hflip to reflect your camera's orientation | ||
camera = PiCamera() | ||
camera.resolution = RESOLUTION | ||
|
@@ -139,13 +162,13 @@ def draw_rectangle(event,x,y,flags,param): | |
rawCapture.truncate(0) | ||
org_image = image.copy() | ||
|
||
if SAVE_CSV: | ||
csvfileout = "carspeed_{}.cvs".format(datetime.datetime.now().strftime("%Y%m%d_%H%M")) | ||
record_speed('Date,Day,Time,Speed,Image') | ||
else: | ||
csvfileout = '' | ||
|
||
prompt = "Define the monitored area - press 'c' to continue" | ||
setup_exist = os.path.isfile("setup.txt") | ||
if setup_exist: | ||
prompt = "Define the monitored area - press 'c' to continue - press 'L' for lastsetup" | ||
else: | ||
prompt = "Define the monitored area - press 'c' to continue" | ||
#test for setup.txt file | ||
prompt_on_image(prompt) | ||
|
||
# wait while the user draws the monitored area's boundry | ||
|
@@ -158,10 +181,29 @@ def draw_rectangle(event,x,y,flags,param): | |
# if the `c` key is pressed, break from the loop | ||
if key == ord("c"): | ||
break | ||
|
||
# if the `l` key is pressed, use last setup | ||
if (key == ord("L") or key == ord("l")) and setup_exist: | ||
with open("setup.txt", 'r') as f: | ||
setup_txt = f.readlines() | ||
f.close | ||
for line in setup_txt: | ||
line = line.strip() | ||
line = line.split("=") | ||
if line[0] == "ix": | ||
ix = int(line[1]) | ||
if line[0] == "iy": | ||
iy = int(line[1]) | ||
if line[0] == "fx": | ||
fx = int(line[1]) | ||
if line[0] == "fy": | ||
fy = int(line[1]) | ||
break | ||
|
||
|
||
# the monitored area is defined, time to move on | ||
prompt = "Press 'q' to quit" | ||
prompt_on_image(prompt) | ||
# since the monitored area's bounding box could be drawn starting | ||
# from any corner, normalize the coordinates | ||
|
||
|
@@ -183,14 +225,23 @@ def draw_rectangle(event,x,y,flags,param): | |
monitored_height = lower_right_y - upper_left_y | ||
|
||
print("Monitored area:") | ||
print(" upper_left_x {}".format(upper_left_x)) | ||
print(" upper_left_y {}".format(upper_left_y)) | ||
print(" lower_right_x {}".format(lower_right_x)) | ||
print(" lower_right_y {}".format(lower_right_y)) | ||
print(" monitored_width {}".format(monitored_width)) | ||
print(" monitored_height {}".format(monitored_height)) | ||
print(" monitored_area {}".format(monitored_width * monitored_height)) | ||
print(" upper_left_x {} px".format(upper_left_x)) | ||
print(" upper_left_y {} px".format(upper_left_y)) | ||
print(" lower_right_x {} px".format(lower_right_x)) | ||
print(" lower_right_y {} px".format(lower_right_y)) | ||
print(" monitored_width {0:d} px ({1:.2f} {2:s})".format(monitored_width, frame_width_unit, LEN_UNIT)) | ||
print(" monitored_height {} px".format(monitored_height)) | ||
print(" monitored_area {} px".format(monitored_width * monitored_height)) | ||
|
||
# save setup | ||
if (monitored_width > 10 and monitored_height > 10): | ||
with open("setup.txt", 'w') as f: | ||
f.write("ix="+str(upper_left_x)+"\n") | ||
f.write("iy="+str(upper_left_y)+"\n") | ||
f.write("fx="+str(lower_right_x)+"\n") | ||
f.write("fy="+str(lower_right_y)+"\n") | ||
f.close | ||
|
||
# capture frames from the camera (using capture_continuous. | ||
# This keeps the picamera in capture mode - it doesn't need | ||
# to prep for each frame's capture. | ||
|
@@ -225,7 +276,7 @@ def draw_rectangle(event,x,y,flags,param): | |
# dilate the thresholded image to fill in any holes, then find contours | ||
# on thresholded image | ||
thresh = cv2.dilate(thresh, None, iterations=2) | ||
(_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) | ||
cnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this needs to be "_, cnts, _ =" for it to work without a "too many values to unpack" error. |
||
|
||
# look for motion | ||
motion_found = False | ||
|
@@ -252,18 +303,18 @@ def draw_rectangle(event,x,y,flags,param): | |
initial_x = x | ||
last_x = x | ||
initial_time = timestamp | ||
last_mph = 0 | ||
last_speed = 0 | ||
text_on_image = 'Tracking' | ||
print(text_on_image) | ||
print("x-chg Secs MPH x-pos width") | ||
print("x-chg Secs {} dir x-pos width".format(SPEED_UNIT)) | ||
else: | ||
# compute the lapsed time | ||
secs = secs_diff(timestamp,initial_time) | ||
|
||
if secs >= 15: | ||
state = WAITING | ||
direction = UNKNOWN | ||
text_on_image = 'No Car Detected' | ||
text_on_image = 'No motion detected' | ||
motion_found = False | ||
biggest_area = 0 | ||
rawCapture.truncate(0) | ||
|
@@ -278,61 +329,74 @@ def draw_rectangle(event,x,y,flags,param): | |
else: | ||
direction = RIGHT_TO_LEFT | ||
abs_chg = initial_x - x | ||
mph = get_speed(abs_chg,ftperpixel,secs) | ||
print("{0:4d} {1:7.2f} {2:7.0f} {3:4d} {4:4d}".format(abs_chg,secs,mph,x,w)) | ||
speed = get_speed(abs_chg,unit_perpixel,secs) | ||
|
||
print("{0:4d} {1:7.2f} {2:7.0f} {3:1d} {4:4d} {5:4d}".format(abs_chg,secs,speed, direction,x,w)) | ||
real_y = upper_left_y + y | ||
real_x = upper_left_x + x | ||
# is front of object outside the monitired boundary? Then write date, time and speed on image | ||
# and save it | ||
if ((x <= 2) and (direction == RIGHT_TO_LEFT)) \ | ||
or ((x+w >= monitored_width - 2) \ | ||
and (direction == LEFT_TO_RIGHT)): | ||
if (last_mph > MIN_SPEED): # save the image | ||
if (last_speed > SAVE_CSV or last_speed > SAVE_IMAGE): # save the image | ||
# timestamp the image | ||
cv2.putText(image, datetime.datetime.now().strftime("%A %d %B %Y %I:%M:%S%p"), | ||
(10, image.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1) | ||
cv2.putText(image, timestamp.strftime("%A %d %B %Y %H:%M:%S"), | ||
(10, image.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 127), 1) | ||
# write the speed: first get the size of the text | ||
size, base = cv2.getTextSize( "%.0f mph" % last_mph, cv2.FONT_HERSHEY_SIMPLEX, 2, 3) | ||
size, base = cv2.getTextSize( "{0:.0f} {1:s}".format(last_speed, SPEED_UNIT), cv2.FONT_HERSHEY_SIMPLEX, 2, 3) | ||
# then center it horizontally on the image | ||
cntr_x = int((IMAGEWIDTH - size[0]) / 2) | ||
cv2.putText(image, "%.0f mph" % last_mph, | ||
(cntr_x , int(IMAGEHEIGHT * 0.2)), cv2.FONT_HERSHEY_SIMPLEX, 2.00, (0, 255, 0), 3) | ||
# and save the image to disk | ||
imageFilename = "car_at_" + datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + ".jpg" | ||
# use the following image file name if you want to be able to sort the images by speed | ||
#imageFilename = "car_at_%02.0f" % last_mph + "_" + datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + ".jpg" | ||
cv2.putText(image, "{0:.0f} {1:s}".format(last_speed, SPEED_UNIT), | ||
(cntr_x , int(IMAGEHEIGHT * 0.2)), cv2.FONT_HERSHEY_SIMPLEX, 2.00, (0, 255, 127), 3) | ||
# and save to disk | ||
# check folder | ||
folder = "{}".format(datetime.datetime.now().strftime("%Y%m%d")) | ||
if not os.path.exists(folder): | ||
os.makedirs(folder) | ||
csvfileout = folder + "/speed_{}.cvs".format(timestamp.strftime("%Y%m%d")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be .csv |
||
record_speed("Date, Time, Speed ({}), Richtung (1>, 2<), Image".format(SPEED_UNIT)) | ||
else: | ||
#Initial | ||
csvfileout = folder + "/speed_{}.cvs".format(datetime.datetime.now().strftime("%Y%m%d")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be .csv |
||
|
||
|
||
if (last_speed > SAVE_IMAGE): | ||
imageFilename = folder + "/motion_at_" + timestamp.strftime("%Y%m%d_%H%M%S") + ".jpg" | ||
# use the following image file name if you want to be able to sort the images by speed | ||
#imageFilename = "motion_at_%02.0f" % last_speed + "_" + datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + ".jpg" | ||
|
||
cv2.imwrite(imageFilename,image) | ||
if SAVE_CSV: | ||
cap_time = datetime.datetime.now() | ||
record_speed(cap_time.strftime("%Y.%m.%d")+','+cap_time.strftime('%A')+','+\ | ||
cap_time.strftime('%H%M')+','+("%.0f" % last_mph) + ','+imageFilename) | ||
cv2.imwrite(imageFilename,image) | ||
else: | ||
imageFilename = "No image" | ||
if (last_speed > SAVE_CSV): | ||
record_speed(timestamp.strftime("%Y.%m.%d")+','+ timestamp.strftime('%H:%M')+','+("%.0f" % last_speed) + ',' + ("%d" % direction) + ','+imageFilename) | ||
state = SAVING | ||
# if the object hasn't reached the end of the monitored area, just remember the speed | ||
# and its last position | ||
last_mph = mph | ||
last_speed = speed | ||
last_x = x | ||
else: | ||
if state != WAITING: | ||
state = WAITING | ||
direction = UNKNOWN | ||
text_on_image = 'No Car Detected' | ||
text_on_image = 'No motion detected' | ||
print(text_on_image) | ||
|
||
# only update image and wait for a keypress when waiting for a car | ||
# only update image and wait for a keypress when waiting for a motion | ||
# This is required since waitkey slows processing. | ||
if (state == WAITING): | ||
|
||
# draw the text and timestamp on the frame | ||
cv2.putText(image, datetime.datetime.now().strftime("%A %d %B %Y %I:%M:%S%p"), | ||
(10, image.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1) | ||
cv2.putText(image, datetime.datetime.now().strftime("%A %d %B %Y %H:%M:%S"), | ||
(10, image.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 127), 1) | ||
cv2.putText(image, "Road Status: {}".format(text_on_image), (10, 20), | ||
cv2.FONT_HERSHEY_SIMPLEX,0.35, (0, 0, 255), 1) | ||
cv2.FONT_HERSHEY_SIMPLEX,0.5, (0, 255, 127), 1) | ||
|
||
if SHOW_BOUNDS: | ||
#define the monitored area right and left boundary | ||
cv2.line(image,(upper_left_x,upper_left_y),(upper_left_x,lower_right_y),(0, 255, 0)) | ||
cv2.line(image,(lower_right_x,upper_left_y),(lower_right_x,lower_right_y),(0, 255, 0)) | ||
cv2.line(image,(upper_left_x,upper_left_y),(upper_left_x,lower_right_y),(0, 255, 127)) | ||
cv2.line(image,(lower_right_x,upper_left_y),(lower_right_x,lower_right_y),(0, 255, 127)) | ||
|
||
# show the frame and check for a keypress | ||
if SHOW_IMAGE: | ||
|
@@ -356,4 +420,3 @@ def draw_rectangle(event,x,y,flags,param): | |
|
||
# cleanup the camera and close any open windows | ||
cv2.destroyAllWindows() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo 'automatically'