Skip to content

Commit

Permalink
Add fixes for minor bugs and more
Browse files Browse the repository at this point in the history
- Add minor bug fixes
- Add example 03 for multithreading
- Improve overall performance
- Update and improve documentation
  • Loading branch information
rathaROG committed Apr 11, 2024
1 parent bb0a032 commit 61990ad
Show file tree
Hide file tree
Showing 20 changed files with 189 additions and 100 deletions.
1 change: 1 addition & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The examples below help you make the most use of **VSenseBox**. Before you try t

examples/example_01
examples/example_02
examples/example_03

|
15 changes: 15 additions & 0 deletions docs/examples/example_03.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Example 03: Detect and track objects in multithreading
======================================================

- **Description:** Use VSense to detect and track objects in a video in multithreading.
- **Featuring:**
- :py:class:`VSense` | :py:class:`vsensebox.vsense.vsense.VSense`
- :py:func:`draw_boxes` | :py:func:`vsensebox.utils.visualizetools.draw_boxes`

ℹ️ **Source code and input file(s)** -> `{vsensebox repo}/examples`_

.. _{vsensebox repo}/examples: https://github.com/rathaumons/vsensebox/tree/main/examples

.. literalinclude:: ../../examples/example_03.py
:encoding: latin-1

3 changes: 3 additions & 0 deletions examples/centroid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
tracker: Centroid
max_spread: 48
pref_y: Top # Top/Center/Bottom
66 changes: 66 additions & 0 deletions examples/example_03.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Example 03: Detect and track objects in multithreading

import cv2
import threading
from vsensebox import VSense
from vsensebox.utils.visualizetools import draw_boxes


def detect_and_track(vsense, input_video, det_yaml, trk_yaml, name="Detect & Track"):

# Read video
cap = cv2.VideoCapture(input_video)

# Loop each frame
while cap.isOpened():

hasFrame, frame = cap.read()
if hasFrame:

# Detect object using local YAML config
vsense.detect(img=frame,
config_yaml=det_yaml,
img_is_mat=True)

# Track object using local YAML config
vsense.track(img=frame,
config_yaml=trk_yaml,
img_is_mat=True)

# Draw bounding boxes of the detected objects
frame = draw_boxes(
frame, ids=vsense.assets.ids,
boxes_xyxy=vsense.assets.boxes_xyxy,
boxes_confs=vsense.assets.boxes_confs
)

