Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added the feature to show frames with pedestrian's only #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
data/
*.csv
*.pyc
*.mp4
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ All available options are listed in the following table:
| `--annotate_orientation` | `False` | Annotate every track by its current orientation. |
| `--annotate_age` | `False` | Annotate every track by its current age. |
| `--show_maximized` | `False` | Show the track Visualizer maximized. Might affect performance. |
| `--ped_only` | `False` | Only render frames with pedestrians and a button to jump to the next pedestrian's initial frame. |

*Please note that drawing additional features may decrease the playback animation update rate.*

Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ loguru>=0.2.5
numpy
matplotlib>=3.0.1
opencv-python
pyqt5
pyqt5
sortedcontainers>=2.4.0
8 changes: 6 additions & 2 deletions src/run_track_visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ def create_args():
help="Show the track Visualizer maximized. Might affect performance.",
type=str2bool)

cs.add_argument('--ped_only', default=False,
help="Play frames having pedestrians only",
type=str2bool)

return vars(cs.parse_args())


Expand All @@ -82,7 +86,7 @@ def main():

# Load csv files
logger.info("Loading csv files {}, {} and {}", tracks_file, tracks_meta_file, recording_meta_file)
tracks, static_info, meta_info = read_from_csv(tracks_file, tracks_meta_file, recording_meta_file,
tracks, tracks_meta, recording_meta = read_from_csv(tracks_file, tracks_meta_file, recording_meta_file,
include_px_coordinates=True)

# Load background image for visualization
Expand All @@ -93,7 +97,7 @@ def main():
config["background_image_path"] = background_image_path

try:
visualization_plot = TrackVisualizer(config, tracks, static_info, meta_info)
visualization_plot = TrackVisualizer(config, tracks, tracks_meta, recording_meta)
visualization_plot.show()
except DataError:
sys.exit(1)
Expand Down
121 changes: 112 additions & 9 deletions src/track_visualizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from matplotlib import animation
from matplotlib.widgets import Button, TextBox

from sortedcontainers import SortedList


class TrackVisualizer(object):
def __init__(self, config, tracks, tracks_meta, recording_meta):
Expand All @@ -21,6 +23,13 @@ def __init__(self, config, tracks, tracks_meta, recording_meta):
self.dataset = config["dataset"].lower()
self.recording_name = config["recording"]
self.playback_speed = config["playback_speed"]
self.pedestrianFrameRanges = 0 # range of frames having pedestrians.
self.currentPedRange = 0

if config['ped_only']:
self.pedestrianFrameRanges = self.getFramesWithPedestrians(tracks_meta)
print(f'number of pedestrians {len(self.pedestrianFrameRanges)}')


# Load dataset specific visualization parameters from file
dataset_params_path = Path(config["visualizer_params_dir"]) / "visualizer_params.json"
Expand Down Expand Up @@ -111,6 +120,9 @@ def __init__(self, config, tracks, tracks_meta, recording_meta):
self.ax_button_next2 = self.fig.add_axes([0.60, 0.035, 0.06, 0.04])
self.ax_button_reset = self.fig.add_axes([0.67, 0.035, 0.06, 0.04])

if config['ped_only']:
self.ax_button_nextPed = self.fig.add_axes([0.74, 0.035, 0.09, 0.04])

# Define the widgets
self.textbox_frame = TextBox(self.ax_textbox, 'Set Frame ', initial=str(self.minimum_frame))

Expand All @@ -132,8 +144,9 @@ def __init__(self, config, tracks, tracks_meta, recording_meta):
self.stop_image = plt.imread("../assets/button_icons/stop.png")
self.button_play = Button(self.ax_button_play, '', image=self.play_image)
self.button_play.ax.axis('off')

self.button_reset = Button(self.ax_button_reset, 'Reset')
if config['ped_only']:
self.button_nextPed = Button(self.ax_button_nextPed, 'Next Ped')

# Define the callbacks for the widgets' actions
self.button_previous.on_clicked(self._on_click_button_previous)
Expand All @@ -142,6 +155,8 @@ def __init__(self, config, tracks, tracks_meta, recording_meta):
self.button_next2.on_clicked(self._on_click_button_next2)
self.button_play.on_clicked(self._start_stop_animation)
self.button_reset.on_clicked(self._reset)
if config['ped_only']:
self.button_nextPed.on_clicked(self._jumpToNextPed)
self.fig.canvas.mpl_connect('key_press_event', self._on_keypress)

# Initialize main axes
Expand Down Expand Up @@ -171,6 +186,7 @@ def __init__(self, config, tracks, tracks_meta, recording_meta):
self.track_animation = animation.FuncAnimation(self.fig, self._update_figure, interval=20, blit=True,
init_func=self._clear_figure, cache_frame_data=False)


# Add listener to figure so that clicks on tracks open a plot window
self.fig.canvas.mpl_connect('pick_event', self._open_track_plots_window)

Expand All @@ -191,7 +207,9 @@ def _update_figure(self, *args):
:param args: Should be unused if called manually. If called by FuncAnimation, args contains a call counter.
:return: List of artist handles that have been updated. Needed for blitting.
"""

# if self.animation_running == False:
# self._clear_figure()
# return self.plot_handles
# Detect if the function was called manually (as FuncAnimation always adds a call counter). If the function
# is called manually, draw all objects directly.
animate = len(args) != 0
Expand Down Expand Up @@ -318,16 +336,26 @@ def _update_figure(self, *args):
fontsize=12, color="white", animated=animate)
plot_handles.append(label_current_frame)

# Update current frame
if self.current_frame == self.maximum_frame:
self.current_frame = self.minimum_frame
elif self.animation_running:
# This is the "play-speed"
self.current_frame = min(self.current_frame + self.playback_speed, self.maximum_frame)
# we are gonna jump to the next frame with pedestrian


# Update the textbox to new current frame
# Update current frame
if self.animation_running:
self.current_frame = self.getNextFrame(self.current_frame)
# print("current_frame", self.current_frame)
self.textbox_frame.set_val(self.current_frame)

# if self.current_frame == self.maximum_frame:
# self.current_frame = self.minimum_frame
# elif self.animation_running:
# # This is the "play-speed"
# self.current_frame = min(self.current_frame + self.playback_speed, self.maximum_frame)

# print("current_frame", self.current_frame)

# # Update the textbox to new current frame
# self.textbox_frame.set_val(self.current_frame)

self.plot_handles = plot_handles
return plot_handles

Expand Down Expand Up @@ -428,6 +456,7 @@ def _start_stop_animation(self, _):
self._set_controls_activation(True)

def _reset(self, _):

self.ax_button_play.images[0].set_data(self.play_image)
self.button_play.canvas.draw_idle()
self._set_controls_activation(True)
Expand Down Expand Up @@ -550,6 +579,80 @@ def _on_close_track_plots_window(self, _, track_id: int):
if track_id in self.track_info_figures:
self.track_info_figures[track_id]["main_figure"].canvas.mpl_disconnect('close_event')
self.track_info_figures.pop(track_id)

def _jumpToNextPed(self, _):
running = self.animation_running

if running:
self._start_stop_animation(None)


nextRange = self.currentPedRange + 1
if nextRange >= len(self.pedestrianFrameRanges):
nextRange = 0


self.current_frame = self.pedestrianFrameRanges[nextRange][0]
self.textbox_frame.set_val(self.current_frame)

self.currentPedRange = nextRange

if running:
self._start_stop_animation(None)


def getNextFrame(self, curFrame):

if self.config['ped_only']:
return self.getNextFrameWithPedestrians(curFrame, self.playback_speed)

if self.current_frame == self.maximum_frame:
return self.minimum_frame

return min(self.current_frame + self.playback_speed, self.maximum_frame)


def getFramesWithPedestrians(self, tracks_meta):
"""
Attributes:
tracks_meta: list of dictionary of tracks_meta_file.
Returns: a list or ranges. Each range for each pedestrian. Not optimized for multiple pedestrians in a frame.
"""
frames = SortedList([])
for track in tracks_meta:
if track['class'] == 'pedestrian':
frames.add((track['initialFrame'], track['finalFrame']))

return frames

def getNextFrameWithPedestrians(self, curFrame, skip=1):
# TODO use bijection for faster performance. use sorted containers.

if len(self.pedestrianFrameRanges) == 0:
raise Exception('No frame with pedestrian found')


nextFrame = curFrame + skip
if nextFrame >= self.maximum_frame:
self.currentPedRange = 0
return self.pedestrianFrameRanges[0][0]

for idx, range in enumerate(self.pedestrianFrameRanges):

if nextFrame <= range[0]:
self.currentPedRange = 0
return range[0]

if range[0] <= nextFrame and range[1] >= nextFrame:
if idx < self.currentPedRange:
continue
self.currentPedRange = idx
return nextFrame


# next frame is greater than all final frames
self.currentPedRange = 0
return self.pedestrianFrameRanges[0][0]


class DataError(Exception):
Expand Down