Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 17 additions & 73 deletions examples/people_counting/people_counting.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,65 +20,7 @@ def make_parser():


class Person(vqpy.VObjBase):

@vqpy.property()
@vqpy.stateful(4)
def direction_vector(self):
tlbr_c, tlbr_p = self.getv('tlbr'), self.getv('tlbr', -5)
if tlbr_c is None or tlbr_p is None:
return None
center_c = (tlbr_c[:2] + tlbr_c[2:]) / 2
center_p = (tlbr_p[:2] + tlbr_p[2:]) / 2
diff = center_c - center_p
return int(diff[0]), int(diff[1])

@vqpy.property()
@vqpy.stateful(4)
def direction(self):
def denoise(target, reference):
THRESHOLD = 10
if target != 0 and reference / target >= THRESHOLD:
target = 0
return target

def get_name(value, pos_name, neg_name):
if value > 0:
result = pos_name
elif value < 0:
result = neg_name
else:
result = ""
return result

def get_center(tlbr):
return (tlbr[:2] + tlbr[2:]) / 2

def most_frequent(List):
from collections import Counter
occurence_count = Counter(List)
return occurence_count.most_common(1)[0][0]

hist_len = 5
tlbr_past = [self.getv("tlbr", (-1)*i) for i in range(1, 1 + hist_len)]
for value in tlbr_past:
if value is None:
return None

centers = list(map(get_center, tlbr_past))
diffs = [centers[i+1] - centers[i] for i in range(hist_len - 1)]

diff_xs = [denoise(diff[0], diff[1]) for diff in diffs]
diff_ys = [denoise(diff[1], diff[0]) for diff in diffs]

horizontal = most_frequent([get_name(diff_x, "right", "left")
for diff_x in diff_xs])
vertical = most_frequent([get_name(diff_y, "bottom", "top")
for diff_y in diff_ys])
direction = vertical + horizontal
if direction == "":
direction = None

return direction
pass


class CountPersonOnCrosswalk(vqpy.QueryBase):
Expand All @@ -93,23 +35,26 @@ def set_output_configs() -> vqpy.OutputConfig:
@staticmethod
def setting() -> vqpy.VObjConstraint:

CROSSWALK_REGION_1 = [(731, 554), (963, 564), (436, 1076), (14, 1076)]
CROSSWALK_REGION_2 = [(1250, 528), (1292, 473),
(1839, 492), (1893, 547)]
CROSSWALK_REGIONS = [CROSSWALK_REGION_1, CROSSWALK_REGION_2]
CROSSWALK_REGION = [
(0, 295),
(488, 1),
(684, 1),
(315, 479),
(0, 479)]

filter_cons = {"__class__": lambda x: x == Person,
"bottom_center": vqpy.utils.within_regions(
CROSSWALK_REGIONS
CROSSWALK_REGION
)}
select_cons = {"track_id": None,
"direction": None,
}
return vqpy.VObjConstraint(filter_cons=filter_cons,
select_cons=select_cons,
filename='on_crosswalk')


class CountPersonHeadLeft(CountPersonOnCrosswalk):
class CountPersonHeadTopright(CountPersonOnCrosswalk):

@staticmethod
def set_output_configs() -> vqpy.OutputConfig:
Expand All @@ -120,17 +65,16 @@ def set_output_configs() -> vqpy.OutputConfig:

@staticmethod
def setting() -> vqpy.VObjConstraint:
filter_cons = {"direction": lambda x: "left" in x}
filter_cons = {"direction": lambda x: x == "topright"}
select_cons = {"track_id": None,
"direction": None,
"direction_vector": None
}
return vqpy.VObjConstraint(filter_cons=filter_cons,
select_cons=select_cons,
filename='head_left')
filename='head_topright')


class CountPersonHeadRight(CountPersonOnCrosswalk):
class CountPersonHeadBottomleft(CountPersonOnCrosswalk):

@staticmethod
def set_output_configs() -> vqpy.OutputConfig:
Expand All @@ -141,22 +85,22 @@ def set_output_configs() -> vqpy.OutputConfig:

@staticmethod
def setting() -> vqpy.VObjConstraint:
filter_cons = {"direction": lambda x: "right" in x}
filter_cons = {"direction": lambda x: "bottomleft" in x}
select_cons = {"track_id": None,
"direction": None,
"direction_vector": None
}
return vqpy.VObjConstraint(filter_cons=filter_cons,
select_cons=select_cons,
filename='head_right')
filename='head_bottomleft')