# Display
cv2.imshow("VSenseBox: Example 03 - " + name, frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break

cap.release()


if __name__ == '__main__':

vs1 = VSense()
vs2 = VSense()

vs1_thread = threading.Thread(
target=detect_and_track,
args=(vs1, "gta.mp4", "yolo_ultralytics_v8n.yaml", "sort.yaml", "VSense 1")
)

vs2_thread = threading.Thread(
target=detect_and_track,
args=(vs2, "gta.mp4", "yolo_ultralytics_v8n.yaml", "centroid.yaml", "VSense 2")
)

vs1_thread.start()
vs2_thread.start()
vs1_thread.join()
vs2_thread.join()

13 changes: 10 additions & 3 deletions vsensebox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@


from vsensebox.vsense import VSense
from vsensebox.config.configurator import reset
from vsensebox.gui import config
from vsensebox.gui import config, reset
from vsensebox.utils.about import docs, github

__version__ = "0.0.3"
__author__ = "Ratha SIV"
__description__ = "VSenseBox - Python toolbox for visual sensing."
__homepage__ = "https://rathaumons.github.io/vsensebox"
__url__ = "https://github.com/rathaumons/vsensebox.git"

__all__ = ("_version__", "VSense", "config", "reset")
__all__ = (
"__version__",
"VSense",
"config",
"reset",
"docs",
"github"
)

9 changes: 3 additions & 6 deletions vsensebox/config/confighelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@
import yaml
from yaml.loader import SafeLoader

from vsensebox.config.strings import UnifiedStrings
from .strings import USTR
from vsensebox.utils.commontools import getAbsPathFDS, isExist
from vsensebox.utils.logtools import add_error_log


unified_strings = UnifiedStrings()


def isDictString(input_string):
"""Check whether the :obj:`input_string` is a valid raw dictionary.
Expand Down Expand Up @@ -228,7 +225,7 @@ def dumpDocDict(output_file, doc, header):
if str(value) == "None" or value is None:
value = "null # NULL=Null=null is None in Python"
if key == "detector" or key == "tracker":
value = unified_strings.getUnifiedFormat(value)
value = USTR.getUnifiedFormat(value)
dumping.write('%s: %s\n' % (key, value))
except ValueError as e:
msg = 'dumpDocDict() -> ' + str(e)
Expand Down Expand Up @@ -257,7 +254,7 @@ def dumpListDocDict(output_file, doc_list, header):
if str(value) == "None" or value is None:
value = "null # NULL=Null=null is None in Python"
if key == "detector" or key == "tracker":
value = unified_strings.getUnifiedFormat(value)
value = USTR.getUnifiedFormat(value)
dumping.write('%s: %s\n' % (key, value))
if sep_index < len(doc_list):
dumping.write("---\n")
Expand Down
46 changes: 19 additions & 27 deletions vsensebox/config/configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
# Copyright (C) 2024 UMONS-Numediart


from .strings import UnifiedStrings
from .strings import USTR
from .confighelper import getCFGDict, getListCFGDoc, dumpDocDict, dumpListDocDict
from vsensebox.utils.logtools import add_warning_log, add_error_log, add_info_log
from vsensebox.utils.logtools import add_warning_log, add_error_log
from vsensebox.utils.commontools import (joinFPathFull, getGlobalRootDir,
getAdaptiveAbsPathFDS, normalizePathFDS)

unified_strings = UnifiedStrings()
internal_root_dir = getGlobalRootDir()
internal_config_dir = joinFPathFull(internal_root_dir, 'config')
detectors_config_dir = joinFPathFull(internal_config_dir, 'detectors')
trackers_config_dir = joinFPathFull(internal_config_dir, 'trackers')
IN_ROOT_DIR = getGlobalRootDir()
IN_DATA_DIR = joinFPathFull(IN_ROOT_DIR, 'data')
IN_CONFIG_DIR = joinFPathFull(IN_ROOT_DIR, 'config')
DET_CONFIG_DIR = joinFPathFull(IN_CONFIG_DIR, 'detectors')
TRK_CONFIG_DIR = joinFPathFull(IN_CONFIG_DIR, 'trackers')
STR_CONFIG_DIR = joinFPathFull(IN_CONFIG_DIR, 'strings')


class BaseCGF(object):
Expand All @@ -31,7 +32,7 @@ class BaseCGF(object):
"""

def __init__(self):
self.unified_strings = unified_strings
self.unified_strings = USTR
self.configs = {}

def loadDoc(self, input):
Expand Down Expand Up @@ -130,7 +131,7 @@ def __init__(self, cfg=None, relative_to_vsensebox_root=False):
super().__init__()
self.from_dir = ""
if relative_to_vsensebox_root:
self.from_dir = internal_root_dir
self.from_dir = IN_ROOT_DIR
if cfg is not None:
self.set(cfg)

Expand Down Expand Up @@ -179,9 +180,9 @@ def getDocument(self):
"imgsz": self.imgsz,
"min_width": self.min_width,
"classes": self.classes,
"class_file": normalizePathFDS(internal_root_dir, self.class_file),
"model_cfg_file": normalizePathFDS(internal_root_dir, self.model_cfg_file),
"model_file": normalizePathFDS(internal_root_dir, self.model_file),
"class_file": normalizePathFDS(IN_ROOT_DIR, self.class_file),
"model_cfg_file": normalizePathFDS(IN_ROOT_DIR, self.model_cfg_file),
"model_file": normalizePathFDS(IN_ROOT_DIR, self.model_file),
}
return yolocs_doc

Expand Down Expand Up @@ -240,7 +241,7 @@ def __init__(self, cfg=None, relative_to_vsensebox_root=False):
super().__init__()
self.from_dir = ""
if relative_to_vsensebox_root:
self.from_dir = internal_root_dir
self.from_dir = IN_ROOT_DIR
if cfg is not None:
self.set(cfg)

Expand Down Expand Up @@ -295,7 +296,7 @@ def getDocument(self):
"device": self.device,
"max_det": self.max_det,
"line_width": self.line_width,
"model_file": normalizePathFDS(internal_root_dir, self.model_file),
"model_file": normalizePathFDS(IN_ROOT_DIR, self.model_file),
}
return yolout_doc

