Browse Source

Handling transition

dev
sipp11 5 years ago
parent
commit
e27db785b2
  1. 162
      src/main.py
  2. 81
      src/utils.py

162
src/main.py

@ -17,6 +17,7 @@ from utils import (
box_distance,
get_heading,
get_avg_heading,
OBJ_LEAVING_COND,
)
pp = pprint.PrettyPrinter(indent=2)
@ -53,7 +54,7 @@ args = vars(ap.parse_args())
# load the COCO class labels our YOLO model was trained on
# labelsPath = os.path.sep.join([args["yolo"], "coco.names"])
labelsPath = "/Users/sipp11/syncthing/dropbox/tracking-obj/mytrain.names"
labelsPath = "../../syncthing/dropbox/tracking-obj/mytrain.names"
LABELS = open(labelsPath).read().strip().split("\n")
# 0 person, 1 wheelchair, 2 bicycle, 3 motorbike, 4 car, 5 bus, 6 truck
@ -62,8 +63,8 @@ np.random.seed(42)
COLORS = np.random.randint(0, 255, size=(len(LABELS), 3), dtype="uint8")
# derive the paths to the YOLO weights and model configuration
weightsPath = "/Users/sipp11/syncthing/dropbox/tracking-obj/mytrain_final.weights"
configPath = "/Users/sipp11/syncthing/dropbox/tracking-obj/mytrain.cfg"
weightsPath = "../../syncthing/dropbox/tracking-obj/mytrain_final.weights"
configPath = "../../syncthing/dropbox/tracking-obj/mytrain.cfg"
# load our YOLO object detector trained on COCO dataset (80 classes)
@ -74,11 +75,11 @@ ln = net.getLayerNames()
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]
def detect_stuffs(frame):
def detect_stuffs(_frame):
# construct a blob from the input frame and then perform a forward
# pass of the YOLO object detector, giving us our bounding boxes
# and associated probabilities
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
blob = cv2.dnn.blobFromImage(_frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
start = time.time()
layerOutputs = net.forward(ln)
@ -135,21 +136,6 @@ def detect_stuffs(frame):
if len(idxs) == 0:
continue
# NOTE: we are not going to draw anything from DETECTION,
# only from tracking one
# loop over the indexes we are keeping
# for i in idxs.flatten():
# # extract the bounding box coordinates
# (x, y) = (boxes[i][0], boxes[i][1])
# (w, h) = (boxes[i][2], boxes[i][3])
# # draw a bounding box rectangle and label on the frame
# color = [int(c) for c in COLORS[classIDs[i]]]
# cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
# text = "{}: {:.4f}".format(LABELS[classIDs[i]], confidences[i])
# cv2.putText(
# frame, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2
# )
return idxs, boxes, confidences, classIDs, start, end
@ -196,15 +182,17 @@ while True:
# grab the updated bounding box coordinates (if any) for each
# object that is being tracked
(success, boxes) = cv_trackers.update(frame)
print("success", success)
print("boxes", boxes)
# print("success", success)
# print("boxes", boxes)
untracking = []
# loop over the bounding boxes and draw then on the frame
if success:
obj_cnt = len(boxes)
print(f"obj_cnt: ", obj_cnt, 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"]
@ -212,7 +200,7 @@ while True:
curr_distance = box_distance(box, _last_pos)
last_distance = trackers[idx]["distance"]
trackers[idx]["distance"] = curr_distance
trackers[idx]["curr_position"] = [int(v) for v in box]
trackers[idx]["curr_position"] = box # [int(v) for v in box]
_heading = get_heading(_x, _y, x, y)
@ -225,7 +213,7 @@ while True:
if trackers[idx]["still"] == 0:
trackers[idx]["heading"] = [_heading] + trackers[idx]["heading"]
trackers[idx]["heading"] = trackers[idx]["heading"][:30]
trackers[idx]["heading"] = trackers[idx]["heading"][:20]
if trackers[idx]["still"] > 30 or x < 5 or x > 1250:
untracking.append(trackers[idx])
@ -233,29 +221,63 @@ while True:
tk = trackers[idx]
# check if it's hit the first
avg_heading = get_avg_heading(trackers[idx]["heading"])
print(f" ---> avg heading: ", avg_heading)
if (
tk["first"]["id"] == 4
and avg_heading == "N"
and (x > 140 or x + w > 175)
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("gone!")
_nid = f"id_5"
print("REACH condition: Y")
REACH_condition = True
if not REACH_condition:
continue
# 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="")
if _nid not in W4A:
print(f">>add AREA {_nid} to W4A", end="")
W4A[_nid] = {"objects": []}
_expected_frame = 30 * 4 # at least 4 sec later
# 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(trackers[idx])
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])
print(
f"[{tk['id']}-{tk['type']}] (x,y)=({x},{y})"
f" | still #{tk['still']} | distance: "
f"{last_distance:.3f} -> {curr_distance:.3f}"
)
_htxt = ",".join(trackers[idx]["heading"])
print(f" ------ heading: {_htxt}")
if GONE:
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]]
@ -270,6 +292,20 @@ while True:
2,
)
# Cleanup Tracker
if untracking:
ut_ids = [_["id"] for _ in untracking] # untracking ids
cv_trackers.clear()
cv_trackers = cv2.MultiTracker_create()
# 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"]))
print(f"=== AFTER CLEANUP ---- UNTRACKING ===")
print(f" cv #{len(cv_trackers.getObjects())} trackers #{len(trackers)}")
# only detect once a sec
if _frame_count % 15 == 1:
idxs, boxes, confidences, classIDs, start, end = detect_stuffs(frame)
@ -291,31 +327,30 @@ while True:
continue
_x, _y, _w, _h = t["curr_position"]
print(f"[{t['id']}] - {t['type']}")
# print(f"[{t['id']}] - {t['type']}")
is_same = is_it_the_same_obj(x, y, w, h, _x, _y, _w, _h, id=t["id"])
if is_same:
break
if not is_same:
gid = None
if found_at["id"] == 5:
print(f"FOUND AT 5 ON {_frame_count}")
_po = W4A["id_5"]["objects"]
_po = [_ for _ in _po if _frame_count > _[2]]
_po = sorted(_po, key=lambda kk: kk[2])
print(' ------ ', _po)
_area_id = f"id_{found_at['id']}"
if _area_id in W4A:
# check candidates which has "matched" opportunity too
_po = W4A[_area_id]["objects"]
_po = [_ for _ in _po if _frame_count > _[2]] # opportunity
_po = sorted(_po, key=lambda kk: kk[2]) # first one first
if _po:
gid = _po[0][0]["id"]
# remove this id out of next W4A
W4A["id_5"]["objects"] = [
_ for _ in W4A["id_5"]["objects"] if _[0]["id"] == gid
W4A[_area_id]["objects"] = [
_ for _ in W4A[_area_id]["objects"] if _[0]["id"] != gid
]
print(f" >> possibly this obj: ", _po)
# add tracker to this obj
# create a new object tracker for the bounding box and add it
# to our multi-object tracker
# tracker = OPENCV_OBJECT_TRACKERS[args["tracker"]]()
# trackers.add(tracker, frame, box)
print(f" --- {len(_po)} candicate: picked id={gid}")
else:
print(f" --- no candidate")
# create tracker and add to multi-object tracker
_tracker = OPENCV_OBJECT_TRACKERS["csrt"]()
bbox = (x, y, w, h)
cv_trackers.add(_tracker, frame, bbox)
@ -324,7 +359,7 @@ while True:
"type": _class,
"curr_position": bbox,
"heading": [],
"first": found_at,
"origin": found_at,
"distance": -1,
"last_position": bbox,
"still": 0,
@ -332,25 +367,22 @@ while True:
if gid is None:
tracker_counter += 1
trackers.append(t)
print(f"trackers ADD - now total #{len(trackers)}")
print(f"trackers ADDED - now total #{len(trackers)}")
pp.pprint(t)
# print(f" i -> {i} ({x},{y}), {w},{h} ({x + w},{y + h})")
_what = ",".join([LABELS[c] for c in classIDs])
print(f"[{_frame_count:08d}] :: {_what}")
# untracking
print("untracking: ", [ut["id"] for ut in untracking])
# untracking_ids = [ut["id"] for ut in untracking]
# trackers = [tk for tk in trackers if tk["id"] not in untracking_ids]
# finished += untracking
if args["live"]:
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("w"):
while cv2.waitKey(1) & 0xFF != ord("w"):
pass
# if the `q` key was pressed, break from the loop
if key == ord("q"):
elif key == ord("q"):
break
if args["output"]:

81
src/utils.py

@ -46,9 +46,9 @@ AREAS = [
],
[
("id", 8),
("area", ((877, 224), (947, 334))),
("area", ((901, 223), (956, 342))),
("target", ["person", "wheelchair"]),
("next", [7, 9, 5]),
("next", [7, 5]),
],
[
("id", 9),
@ -62,12 +62,61 @@ AREAS = [
("target", ["person", "wheelchair"]),
("next", [9]),
],
[
("id", 11),
("area", ((875, 179), (915, 278))),
("target", ["person", "wheelchair"]),
("next", [9]),
],
]
OBJ_LEAVING_COND = [
# [
# ('origin_id', ),
# ('heading', ''),
# ('x', ),
# ('y', ),
# ('next_area', []),
# ('duration_to_next', )
# ],
[
("origin_id", 3),
("heading", "N"),
("x", 175),
("y", -1),
("next_area", [5]),
("duration_to_next", 30 * 4),
],
[
("origin_id", 4),
("heading", "N"),
("x", 175),
("y", -1),
("next_area", [5]),
("duration_to_next", 30 * 4),
],
[
('origin_id', 5),
('heading', 'N'),
('x', 715),
('y', -1),
('next_area', [11]),
('duration_to_next', 30 * 3)
],
# [
# ('origin_id', ),
# ('heading', ''),
# ('x', ),
# ('y', ),
# ('next_area', []),
# ('duration_to_next', )
# ],
]
def get_avg_heading(headings):
latest = headings[:15]
chars = collections.Counter(''.join(latest)).most_common(10)
chars = collections.Counter("".join(latest)).most_common(10)
if chars:
return chars[0][0]
return None
@ -115,7 +164,7 @@ def check_if_inside_the_boxes(x, y, w, h, _type):
is_inside = True
# if diff_x < box_w
if is_inside:
print("INSIDE!! this -> ", box)
# print("INSIDE!! this -> ", box)
return box
return False
@ -125,41 +174,41 @@ def is_it_the_same_obj(x1, y1, w1, h1, i1, j1, w2, h2, **kwargs):
object and of course, dimension too.
"""
_id = kwargs.get("id", None)
if _id:
print(" :: check against id:", _id)
# if _id:
# print(" :: check against id:", _id)
DIMENSION_SHIFT = 0.15
# we have to use centroid !! from the experience
cx1, cy1, cx2, cy2 = x1 + w1 / 2, y1 + h1 / 2, i1 + w2 / 2, j1 + h2 / 2
c_dff_x, c_dff_y = abs(cx2 - cx1), abs(cy2 - cy1)
w_shift, h_shift = w1 * DIMENSION_SHIFT, h1 * DIMENSION_SHIFT
print(" ::SAME:: shift")
print(f" ---> SHIFT --> w:{w_shift}, h:{h_shift}")
print(f" ---> centroid {c_dff_x}, {c_dff_y}")
# print(" ::SAME:: shift")
# print(f" ---> SHIFT --> w:{w_shift}, h:{h_shift}")
# print(f" ---> centroid {c_dff_x}, {c_dff_y}")
if c_dff_x > w_shift and c_dff_y > h_shift:
print(" ::SAME:: shift too much already -- NOT THE SAME")
# print(" ::SAME:: shift too much already -- NOT THE SAME")
return False
# if one inside the other
if i1 > x1 and (w1 - w2) > i1 - x1 and j1 > y1 and h1 - h2 > j1 - y1:
# one is inside the other
print(" ::SAME:: new one inside existing tracker")
# print(" ::SAME:: new one inside existing tracker")
return True
if x1 > i1 and (w2 - w1) > x1 - i1 and y1 > j1 and h2 - h1 > y1 - j1:
# one is inside the other
print(" ::SAME:: existing tracker inside new tracker")
# print(" ::SAME:: existing tracker inside new tracker")
return True
# if it's not inside the other, then we can use "size" if it's different
size1, size2 = w1 * h1, w2 * h2
# if size is larger than 20%, then it's not the same thing
print(f" ---> size {size1}, {size2}, diff % : {abs(size2 - size1)/size1}")
print(" ::SAME:: size")
# print(f" ---> size {size1}, {size2}, diff % : {abs(size2 - size1)/size1}")
# print(" ::SAME:: size")
if abs(size2 - size1) / size1 > 0.45:
print(" ::SAME:: too diff in size -- NOT THE SAME")
# print(" ::SAME:: too diff in size -- NOT THE SAME")
return False
print(" ::SAME:: last")
# print(" ::SAME:: last")
return True

Loading…
Cancel
Save