Source code for CAM2ImageArchiver.CameraHandler

'''
Copyright 2017 Purdue University

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''

from multiprocessing import Process
import time
import datetime
import os
import cv2
import numpy as np

[docs]class CameraHandler(Process): """ The thread to download snapshots from a single camera. Parameters ---------- camera : camera object The camera from which snapshots will be taken. Attributes ---------- camera : camera object The camera from which snapshots will be taken. id : int The ID of the the camera. url : str The URL of the camera image stream. duration : int The duration of downloading the images in seconds. interval : int The interval between each two successive snapshots. """ # The path of the results directory. def __init__(self, cameras, chunk, duration, interval, result_path, remove_after_failure, image_difference_percentage): Process.__init__(self) self.cameras = cameras self.duration = duration self.interval = interval self.result_path = result_path self.chunk = chunk self.remove_after_failure = remove_after_failure self.image_difference_percentage = image_difference_percentage
[docs] def run(self): """ Download snapshots from the camera, and save locally. """ print("Starting download of {} cameras from chunk {}".format(len(self.cameras), str(self.chunk))) # Set the starting timestamp, and process until the end of the duration. start_timestamp = time.time() while (time.time() - start_timestamp) < self.duration: # Set the timestamp of the start of the new loop iteration. loop_start_timestamp = time.time() # print("Loop Start", time.time()) # bad_cams is initialized in the while loop so that the array is emptied after # each iteration bad_cams = [] x = 0 for camera in self.cameras: print("Process {} Downloading Image {} of {} at time {}".format(self.chunk, x, len(self.cameras), datetime.datetime.now())) x = x + 1 try: # Download the image. frame, _ = camera.get_frame() except Exception: if self.remove_after_failure: print("Error retrieving from camera {}. Marking camera for removal " "from chunk {}.".format(str(camera.id), str(self.chunk))) bad_cams.append(camera) else: if frame is not None: # Save the image. frame_timestamp = time.time() cam_directory = os.path.join(self.result_path, str(camera.id)) file_name = '{}/{}_{}.png'.format( cam_directory, camera.id, datetime.datetime.fromtimestamp( frame_timestamp).strftime('%Y-%m-%d_%H-%M-%S-%f')) if self.image_difference_percentage: if frame.size != 0 and (type(camera.last_frame) == type(None) or (np.count_nonzero(np.absolute(camera.last_frame - frame)) * 100) / frame.size >= self.image_difference_percentage): cv2.imwrite(file_name, frame) camera.last_frame = frame else: # print("diff_{}".format(np.sum(camera.last_frame - frame) == 0)) # cv2.imwrite(file_name, frame) print("Camera frame has not changed for {}. Will retry after {}sec.".format(str(camera.id), str(self.interval))) else: cv2.imwrite(file_name, frame) else: if self.remove_after_failure: print("Empty frame retrieved from camera {}. Marking camera for removal from chunk {}.".format(str(camera.id), str(self.chunk))) bad_cams.append(camera) finally: # These variables are explicitely set to None to encourage the garbage # collector. # Testing showed that without this these variables would persist. frame = None frame_timestamp = None cam_directory = None file_name = None # Remove all bad cameras if bad_cams and self.remove_after_failure: for bad_camera in bad_cams: self.cameras.remove(bad_camera) # Sleep until the interval between frames ends. time_to_sleep = self.interval - (time.time() - loop_start_timestamp) if time_to_sleep > 0: print("Process {} going to sleep...".format(self.chunk)) time.sleep(time_to_sleep) else: print("Warning: Retrieval time exceeded sleep time for chunk {}. Specified interval" "cannot be met." .format(self.chunk))