Expand Down Expand Up @@ -336,7 +337,7 @@ def __init__(self, cfg=None, relative_to_vsensebox_root=False):
super().__init__()
self.from_dir = ""
if relative_to_vsensebox_root:
self.from_dir = internal_root_dir
self.from_dir = IN_ROOT_DIR
if cfg is not None:
self.set(cfg)

Expand Down Expand Up @@ -418,7 +419,7 @@ def __init__(self, cfg=None, relative_to_vsensebox_root=False):
super().__init__()
self.from_dir = ""
if relative_to_vsensebox_root:
self.from_dir = internal_root_dir
self.from_dir = IN_ROOT_DIR
if cfg is not None:
self.set(cfg)

Expand Down Expand Up @@ -509,7 +510,7 @@ def __init__(self, cfg=None, relative_to_vsensebox_root=False):
super().__init__()
self.from_dir = ""
if relative_to_vsensebox_root:
self.from_dir = internal_root_dir
self.from_dir = IN_ROOT_DIR
if cfg is not None:
self.set(cfg)

Expand Down Expand Up @@ -554,16 +555,7 @@ def getDocument(self):
"batch_size": self.batch_size,
"nms_max_overlap": self.nms_max_overlap,
"max_cosine_distance": self.max_cosine_distance,
"model_file": normalizePathFDS(internal_root_dir, self.model_file)
"model_file": normalizePathFDS(IN_ROOT_DIR, self.model_file)
}
return deepsort_doc

def reset():
"""Reset the internal configurations.
"""
import shutil
strings_config_dir = joinFPathFull(internal_config_dir, 'strings')
shutil.unpack_archive(joinFPathFull(strings_config_dir, 'strings.zip'), strings_config_dir)
shutil.unpack_archive(joinFPathFull(detectors_config_dir, 'detectors.zip'), detectors_config_dir)
shutil.unpack_archive(joinFPathFull(trackers_config_dir, 'trackers.zip'), trackers_config_dir)
add_info_log("Reset successfully!")
Binary file modified vsensebox/config/detectors/detectors.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion vsensebox/config/detectors/yolo_classic_v3tiny.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ conf: 0.5
imgsz: 416
min_width: 35
classes: null # NULL=Null=null is None in Python
class_file: coco.names
class_file: data/detectors/coco.names
model_cfg_file: data/detectors/yolov3-tiny.cfg
model_file: data/detectors/yolov3-tiny.weights
2 changes: 1 addition & 1 deletion vsensebox/config/detectors/yolo_classic_v4tiny.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ conf: 0.5
imgsz: 416
min_width: 35
classes: null # NULL=Null=null is None in Python
class_file: coco.names
class_file: data/detectors/coco.names
model_cfg_file: data/detectors/yolov4-tiny.cfg
model_file: data/detectors/yolov4-tiny.weights
6 changes: 4 additions & 2 deletions vsensebox/config/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from vsensebox.utils.commontools import joinFPathFull, getGlobalRootDir


default_strings_yaml = joinFPathFull(getGlobalRootDir(), "config/strings/strings.yaml")
DEFAULT_STR_YAML = joinFPathFull(getGlobalRootDir(), "config/strings/strings.yaml")

class UnifiedStrings(object):

Expand Down Expand Up @@ -37,7 +37,7 @@ class UnifiedStrings(object):
Unified string of word 'Centroid'.
"""

def __init__(self, strings_yaml=default_strings_yaml):
def __init__(self, strings_yaml=DEFAULT_STR_YAML):
"""Initailize by calling :meth:`load(strings_yaml=strings_yaml)`.
Parameters
Expand Down Expand Up @@ -114,3 +114,5 @@ def getUnifiedFormat(self, input_str):
res = input_str

return res

USTR = UnifiedStrings()
4 changes: 2 additions & 2 deletions vsensebox/gui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
# GNU General Public License v3 or later (GPLv3+)
# Copyright (C) 2024 UMONS-Numediart

from .uitools import config
from .uitools import config, reset

__all__ = "config"
__all__ = "config", "reset"
Loading

0 comments on commit 61990ad

Please sign in to comment.