if __name__ == '__main__':
args = make_parser().parse_args()
register("yolox", YOLOXDetector, "yolox_x.pth")
vqpy.launch(cls_name=vqpy.COCO_CLASSES,
cls_type={"person": Person},
tasks=[CountPersonHeadLeft(), CountPersonHeadRight()],
# tasks=[CountPersonOnCrosswalk()],
tasks=[CountPersonHeadTopright(), CountPersonHeadBottomleft()],
video_path=args.path,
save_folder=args.save_folder,
detector_name="yolox",
Expand Down
2 changes: 1 addition & 1 deletion examples/people_counting/yolox_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def __init__(self, model_path, device="gpu", fp16=True):
exp = get_exp(None, "yolox_x")
exp.test_conf = 0.3
exp.nmsthre = 0.3
exp.test_size = (640, 640)
exp.test_size = (480, 854)

model = exp.get_model()
model_info = get_model_info(model, exp.test_size)
Expand Down
2 changes: 1 addition & 1 deletion vqpy/base/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def vqpy_update(self, frame: FrameInterface):
total_vobj_num_data = {
OUTPUT_TOTAL_VOBJ_NUM_NAME: len(self._total_ids)
}
if frame_id == 1:
if frame_id == 0:
self._query_data = [total_vobj_num_data]
else:
assert OUTPUT_TOTAL_VOBJ_NUM_NAME in self._query_data[0]
Expand Down
55 changes: 55 additions & 0 deletions vqpy/function/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,58 @@ def bottom_center_coordinate(obj, tlbr):
x = (tlbr[0] + tlbr[2]) / 2
y = tlbr[3]
return [(x, y)]


@vqpy_func_logger(['tlbr'], ['direction'], ['tlbr'], required_length=5)
def direction(obj, tlbr):
"""
The general direction computed with the past 5 historical frames.
There are 9 posible results:
"top", "topright", "right", "bottomright",
"bottom", "bottomleft", "left", "topleft",
and None, which means the vobj stays still in the past 5 frames.
"""
def denoise(target, reference):
THRESHOLD = 10
if target != 0 and reference / target >= THRESHOLD:
target = 0
return target

def get_name(value, pos_name, neg_name):
if value > 0:
result = pos_name
elif value < 0:
result = neg_name
else:
result = ""
return result

def get_center(tlbr):
return (tlbr[:2] + tlbr[2:]) / 2

def most_frequent(List):
from collections import Counter
occurence_count = Counter(List)
return occurence_count.most_common(1)[0][0]

hist_len = 5
tlbr_past = [obj.getv("tlbr", (-1)*i) for i in range(1, 1 + hist_len)]
for value in tlbr_past:
if value is None:
return [None]

centers = list(map(get_center, tlbr_past))
diffs = [centers[i+1] - centers[i] for i in range(hist_len - 1)]

diff_xs = [denoise(diff[0], diff[1]) for diff in diffs]
diff_ys = [denoise(diff[1], diff[0]) for diff in diffs]

horizontal = most_frequent([get_name(diff_x, "right", "left")
for diff_x in diff_xs])
vertical = most_frequent([get_name(diff_y, "bottom", "top")
for diff_y in diff_ys])
direction = vertical + horizontal
if direction == "":
direction = None

return [direction]
18 changes: 18 additions & 0 deletions vqpy/utils/predicate_funcs.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@

def within_regions(regions):
"""
A predicate function that check whether the coordinate is in the regions.
This function should be used as the value of `filter_cons` dictionary.
and its key should be a coordinate property. The function will return true
if the computed coordinate values of the property is in the regions.

:param regions: one region or a list of regions, where region should be
a list of coordinates and coordinates is a tuple of (x, y).
The coordinates should be the exterior points of a Polygon.

"""
if type(regions[0]) is tuple:
regions = [regions]

def point_within_regions(coordinate):
from shapely.geometry import Point, Polygon
point = Point(coordinate)
for region in regions:
poly = Polygon(region)
if poly.area <= 0:
raise ValueError(f"The area with in region {region} is less"
f"than zero. Please check your region"
f"coordinates.")
if point.within(poly):
return True
return False
Expand Down