|
|
|
@ -5,6 +5,7 @@ time python src/_detector.py --input ~/Desktop/5min.mp4 -l
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
# import the necessary packages |
|
|
|
|
import sys |
|
|
|
|
import time |
|
|
|
|
import argparse |
|
|
|
|
import pprint |
|
|
|
@ -18,6 +19,7 @@ from utils import (
|
|
|
|
|
get_heading, |
|
|
|
|
get_avg_heading, |
|
|
|
|
OBJ_LEAVING_COND, |
|
|
|
|
DONTCARE, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
pp = pprint.PrettyPrinter(indent=2) |
|
|
|
@ -73,6 +75,7 @@ print("[INFO] loading YOLO from disk...")
|
|
|
|
|
net = cv2.dnn.readNetFromDarknet(configPath, weightsPath) |
|
|
|
|
ln = net.getLayerNames() |
|
|
|
|
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()] |
|
|
|
|
start = end = 0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def detect_stuffs(_frame): |
|
|
|
@ -163,6 +166,11 @@ except:
|
|
|
|
|
_frame_count = 0 |
|
|
|
|
tracker_counter = 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for xx in range(3996): |
|
|
|
|
(grabbed, frame) = vs.read() |
|
|
|
|
_frame_count += 1 |
|
|
|
|
|
|
|
|
|
# loop over frames from the video file stream |
|
|
|
|
while True: |
|
|
|
|
# read the next frame from the file |
|
|
|
@ -186,119 +194,169 @@ while True:
|
|
|
|
|
# print("boxes", boxes) |
|
|
|
|
print(f"[{_frame_count:08d}] ::") |
|
|
|
|
|
|
|
|
|
# quit if unable to read the video file |
|
|
|
|
if not success: |
|
|
|
|
print("Failed to read video", grabbed, frame) |
|
|
|
|
|
|
|
|
|
cv_trackers.clear() |
|
|
|
|
cv_trackers = cv2.MultiTracker_create() |
|
|
|
|
# print(" INIT AGAIN cv_tracker", type(cv_trackers), cv_trackers) |
|
|
|
|
# get rid of them in trackers too |
|
|
|
|
trackers = [_ for _ in trackers if _["id"] not in ut_ids] |
|
|
|
|
# add tracker again |
|
|
|
|
for _trckr in trackers: |
|
|
|
|
__tkr = OPENCV_OBJECT_TRACKERS["csrt"]() |
|
|
|
|
cv_trackers.add(__tkr, frame, tuple(_trckr["curr_position"])) |
|
|
|
|
(success, boxes) = cv_trackers.update(frame) |
|
|
|
|
# print('SUCCESS? ', success) |
|
|
|
|
|
|
|
|
|
untracking = [] |
|
|
|
|
# loop over the bounding boxes and draw then on the frame |
|
|
|
|
if success: |
|
|
|
|
obj_cnt = len(boxes) |
|
|
|
|
# print(f"obj_cnt: ", obj_cnt, ' | tracker #', len(trackers)) |
|
|
|
|
for idx in range(obj_cnt): |
|
|
|
|
GONE = False |
|
|
|
|
|
|
|
|
|
box = boxes[idx] |
|
|
|
|
(x, y, w, h) = [int(v) for v in box] |
|
|
|
|
_last_pos = trackers[idx]["curr_position"] |
|
|
|
|
(_x, _y, _w, _h) = _last_pos |
|
|
|
|
curr_distance = box_distance(box, _last_pos) |
|
|
|
|
last_distance = trackers[idx]["distance"] |
|
|
|
|
trackers[idx]["distance"] = curr_distance |
|
|
|
|
trackers[idx]["curr_position"] = box # [int(v) for v in box] |
|
|
|
|
|
|
|
|
|
_heading = get_heading(_x, _y, x, y) |
|
|
|
|
|
|
|
|
|
STILL_DIST_PX = 2 |
|
|
|
|
if last_distance < STILL_DIST_PX and curr_distance < STILL_DIST_PX: |
|
|
|
|
trackers[idx]["still"] += 1 |
|
|
|
|
else: |
|
|
|
|
trackers[idx]["still"] = 0 |
|
|
|
|
|
|
|
|
|
if trackers[idx]["still"] == 0: |
|
|
|
|
trackers[idx]["heading"] = [_heading] + trackers[idx]["heading"] |
|
|
|
|
|
|
|
|
|
trackers[idx]["heading"] = trackers[idx]["heading"][:20] |
|
|
|
|
|
|
|
|
|
if trackers[idx]["still"] > 30 or x < 5 or x > 1250: |
|
|
|
|
untracking.append(trackers[idx]) |
|
|
|
|
|
|
|
|
|
tk = trackers[idx] |
|
|
|
|
# check if it's hit the first |
|
|
|
|
avg_heading = get_avg_heading(trackers[idx]["heading"]) |
|
|
|
|
for lvng_cnd in OBJ_LEAVING_COND: |
|
|
|
|
_origin = tk["origin"]["id"] |
|
|
|
|
cond = dict(lvng_cnd) |
|
|
|
|
if cond["origin_id"] != _origin or avg_heading != cond["heading"]: |
|
|
|
|
continue |
|
|
|
|
REACH_condition = False |
|
|
|
|
if cond["x"] != -1: |
|
|
|
|
if (cond["heading"] in "NE" and x + w > cond["x"]) or ( |
|
|
|
|
cond["heading"] in "SW" and x < cond["x"] |
|
|
|
|
): |
|
|
|
|
# print("REACH condition: X", x, cond["x"]) |
|
|
|
|
REACH_condition = True |
|
|
|
|
|
|
|
|
|
elif cond["y"] != -1: |
|
|
|
|
# Don't have one yet |
|
|
|
|
if (cond["heading"] in "NE" and x + w > cond["y"]) or ( |
|
|
|
|
cond["heading"] in "SW" and x < cond["y"] |
|
|
|
|
): |
|
|
|
|
# print("REACH condition: Y") |
|
|
|
|
REACH_condition = True |
|
|
|
|
if not REACH_condition: |
|
|
|
|
continue |
|
|
|
|
obj_cnt = len(boxes) |
|
|
|
|
# print(f"obj_cnt: ", obj_cnt, ' | tracker #', len(trackers)) |
|
|
|
|
for idx in range(obj_cnt): |
|
|
|
|
GONE = False |
|
|
|
|
|
|
|
|
|
# print("MATCH COND") |
|
|
|
|
# pp.pprint(cond) |
|
|
|
|
# TODO: should be a loop here if next has > 1 |
|
|
|
|
_nid = f"id_{cond['next_area'][0]}" |
|
|
|
|
# print(f"#{tk['id']} origin:#{_origin} to#{_nid}", end="") |
|
|
|
|
print(f" {tk['id']} LEFT from {_origin} -> {_nid}") |
|
|
|
|
if _nid not in W4A: |
|
|
|
|
# print(f">>add AREA {_nid} to W4A", end="") |
|
|
|
|
W4A[_nid] = {"objects": []} |
|
|
|
|
# put this object to W4A for next area if doesn't exist |
|
|
|
|
has_this = [_ for _ in W4A[_nid]["objects"] if _[0]["id"] == tk["id"]] |
|
|
|
|
if not has_this: |
|
|
|
|
GONE = True |
|
|
|
|
# unit in frame |
|
|
|
|
_expected_frame = _frame_count + cond["duration_to_next"] |
|
|
|
|
W4A[_nid]["objects"].append((tk, _frame_count, _expected_frame)) |
|
|
|
|
untracking.append(tk) |
|
|
|
|
# print(f'>>GONE - W#{len(W4A[_nid]["objects"])}') |
|
|
|
|
# print(f' {_nid} objs: ') |
|
|
|
|
# pp.pprint(W4A[_nid]["objects"]) |
|
|
|
|
# print(f' {_nid} untracking: ', [_['id'] for _ in untracking]) |
|
|
|
|
|
|
|
|
|
if GONE: |
|
|
|
|
box = boxes[idx] |
|
|
|
|
(x, y, w, h) = [int(v) for v in box] |
|
|
|
|
|
|
|
|
|
# check if size is growing? if more than twice then, untrack it |
|
|
|
|
ow, oh = trackers[idx]["size"] |
|
|
|
|
if ow / w > 2 or oh / h > 2: |
|
|
|
|
print(f" {tk['id']} GROW_TOO_BIG") |
|
|
|
|
trackers[idx]["status"] = "grow-too-big" |
|
|
|
|
untracking.append(trackers[idx]) |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
_last_pos = trackers[idx]["curr_position"] |
|
|
|
|
(_x, _y, _w, _h) = _last_pos |
|
|
|
|
curr_distance = box_distance(box, _last_pos) |
|
|
|
|
last_distance = trackers[idx]["distance"] |
|
|
|
|
trackers[idx]["distance"] = curr_distance |
|
|
|
|
trackers[idx]["curr_position"] = box # [int(v) for v in box] |
|
|
|
|
|
|
|
|
|
_heading = get_heading(_x, _y, x, y) |
|
|
|
|
tk = trackers[idx] |
|
|
|
|
|
|
|
|
|
STILL_DIST_PX = 1 |
|
|
|
|
if last_distance < STILL_DIST_PX and curr_distance < STILL_DIST_PX: |
|
|
|
|
trackers[idx]["still"] += 1 |
|
|
|
|
else: |
|
|
|
|
trackers[idx]["still"] = 0 |
|
|
|
|
|
|
|
|
|
if trackers[idx]["still"] == 0: |
|
|
|
|
trackers[idx]["heading"] = [_heading] + trackers[idx]["heading"] |
|
|
|
|
|
|
|
|
|
# trackers[idx]["heading"] = trackers[idx]["heading"][:20] |
|
|
|
|
|
|
|
|
|
if trackers[idx]["still"] > 30 or x < 5 or x > 1250: |
|
|
|
|
untracking.append(trackers[idx]) |
|
|
|
|
|
|
|
|
|
if trackers[idx]["still"] > 10 and len(trackers[idx]["heading"]) < 5: |
|
|
|
|
print(f" {tk['id']} LEFT - short-life") |
|
|
|
|
trackers[idx]["status"] = "short-life" |
|
|
|
|
untracking.append(trackers[idx]) |
|
|
|
|
|
|
|
|
|
# check if it's hit the first |
|
|
|
|
avg_heading = get_avg_heading(trackers[idx]["heading"]) |
|
|
|
|
|
|
|
|
|
h_count = len(tk["heading"]) |
|
|
|
|
if 5 < h_count and h_count < 10: |
|
|
|
|
# enough to validate, but never an established one |
|
|
|
|
DONTCARE_IDS = [_[0][1] for _ in DONTCARE] |
|
|
|
|
if tk["origin"]["id"] in DONTCARE_IDS: |
|
|
|
|
dc_id = DONTCARE_IDS.index(tk["origin"]["id"]) |
|
|
|
|
dc_dict = dict(DONTCARE[dc_id]) |
|
|
|
|
print(DONTCARE_IDS, tk["origin"]["id"], dc_id, dc_dict["heading"]) |
|
|
|
|
if avg_heading in dc_dict["heading"]: |
|
|
|
|
print(f" {tk['id']} DONT-CARE condition") |
|
|
|
|
trackers[idx]["status"] = "dont-care" |
|
|
|
|
untracking.append(trackers[idx]) |
|
|
|
|
|
|
|
|
|
for lvng_cnd in OBJ_LEAVING_COND: |
|
|
|
|
_origin = tk["origin"]["id"] |
|
|
|
|
cond = dict(lvng_cnd) |
|
|
|
|
if cond["origin_id"] != _origin or avg_heading != cond["heading"]: |
|
|
|
|
continue |
|
|
|
|
REACH_condition = False |
|
|
|
|
if cond["x"] != -1: |
|
|
|
|
# print("REACH condition: X", x, cond["x"]) |
|
|
|
|
if cond["heading"] in "NE": |
|
|
|
|
_cond = cond["x"](y + w) if callable(cond["x"]) else cond["x"] |
|
|
|
|
if x + w > _cond: |
|
|
|
|
REACH_condition = True |
|
|
|
|
elif cond["heading"] in "SW": |
|
|
|
|
_cond = cond["x"](y + h) if callable(cond["x"]) else cond["x"] |
|
|
|
|
if x < _cond: |
|
|
|
|
REACH_condition = True |
|
|
|
|
elif cond["y"] != -1: |
|
|
|
|
_cond = cond["y"](x + h) if callable(cond["y"]) else cond["y"] |
|
|
|
|
# Don't have one yet |
|
|
|
|
if cond["heading"] in "SW" and y + h > _cond: |
|
|
|
|
print("REACH condition: Y", y + h, _cond) |
|
|
|
|
REACH_condition = True |
|
|
|
|
# pass |
|
|
|
|
if not REACH_condition: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
# print( |
|
|
|
|
# f"[{tk['id']}-{tk['type']}] (x,y)=({x},{y})" |
|
|
|
|
# f" | still #{tk['still']} | distance: " |
|
|
|
|
# f"{last_distance:.3f} -> {curr_distance:.3f}", |
|
|
|
|
# end="", |
|
|
|
|
# ) |
|
|
|
|
# _htxt = ",".join(trackers[idx]["heading"]) |
|
|
|
|
# print(f" ------ heading: {_htxt}", end='') |
|
|
|
|
# print(f" ------ avg heading: {avg_heading}", end="") |
|
|
|
|
# print("") |
|
|
|
|
|
|
|
|
|
# DRAW on FRAME |
|
|
|
|
color = [int(c) for c in COLORS[0]] |
|
|
|
|
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) |
|
|
|
|
cv2.putText( |
|
|
|
|
frame, |
|
|
|
|
f"{tk['id']} - {tk['type']}", |
|
|
|
|
(x, y - 5), |
|
|
|
|
cv2.FONT_HERSHEY_SIMPLEX, |
|
|
|
|
0.5, |
|
|
|
|
color, |
|
|
|
|
2, |
|
|
|
|
) |
|
|
|
|
# print("MATCH COND") |
|
|
|
|
# pp.pprint(cond) |
|
|
|
|
_nid = f"id_{cond['next_area'][0]}" |
|
|
|
|
# print(f"#{tk['id']} origin:#{_origin} to#{_nid}", end="") |
|
|
|
|
print(f" {tk['id']} LEFT from {_origin} -> {_nid}") |
|
|
|
|
if _nid not in W4A: |
|
|
|
|
# print(f">>add AREA {_nid} to W4A", end="") |
|
|
|
|
W4A[_nid] = {"objects": []} |
|
|
|
|
# put this object to W4A for next area if doesn't exist |
|
|
|
|
has_this = [_ for _ in W4A[_nid]["objects"] if _[0]["id"] == tk["id"]] |
|
|
|
|
if not has_this: |
|
|
|
|
GONE = True |
|
|
|
|
# unit in frame |
|
|
|
|
_expected_frame = _frame_count + cond["duration_to_next"] |
|
|
|
|
W4A[_nid]["objects"].append((tk, _frame_count, _expected_frame)) |
|
|
|
|
untracking.append(tk) |
|
|
|
|
# print(f'>>GONE - W#{len(W4A[_nid]["objects"])}') |
|
|
|
|
# print(f' {_nid} objs: ') |
|
|
|
|
# pp.pprint(W4A[_nid]["objects"]) |
|
|
|
|
# print(f' {_nid} untracking: ', [_['id'] for _ in untracking]) |
|
|
|
|
|
|
|
|
|
if GONE: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
print( |
|
|
|
|
f"[{tk['id']}{tk['type'][:1]}] o#{tk['origin']['id']} (x,y)=({x},{y},{w},{h})" |
|
|
|
|
f" | still #{tk['still']} | distance: " |
|
|
|
|
f"{last_distance:.3f} -> {curr_distance:.3f}", |
|
|
|
|
end="", |
|
|
|
|
) |
|
|
|
|
_htxt = ",".join(trackers[idx]["heading"][:18]) |
|
|
|
|
print(f"|heading:{_htxt}", end="") |
|
|
|
|
print(f"|avg:{avg_heading}", end="") |
|
|
|
|
print("") |
|
|
|
|
|
|
|
|
|
# DRAW on FRAME |
|
|
|
|
color = [int(c) for c in COLORS[0]] |
|
|
|
|
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) |
|
|
|
|
cv2.putText( |
|
|
|
|
frame, |
|
|
|
|
f"{tk['id']} - {tk['type']}", |
|
|
|
|
(x, y - 5), |
|
|
|
|
cv2.FONT_HERSHEY_SIMPLEX, |
|
|
|
|
0.5, |
|
|
|
|
color, |
|
|
|
|
2, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
# Cleanup Tracker |
|
|
|
|
if untracking: |
|
|
|
|
ut_ids = [_["id"] for _ in untracking] # untracking ids |
|
|
|
|
# cv_trackers.clear() |
|
|
|
|
cv_trackers.clear() |
|
|
|
|
cv_trackers = None |
|
|
|
|
time.sleep(1) |
|
|
|
|
cv_trackers = cv2.MultiTracker_create() |
|
|
|
|
# print(" cv_tracker", type(cv_trackers), cv_trackers) |
|
|
|
|
# get rid of them in trackers too |
|
|
|
|
trackers = [_ for _ in trackers if _["id"] not in ut_ids] |
|
|
|
|
# add tracker again |
|
|
|
@ -313,6 +371,12 @@ while True:
|
|
|
|
|
if _frame_count % 15 == 1: |
|
|
|
|
idxs, boxes, confidences, classIDs, start, end = detect_stuffs(frame) |
|
|
|
|
# loop over the indexes we are keeping |
|
|
|
|
if len(idxs) == 0: |
|
|
|
|
print("CAN NOT DETECT STUFFS??") |
|
|
|
|
continue |
|
|
|
|
if isinstance(idxs, tuple): |
|
|
|
|
pp.pprint(idxs) |
|
|
|
|
|
|
|
|
|
for i in idxs.flatten(): |
|
|
|
|
# extract the bounding box coordinates |
|
|
|
|
(x, y) = (boxes[i][0], boxes[i][1]) |
|
|
|
@ -323,6 +387,10 @@ while True:
|
|
|
|
|
if not found_at: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
# only do for person/wheelchair |
|
|
|
|
if _class not in ["person", "wheelchair", "bicycle"]: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
# (1) check whether it's the same object as one in trackers |
|
|
|
|
is_same = False |
|
|
|
|
for t in trackers: |
|
|
|
@ -360,7 +428,9 @@ while True:
|
|
|
|
|
t = { |
|
|
|
|
"id": tracker_counter if gid is None else gid, |
|
|
|
|
"type": _class, |
|
|
|
|
"status": "", |
|
|
|
|
"curr_position": bbox, |
|
|
|
|
"size": (w, h), |
|
|
|
|
"heading": [], |
|
|
|
|
"origin": found_at, |
|
|
|
|
"distance": -1, |
|
|
|
@ -383,8 +453,9 @@ while True:
|
|
|
|
|
# CLEANUP |
|
|
|
|
cleanups = [] |
|
|
|
|
for k in W4A: |
|
|
|
|
print(f" CLEANUP[area {k}] ", end="") |
|
|
|
|
for _o in W4A[k]["objects"]: |
|
|
|
|
print(f" CLEANUP: {_o[0]['id']} - {_o[1]} - {_o[2]}", end="\r\n") |
|
|
|
|
print(f" {_o[0]['id']} - {_o[1]} - {_o[2]}", end="") |
|
|
|
|
if _o[2] < _frame_count: |
|
|
|
|
continue |
|
|
|
|
wf = _o[2] - _o[1] |
|
|
|
@ -396,6 +467,7 @@ while True:
|
|
|
|
|
W4A[k]["objects"] = [ |
|
|
|
|
_ for _ in W4A[_area_id]["objects"] if _[0]["id"] != _o[0]["id"] |
|
|
|
|
] |
|
|
|
|
print(f" | tracked #{len(trackers)}") |
|
|
|
|
for obj, _s, _e in cleanups: |
|
|
|
|
print( |
|
|
|
|
f" {obj['id']} CLEANED UP should found at {_e - _frame_count} ago" |
|
|
|
|