_boxes = np.array(output_dict['detection_boxes'])
        detection_scores = np.array(output_dict['detection_scores'])
        detection_classes = np.array(output_dict['detection_classes'])
        output_dict['detection_boxes'] = detection_boxes
        output_dict['detection_scores'] = detection_scores
        output_dict['detection_classes'] = detection_classes


        detected_frame_tuple = ( frame_number, {"detected": 1, "frame": frame, "frame_timestamp": frame_timestamp, "output_dict": output_dict} )
        if no_callback:
            add_to_o_queue(detected_frame_tuple)
            delete_from_s3(s3_bucket, file_name_ext)
        else:
            delete_from_s3(s3_bucket, file_name_ext)
            return detected_frame_tuple


    except KeyboardInterrupt:
        import traceback
        traceback.print_exc()
        raise                
    except:
        import traceback
        traceback.print_exc()
        
        #raise # Without this raise, the regular callback of apply_async will be called

        
def add_to_o_queue(detected_frame_tuple):
    try:
        if o_queue.full():
            print("o_queue FULL")
            print("-------PROGRAM STOPPED UNTIL o_queue DRAINED INTO p_queue-----")
            
        #if not o_queue.full():
        #    print("Adding detection to o_queue")
        #    print("o_queue size")
        #    print(o_queue.qsize())

        # Change detected frame back to size for tracking
        frame_number, frame_dict = detected_frame_tuple
        frame = frame_dict['frame']
        frame = imutils.resize(frame, width=tracking_frame_width)
        frame_dict['frame'] = frame
        detected_frame_tuple = (frame_number, frame_dict)

        o_queue.put(detected_frame_tuple)
        #else:
        #    print("o_queue full")
    except:
        import traceback
        traceback.print_exc()
        raise
        


print("NODE IS IN '", args['mode'], "' MODE")
# if a video path was not supplied, grab the reference to the web cam
if not args.get("video", False):
    framerate = 30
        
    print("[INFO] starting camera stream...")    
    vs = VideoStream(usePiCamera=args["picamera"], resolution=(detection_frame_width, int(detection_frame_width*frame_ratio)), framerate=framerate).start()
    print("[INFO] Warming up camera...")
    time.sleep(3)
    
    if args["picamera"] == 1 or args["picamera"] == True:
        vs.camera.rotation = args["rotation"]
    
    
else: # otherwise, grab a reference to the video file
    framerate = 30
    print("[INFO] starting video file stream...")    
    vs = FileVideoStream(args["video"], queueSize=15).start()

    # loop over frames from the video stream




    
'''
Here we calculate and set the linear map (transformation matrix) that we use to turn the pixel coordinates of the objects on the frame into their corresponding lat/lng coordinates in the real world. It's a computationally expensive calculation and requires inputs from the camera's calibration (frame of reference in the real world) so we do it once here instead of everytime we need to do a transformation from pixels to lat/lng
'''
rw = RealWorldCoordinates({"height": tracking_frame_width*frame_ratio, "width": tracking_frame_width})
if args['mode'] == 'CALIBRATING':
    rw.set_transform(calibrating=True)
    print("set calibration")
else:
    rw.node_update()
    rw.set_transform() 


# Set Leveldb database variable
if args['mode'] == 'CALIBRATING':
    tracklets_db = plyvel.DB('/tmp/gl_tmp_tracklets_db/', create_if_missing=True)
else:
    tracklets_db = plyvel.DB(str(Path.home())+'/.grassland/gl_tracklets_db/', create_if_missing=True)

# Use current eon number for LevelDB prefix to partition database
# https://plyvel.readthedocs.io/en/latest/user.html#prefixed-databases
eon_tracklets_db = tracklets_db.prefixed_db(b'\x00') 


        
first_frame_detected = False
if args["display"] == 1:
    display = True
else:
    display = False
    
run_tracking_loop = Value('i', 0)
run_detection_loop = Value('i', 0)
run_tracklets_loop = Value('i', 0)

count_read_frame = 0
count_write_frame = 1

                
count = 0

frame_dimensions_set = False
last_frame = np.array([])
#frame_number = 0
start = time.time()
update_frames = True


lambda_wakeup_duration = 0

print("Sending Wakeup Ping to Lambda function")
requests.get(lambda_url)
print("Waiting "+str(lambda_wakeup_duration)+" seconds for function to wake up...")
time.sleep(lambda_wakeup_duration)



# this handler will be run for each incoming connection in a dedicated greenlet
def tracklets_socket_server_handler(socket, address):
    print('New connection for tracklets_socket_server from %s:%s' % address)

    # Read socket query
    query_dict =  json.loads(socket.recv(4096).decode('utf-8'))
    query_timestamp = query_dict['timestamp']
    query_range = query_dict['range']
    query_timestamp = int(query_timestamp)
    query_range = int(query_range)

    print("query_timestamp", query_timestamp)

    trackableObjects = {}
    for key, val in eon_tracklets_db:
        if query_timestamp <= int.from_bytes(key[8:], byteorder=s2sphere_byteorder) < query_timestamp+query_range:
            # print("query_timestamp", query_timestamp)
            # print('int.from_bytes(key[8:], byteorder=s2sphere_byteorder)')
            # print(int.from_bytes(key[8:], byteorder=s2sphere_byteorder))
            # print("------------------------------------------")
            
            cell_id = int.from_bytes(key[0:8], byteorder=s2sphere_byteorder)
            s2_cellid = s2sphere.CellId(id_=cell_id)
            s2_latlng = s2_cellid.to_lat_lng()
            lat = s2_latlng.lat().degrees
            lng = s2_latlng.lng().degrees
            frame_timestamp = int.from_bytes(key[8:], byteorder=s2sphere_byteorder)

            if val[0:16].hex() in trackableObjects:
                
                trackableObjects[val[0:16].hex()]['tracklets'].append(
                    [
                        lng,
                        lat,
                        frame_timestamp 
                    ]
                )
            else:
                trackableObjects[val[0:16].hex()] = {
                    "detection_class_id": int.from_bytes(val[16:], byteorder=s2sphere_byteorder),
                    "tracklets": [
                        [
                            lng,
                            lat,
                            frame_timestamp
                        ]
                    ]
                }

    
    trackable_object_list = []
    for object_id, trackableObject in trackableObjects.items():

        trackable_object_list.append(

            {
                "object_id": object_id,
                "detection_class_id": trackableObject['detection_class_id'],
                "tracklets": trackableObject['tracklets']
            }
        )
    

    if len(trackable_object_list) > 0:
        socket.sendall(bytes(str(trackable_object_list), 'utf-8'))
        print("sent "+str(len(trackable_object_list))+ " trackable objects for query_timestamp "+str(query_timestamp))
        #print(str(track