diff --git a/config.py b/config.py index 0ec8e2d..c3969c4 100644 --- a/config.py +++ b/config.py @@ -1,5 +1,5 @@ # ---------------- User Configuration Settings for speed-cam.py --------------------------- -# Ver 13.08 speed-cam.py Variable Configuration Settings +# Ver 13.13 speed-cam.py Variable Configuration Settings ####################################### # speed-cam.py Variable Settings @@ -9,20 +9,23 @@ # to change resolution. ####################################### -# IMPORTANT: Camera settings are now stored in configcam.py -# This was done to allow camera code to be more portable - # Calibration Settings # -------------------- -CALIBRATE_ON = True # Create a calibration image file with calibration hash markers 10 px per mark +CALIBRATE_ON = True # Create a calibration image file with calibration hash markers 10 px per mark +CAL_OBJ_PX_L2R = 80 # L2R Moving Objects, Length of a calibration object in pixels +CAL_OBJ_MM_L2R = 4700 # L2R Moving Objects, Length of the calibration object in millimetres +CAL_OBJ_PX_R2L = 85 # R2L Moving Objects, Length of a calibration object in pixels +CAL_OBJ_MM_R2L = 4700 # R2L Moving Objects, Length of the calibration object in millimetres +# Note if tested speed is too low increase appropriate cal_obj_mm value and redo speed test for desired direction. +# IMPORTANT - If plugins Enabled Edit Settings in specified plugin file located in plugins folder. +# Align Camera Settings ALIGN_CAM_ON = False # Default=False True Saves alignment image to help with camera pointing ALIGN_DELAY_SEC = 3 # Default=3 seconds delay between each alignment image in recent folder -SHOW_SETTINGS_ON = False # True Displays the config.py file on startup - # Display and Log settings # ------------------------ +SHOW_SETTINGS_ON = False # True Displays the config.py file on startup LOG_VERBOSE_ON = True # True= Display basic status information on console False= Off LOG_DATA_TO_CSV = False # True= Save log data as CSV comma separated values False= Off LOG_TO_FILE_ON = False # True= Send logging to file False= No Logging to File @@ -33,11 +36,9 @@ # --------------- CAMERA = "pilibcam" # valid values usbcam, rtspcam, pilibcam, pilegcam CAM_LOCATION = "Front Window" - USBCAM_SRC = 0 # Device number of USB connection usually 0, 1, 2, Etc RTSPCAM_SRC = "rtsp://user:password@IP:554/path" # Set per IP Cam Docs and config see example below # rtsp://admin:mypwd@192.168.1.100:554/12 - # Camera Image Stream Settings IM_SIZE = (320, 240) # Image resolution width, height pixels IM_VFLIP = False # True enables flipping image vertically @@ -45,42 +46,43 @@ IM_ROTATION = 0 # Rotate camera image valid values are 0, 90, 180, 270 IM_FRAMERATE = 30 # Legacy Picamera Framerate -# Calibration Settings -# -------------------- -CAL_OBJ_PX_L2R = 80 # L2R Moving Objects, Length of a calibration object in pixels -CAL_OBJ_MM_L2R = 4700 # L2R Moving Objects, Length of the calibration object in millimetres - -CAL_OBJ_PX_R2L = 85 # R2L Moving Objects, Length of a calibration object in pixels -CAL_OBJ_MM_R2L = 4700 # R2L Moving Objects, Length of the calibration object in millimetres - -# Note if tested speed is too low increase appropriate cal_obj_mm value and redo speed test for desired direction. -# IMPORTANT - If plugins Enabled Edit Settings in specified plugin file located in plugins folder. - -# Plugins override the specified config.py variable settings -# ---------------------------------------------------------- -PLUGIN_ENABLE_ON = False # True enables import of the specified PLUGIN_NAME -PLUGIN_NAME = "picam240" # Specify filename in plugins subfolder without .py extension per below - # picam240, webcam240 (Recommended for RPI2 or greater) - # picam480, webcam480, rtsp352, picam720, webcam720 (can use RPI3 but Test) - # picam1080 (Experimental Not Recommended) - # secpicam480, secwebcam480 (Experimental no CSV entries) +# Image Settings +# -------------- +IM_DIR_PATH = "media/images" # folder name to store images +IM_PREFIX = "speed-" # image name prefix +IM_FORMAT_EXT = ".jpg" # Default = ".jpg" image Formats .jpg .jpeg .png .gif .bmp +IM_JPG_QUALITY = 98 # Set the quality of the jpeg. Default = 95 + # https://docs.opencv.org/3.4/d8/d6a/group__imgcodecs__flags.html#ga292d81be8d76901bff7988d18d2b42ac +IM_JPG_OPTIMIZE_ON = True # Optimize the image. Default = False + # https://docs.opencv.org/3.4/d8/d6a/group__imgcodecs__flags.html#ga292d81be8d76901bff7988d18d2b42ac +IM_SHOW_SPEED_FILENAME_ON = True # True= Include speed value in filename +IM_SHOW_CROP_AREA_ON = False # True= Display motion detection rectangle area on saved images +IM_BIGGER = 3.0 # Default= 3.0 min=0.1 Resize saved speed image by specified multiplier value +IM_SHOW_TEXT_ON = True # True= Show Text on speed images False= No Text on images +IM_SHOW_TEXT_BOTTOM_ON = True # True= Show image text at bottom otherwise at top +IM_FONT_SIZE_PX = 12 # Default= 12 Font text height in px for text on images +IM_FONT_SCALE = 0.5 # Default= 0.5 Font scale factor that is multiplied by the font-specific base size. +IM_FONT_THICKNESS = 2 # Default= 2 Font text thickness in px for text on images +IM_FONT_COLOR = (255, 255, 255) # Default= (255, 255, 255) White +IM_MAX_FILES = 0 # 0=off or specify MaxFiles to maintain then oldest are deleted Default=0 (off) -# Display opencv windows on gui desktop -# GUI_WINDOW_ON suppresses All Windows if False -# ---------------------------------------------- -GUI_WINDOW_ON = False # True= Turn On All desktop GUI openCV windows. False=Don't Show (req'd for SSH) . -GUI_IMAGE_WIN_ON = True # True=Show the camera on a gui windows. False=Don't Show (useful for image_sign) -GUI_THRESH_WIN_ON = False # True=Show openCV cropped BLUR, THRESHOLD grayscale image window. Used for detecting movement contours -GUI_CROP_WIN_ON = False # True=Show crop window. Same as GUI_THRESH_WIN_ON but in color. +# AI Settings +# ------------ +IM_SAVE_4AI_ON = False # will save small colour image for later AI processing +IM_SAVE_4AI_POS_DIR = "media/ai/pos" # Save positive ai images after tracking completed +IM_SAVE_4AI_NEG_DIR = "media/ai/neg" # Save negative ai images (no motion detected) +IM_SAVE_4AI_NEG_TIMER_SEC = 60 * 60 * 6 # Save a non positive image every specified seconds +IM_FIRST_AND_LAST_ON = False # Save and process first and last tracking images (NOT Fully Implemented) -# OpenCV Motion Settings -# ---------------------- -CV_SHOW_CIRCLE_ON = False # True=circle in center of motion, False=rectangle -CV_CIRCLE_SIZE_PX = 5 # Default= 5 Diameter circle in px if CV_SHOW_CIRCLE_ON = True -CV_LINE_WIDTH_PX = 1 # Default= 1 Size of lines for circle or Rectangle -CV_WINDOW_BIGGER = 1.0 # Default= 1.0 min=0.1 Resize multiplier for opencv window if GUI_WINDOW_ON=True -BLUR_SIZE = 10 # Default= 10 OpenCV setting for Gaussian difference image blur -THRESHOLD_SENSITIVITY = 20 # Default= 20 OpenCV setting for difference image threshold +# Sign Settings +# ------------- +IM_SHOW_SIGN_ON = False +IM_SIGN_RESIZE = (1280, 720) +IM_SIGN_TEXT_XY = (100, 675) +IM_SIGN_FONT_SCALE = 30.0 +IM_SIGN_FONT_THICK_PX = 60 +IM_SIGN_FONT_COLOR = (255, 255, 255) +IM_SIGN_TIMEOUT_SEC = 5 # Keep the image sign for 5 seconds. # Motion Event Settings # --------------------- @@ -96,7 +98,6 @@ MO_EVENT_TIMEOUT_SEC = 0.3 # Default= 0.3 seconds to wait for next motion event before starting new track MO_MAX_SPEED_OVER = 0 # Exclude track if Speed less than or equal to value specified 0=All # Can be useful to exclude pedestrians and/or bikes, Etc or track only fast objects - # Motion Tracking Window Crop Area Settings # ----------------------------------------- # Note: Values based on 320x240 image stream size. @@ -108,35 +109,28 @@ MO_CROP_Y_UPPER = 90 # Default=90 MO_CROP_Y_LOWER = 150 # Default=150 -# Camera Image Settings -# --------------------- -IM_DIR_PATH = "media/images" # folder name to store images -IM_PREFIX = "speed-" # image name prefix -IM_FORMAT_EXT = ".jpg" # Default = ".jpg" image Formats .jpg .jpeg .png .gif .bmp -IM_JPG_QUALITY = 98 # Set the quality of the jpeg. Default = 95 - # https://docs.opencv.org/3.4/d8/d6a/group__imgcodecs__flags.html#ga292d81be8d76901bff7988d18d2b42ac -IM_JPG_OPTIMIZE_ON = True # Optimize the image. Default = False - # https://docs.opencv.org/3.4/d8/d6a/group__imgcodecs__flags.html#ga292d81be8d76901bff7988d18d2b42ac -IM_SHOW_CROP_AREA_ON = False # True= Display motion detection rectangle area on saved images -IM_SHOW_SPEED_FILENAME_ON = True # True= Include speed value in filename -IM_SHOW_TEXT_ON = True # True= Show Text on speed images False= No Text on images -IM_SHOW_TEXT_BOTTOM_ON = True # True= Show image text at bottom otherwise at top -IM_FONT_SIZE_PX = 12 # Default= 12 Font text height in px for text on images -IM_FONT_SCALE = 0.5 # Default= 0.5 Font scale factor that is multiplied by the font-specific base size. -IM_FONT_THICKNESS = 2 # Default= 2 Font text thickness in px for text on images -IM_FONT_COLOR = (255, 255, 255) # Default= (255, 255, 255) White -IM_BIGGER = 3.0 # Default= 3.0 min=0.1 Resize saved speed image by specified multiplier value -IM_MAX_FILES = 0 # 0=off or specify MaxFiles to maintain then oldest are deleted Default=0 (off) +# Plugins override the specified config.py variable settings +# ---------------------------------------------------------- +PLUGIN_ENABLE_ON = False # True enables import of the specified PLUGIN_NAME +PLUGIN_NAME = "picam240" # Specify filename in plugins subfolder without .py extension per below + # picam240, webcam240 (Recommended for RPI2 or greater) + # picam480, webcam480, rtsp352, picam720, webcam720 (can use RPI3 but Test) + # picam1080 (Experimental Not Recommended) + # secpicam480, secwebcam480 (Experimental no CSV entries) -# Sign Settings -# --------------------- -IM_SHOW_SIGN_ON = False -IM_SIGN_RESIZE = (1280, 720) -IM_SIGN_TEXT_XY = (100, 675) -IM_SIGN_FONT_SCALE = 30.0 -IM_SIGN_FONT_THICK_PX = 60 -IM_SIGN_FONT_COLOR = (255, 255, 255) -IM_SIGN_TIMEOUT_SEC = 5 # Keep the image sign for 5 seconds. +# Display opencv windows on GUI desktop +# GUI_WINDOW_ON suppresses All Windows if False +# ---------------------------------------------- +GUI_WINDOW_ON = False # True= Turn On All desktop GUI openCV windows. False=Don't Show (req'd for SSH) . +GUI_IMAGE_WIN_ON = True # True=Show the camera on a gui windows. False=Don't Show (useful for image_sign) +GUI_THRESH_WIN_ON = False # True=Show openCV cropped BLUR, THRESHOLD grayscale image window. Used for detecting movement contours +GUI_CROP_WIN_ON = False # True=Show crop window. Same as GUI_THRESH_WIN_ON but in color. +CV_SHOW_CIRCLE_ON = False # True=circle in center of motion, False=rectangle +CV_CIRCLE_SIZE_PX = 5 # Default= 5 Diameter circle in px if CV_SHOW_CIRCLE_ON = True +CV_LINE_WIDTH_PX = 1 # Default= 1 Size of lines for circle or Rectangle +CV_WINDOW_BIGGER = 1.0 # Default= 1.0 min=0.1 Resize multiplier for opencv window if GUI_WINDOW_ON=True +BLUR_SIZE = 10 # Default= 10 OpenCV setting for Gaussian difference image blur +THRESHOLD_SENSITIVITY = 20 # Default= 20 OpenCV setting for difference image threshold # Optional Manage SubDir Creation by time, number of files or both (not recommended) # ---------------------------------------------------------------- diff --git a/speed-cam.py b/speed-cam.py index f4b519b..2576691 100644 --- a/speed-cam.py +++ b/speed-cam.py @@ -44,7 +44,7 @@ """ from __future__ import print_function -PROG_VER = "13.12" # current version of this python script +PROG_VER = "13.13" # current version of this python script print('Loading Wait...') import os import sys @@ -132,6 +132,11 @@ "IM_FORMAT_EXT": ".jpg", "IM_JPG_QUALITY": 95, "IM_JPG_OPTIMIZE_ON": False, + "IM_SAVE_4AI_ON": False, + "IM_SAVE_4AI_POS_DIR": "media/ai/pos", + "IM_SAVE_4AI_NEG_DIR": "media/ai/pos", + "IM_SAVE_4AI_NEG_TIMER_SEC": 60 * 60 * 24, + "IM_FIRST_AND_LAST_ON": False, "IM_SHOW_CROP_AREA_ON": True, "IM_SHOW_SPEED_FILENAME_ON": False, "IM_SHOW_TEXT_ON": True, @@ -457,6 +462,10 @@ def make_media_dirs(): if not os.path.isdir(html_path): logging.info("Creating html Folder %s", html_path) os.makedirs(html_path) + if IM_SAVE_4AI_ON and not os.path.isdir(IM_SAVE_4AI_POS_DIR): + os.makedirs(IM_SAVE_4AI_POS_DIR) + if IM_SAVE_4AI_ON and not os.path.isdir(IM_SAVE_4AI_NEG_DIR): + os.makedirs(IM_SAVE_4AI_NEG_DIR) os.chdir(cwd) @@ -1316,7 +1325,8 @@ def speed_camera(): else: print("Logging Messages Disabled per LOG_VERBOSE_ON=%s" % LOG_VERBOSE_ON) - off_time = datetime.datetime.now() + mo_track_timeout = datetime.datetime.now() + ai_neg_time = datetime.datetime.now() print(HORIZ_LINE) logging.info("Begin Motion Tracking .....") # Start main speed camera loop @@ -1330,13 +1340,21 @@ def speed_camera(): motion_found, big_contour = get_biggest_contour(contours) # Keep camera running while waiting for timer to expire per MO_TRACK_TIMEOUT_SEC - if timer_is_on(off_time): + if timer_is_on(mo_track_timeout): continue if GUI_WINDOW_ON or ALIGN_CAM_ON or CALIBRATE_ON: image2_copy = image2 # make a copy of current image2 when needed - if motion_found: + if not motion_found: + if IM_SAVE_4AI_ON and not timer_is_on(ai_neg_time): + AI_neg_filename = get_image_name(IM_SAVE_4AI_NEG_DIR, IM_PREFIX) + logging.info("Save neg %s", AI_neg_filename) + cv2.imwrite(AI_neg_filename, image2) + ai_neg_time = (datetime.datetime.now() + + datetime.timedelta(seconds=IM_SAVE_4AI_NEG_TIMER_SEC)) + logging.info("Next AI neg image in %.2f hours", float(IM_SAVE_4AI_NEG_TIMER_SEC / 3600)) + else: # Motion Found (track_x, track_y, track_w, track_h) = big_contour total_contours = len(contours) biggest_area = int(track_w * track_h) @@ -1359,6 +1377,8 @@ def speed_camera(): event_timer = time.time() # Reset event timeout track_count = 0 speed_list = [] + if IM_FIRST_AND_LAST_ON: + mo_im_first = image2 continue else: # Check if last motion event timed out @@ -1416,7 +1436,8 @@ def speed_camera(): if track_count >= MO_TRACK_EVENT_COUNT: tot_track_dist = abs(track_x - start_pos_x) tot_track_time = abs(track_start_time - cur_track_time) - + if IM_FIRST_AND_LAST_ON or IM_SAVE_4AI_ON: + mo_im_last = image2 if ave_speed > MO_MAX_SPEED_OVER or CALIBRATE_ON: logging.info( " Add - %i/%i xy(%i,%i) %3.2f %s" @@ -1549,7 +1570,7 @@ def speed_camera(): if ((IM_FORMAT_EXT.lower() == ".jpg" or IM_FORMAT_EXT.lower() == ".jpeg") and IM_JPG_OPTIMIZE_ON): try: - cv2.imwrite( filename, big_image, + cv2.imwrite(filename, big_image, [ int(cv2.IMWRITE_JPEG_QUALITY), IM_JPG_QUALITY, int(cv2.IMWRITE_JPEG_OPTIMIZE), 1 ] @@ -1560,6 +1581,21 @@ def speed_camera(): else: cv2.imwrite(filename, big_image) + if IM_SAVE_4AI_ON: + AI_pos_filename = get_image_name(IM_SAVE_4AI_POS_DIR, IM_PREFIX) + logging.info("Save pos %s", AI_pos_filename) + cv2.imwrite(AI_pos_filename, mo_im_last) + + if IM_FIRST_AND_LAST_ON: + # Save first and last image for later AI processing + fn_split = os.path.splitext(filename) + filename_first = fn_split[0] + "_1" + fn_split[1] + filename_last = fn_split[0] + "_2" + fn_split[1] + logging.info("Saving first %s", filename_first) + cv2.imwrite(filename_first, mo_im_first) + logging.info("Saving last %s", filename_last) + cv2.imwrite(filename_last, mo_im_last) + if USER_MOTION_CODE_ON: # =========================================== # Put your user code in userMotionCode() function @@ -1756,7 +1792,8 @@ def speed_camera(): ) first_event = True # Reset Track # Set track timeout time - off_time = datetime.datetime.now() + datetime.timedelta(seconds=MO_TRACK_TIMEOUT_SEC) + mo_track_timeout = (datetime.datetime.now() + + datetime.timedelta(seconds=MO_TRACK_TIMEOUT_SEC)) continue # go back to start of speed loop to idle camera first_event = True else: