Просмотр исходного кода

integrate object detection with motion detection

blakeblackshear 6 лет назад
Родитель
Сommit
80dbed8055
1 измененных файлов с 34 добавлено и 26 удалено
  1. 34 26
      detect_objects.py

+ 34 - 26
detect_objects.py

@@ -25,8 +25,9 @@ PATH_TO_LABELS = '/label_map.pbtext'
 # TODO: make dynamic?
 NUM_CLASSES = 90
 
-REGIONS = "350,0,300:400,350,250:400,750,250"
-#REGIONS = os.getenv('REGIONS')
+# REGIONS = "350,0,300:400,350,250:400,750,250"
+# REGIONS = "400,350,250"
+REGIONS = os.getenv('REGIONS')
 
 DETECTED_OBJECTS = []
 
@@ -121,8 +122,6 @@ def main():
     shared_memory_objects = []
     for region in regions:
         shared_memory_objects.append({
-            # create shared value for storing the time the frame was captured
-            'frame_time': mp.Value('d', 0.0),
             # shared value for signaling to the capture process that we are ready for the next frame
             # (1 for ready 0 for not ready)
             'ready_for_frame': mp.Value('i', 1),
@@ -139,17 +138,19 @@ def main():
     flat_array_length = frame_shape[0] * frame_shape[1] * frame_shape[2]
     # create shared array for storing the full frame image data
     shared_arr = mp.Array(ctypes.c_uint16, flat_array_length)
+    # create shared value for storing the frame_time
+    shared_frame_time = mp.Value('d', 0.0)
     # shape current frame so it can be treated as an image
     frame_arr = tonumpyarray(shared_arr).reshape(frame_shape)
 
-    capture_process = mp.Process(target=fetch_frames, args=(shared_arr, [obj['frame_time'] for obj in shared_memory_objects], frame_shape))
+    capture_process = mp.Process(target=fetch_frames, args=(shared_arr, shared_frame_time, [obj['ready_for_frame'] for obj in shared_memory_objects], frame_shape))
     capture_process.daemon = True
 
     detection_processes = []
     for index, region in enumerate(regions):
         detection_process = mp.Process(target=process_frames, args=(shared_arr, 
             shared_memory_objects[index]['output_array'],
-            shared_memory_objects[index]['frame_time'],
+            shared_frame_time,
             shared_memory_objects[index]['motion_detected'],
             frame_shape, 
             region['size'], region['x_offset'], region['y_offset']))
@@ -158,8 +159,9 @@ def main():
 
     motion_processes = []
     for index, region in enumerate(regions):
-        motion_process = mp.Process(target=detect_motion, args=(shared_arr, 
-            shared_memory_objects[index]['frame_time'],
+        motion_process = mp.Process(target=detect_motion, args=(shared_arr,
+            shared_frame_time,
+            shared_memory_objects[index]['ready_for_frame'],
             shared_memory_objects[index]['motion_detected'],
             frame_shape, 
             region['size'], region['x_offset'], region['y_offset']))
@@ -197,7 +199,7 @@ def main():
             # convert to RGB for drawing
             frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
             # draw the bounding boxes on the screen
-            for obj in DETECTED_OBJECTS:
+            for obj in detected_objects:
                 vis_util.draw_bounding_box_on_image_array(frame,
                     obj['ymin'],
                     obj['xmin'],
@@ -212,6 +214,12 @@ def main():
                 cv2.rectangle(frame, (region['x_offset'], region['y_offset']), 
                     (region['x_offset']+region['size'], region['y_offset']+region['size']), 
                     (255,255,255), 2)
+
+            motion_status = 'No Motion'
+            if any(obj['motion_detected'].value == 1 for obj in shared_memory_objects):
+                motion_status = 'Motion'
+            cv2.putText(frame, motion_status, (10, 20),
+		        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
             # convert back to BGR
             frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
             # encode the image into a jpg
@@ -234,7 +242,7 @@ def tonumpyarray(mp_arr):
 
 # fetch the frames as fast a possible, only decoding the frames when the
 # detection_process has consumed the current frame
-def fetch_frames(shared_arr, shared_frame_times, frame_shape):
+def fetch_frames(shared_arr, shared_frame_time, ready_for_frame_flags, frame_shape):
     # convert shared memory array into numpy and shape into image array
     arr = tonumpyarray(shared_arr).reshape(frame_shape)
 
@@ -249,16 +257,17 @@ def fetch_frames(shared_arr, shared_frame_times, frame_shape):
         # snapshot the time the frame was grabbed
         frame_time = datetime.datetime.now()
         if ret:
-            # if the detection_process is ready for the next frame decode it
+            # if the anyone is ready for the next frame decode it
             # otherwise skip this frame and move onto the next one
-            if all(shared_frame_time.value == 0.0 for shared_frame_time in shared_frame_times):
+            if any(flag.value == 1 for flag in ready_for_frame_flags):
                 # go ahead and decode the current frame
                 ret, frame = video.retrieve()
                 if ret:
                     arr[:] = frame
+                    shared_frame_time.value = frame_time.timestamp()
                     # signal to the detection_processes by setting the shared_frame_time
-                    for shared_frame_time in shared_frame_times:
-                        shared_frame_time.value = frame_time.timestamp()
+                    for flag in ready_for_frame_flags:
+                        flag.value = 0
             else:
                 # sleep a little to reduce CPU usage
                 time.sleep(0.01)
@@ -325,22 +334,22 @@ def process_frames(shared_arr, shared_output_arr, shared_frame_time, shared_moti
         shared_output_arr[:] = objects + [0.0] * (60-len(objects))
 
 # do the actual object detection
-def detect_motion(shared_arr, shared_frame_time, shared_motion, frame_shape, region_size, region_x_offset, region_y_offset):
+def detect_motion(shared_arr, shared_frame_time, ready_for_frame, shared_motion, frame_shape, region_size, region_x_offset, region_y_offset):
     # shape shared input array into frame for processing
     arr = tonumpyarray(shared_arr).reshape(frame_shape)
 
     no_frames_available = -1
     avg_frame = None
     last_motion = -1
+    frame_time = 0.0
     while True:
         now = datetime.datetime.now().timestamp()
         # if it has been 30 seconds since the last motion, clear the flag
         if last_motion > 0 and (now - last_motion) > 30:
             last_motion = -1
             shared_motion.value = 0
-            print("motion cleared")
         # if there isnt a frame ready for processing
-        if shared_frame_time.value == 0.0:
+        if shared_frame_time.value == frame_time:
             # save the first time there were no frames available
             if no_frames_available == -1:
                 no_frames_available = now
@@ -352,6 +361,8 @@ def detect_motion(shared_arr, shared_frame_time, shared_motion, frame_shape, reg
             else:
                 # rest a little bit to avoid maxing out the CPU
                 time.sleep(0.01)
+            if ready_for_frame.value == 0:
+                ready_for_frame.value = 1
             continue
         
         # we got a valid frame, so reset the timer
@@ -360,21 +371,19 @@ def detect_motion(shared_arr, shared_frame_time, shared_motion, frame_shape, reg
         # if the frame is more than 0.5 second old, discard it
         if (now - shared_frame_time.value) > 0.5:
             # signal that we need a new frame
-            shared_frame_time.value = 0.0
+            ready_for_frame.value = 1
             # rest a little bit to avoid maxing out the CPU
             time.sleep(0.01)
             continue
         
         # make a copy of the cropped frame
-        cropped_frame = arr[region_y_offset:region_y_offset+region_size, region_x_offset:region_x_offset+region_size].copy()
+        cropped_frame = arr[region_y_offset:region_y_offset+region_size, region_x_offset:region_x_offset+region_size].copy().astype('uint8')
         frame_time = shared_frame_time.value
         # signal that the frame has been used so a new one will be ready
-        shared_frame_time.value = 0.0
+        ready_for_frame.value = 1
 
         # convert to grayscale
         gray = cv2.cvtColor(cropped_frame, cv2.COLOR_BGR2GRAY)
-        # convert to uint8
-        gray = (gray/256).astype('uint8')
         # apply gaussian blur
         gray = cv2.GaussianBlur(gray, (21, 21), 0)
 
@@ -400,15 +409,14 @@ def detect_motion(shared_arr, shared_frame_time, shared_motion, frame_shape, reg
             if cv2.contourArea(c) < 50:
                 continue
             
-            print("motion_detected")
             last_motion = now
             shared_motion.value = 1
 
             # compute the bounding box for the contour, draw it on the frame,
             # and update the text
-            (x, y, w, h) = cv2.boundingRect(c)
-            cv2.rectangle(cropped_frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
-            cv2.imwrite("motion%d.png" % frame_time, cropped_frame)
+        #     (x, y, w, h) = cv2.boundingRect(c)
+        #     cv2.rectangle(cropped_frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
+        # cv2.imwrite("motion%d.jpg" % frame_time, cropped_frame)
 if __name__ == '__main__':
     mp.freeze_support()
     main()