Skip to content

Commit

Permalink
various bug fixes and improvements to using AIR 'exporter' output for…
Browse files Browse the repository at this point in the history
…mat + code cleanup
  • Loading branch information
Pasi Pyrrö committed Jan 14, 2022
1 parent 9fc9f57 commit 1f8aff6
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 53 deletions.
14 changes: 9 additions & 5 deletions airutils/dataset/detection_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,16 @@ def __init__(self, output_path, fps, in_resolution, out_resolution, inverse_samp
self.inverse_sampling_rate = inverse_sampling_rate
self._detection_timeseries = [[[0,0]]]
self._video_idx = 0
self._num_detections = 0
self._num_detections = [0]


@property
def detection_timeseries(self):
# TODO: don't scale x-axis (irrelevant in ViDAR plots)
return np.array(self._detection_timeseries[self._video_idx]) / self._num_detections
if self._num_detections[self._video_idx] > 0:
return np.array(self._detection_timeseries[self._video_idx]) / self._num_detections[self._video_idx]
else:
return None


def __enter__(self):
Expand All @@ -74,8 +77,8 @@ def update_timeseries(self, detections, frame_no, frame_offset=0):
sum_confidence = np.sum([d.confidence if not math.isnan(d.confidence)
else d.detection_history[-1]
for d in detections])
self._num_detections += len(detections)
current_timestamp = (frame_no + frame_offset) / self.fps
self._num_detections[self._video_idx] += len(detections)
current_timestamp = (frame_no + frame_offset) / self.fps
last_time_point = self._detection_timeseries[self._video_idx][-1][0] \
if self._detection_timeseries[self._video_idx] else 0
if math.isclose(last_time_point, current_timestamp):
Expand Down Expand Up @@ -107,7 +110,7 @@ def add_detections_at_frame(self, detections, frame_no):
},
"label": self.map_labels.get(d.object_class, d.object_class),
"id": self.running_id,
"timestamp": 1000. * (self.frame_offset + frame_no) / self.fps,
"timestamp": 1000. * (self.frame_offset + frame_no) / self.fps + 1000.,
"note" : note
})
self.running_id += 1
Expand All @@ -116,6 +119,7 @@ def add_detections_at_frame(self, detections, frame_no):
def switch_video(self):
self._video_idx += 1
self._detection_timeseries.append([[0,0]])
self._num_detections.append(0)


def save(self, output_path=None):
Expand Down
59 changes: 33 additions & 26 deletions airutils/imtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,32 +461,39 @@ def get_contour_mean_speeds(contours, motion_field):

def plot_detection_timeseries(detection_frequencies, filename=None, mode="lineplot", num_frames=1000, figsize=(22, 1),
smoothing=False, crop_image=True):

x = detection_frequencies[:,0]
y = detection_frequencies[:,1]
if mode == "barplot":
if smoothing:
from scipy.signal import savgol_filter
y = savgol_filter(y, 5, 3)
plt.figure(figsize=figsize)
plt.bar(x, y,
color="magenta",
width=0.8/num_frames,
edgecolor="black",
align="edge",
linewidth=1)
elif mode == "lineplot":
from scipy.interpolate import interp1d
fig, ax = plt.subplots(figsize=figsize)
# p = np.polyfit(x, y, 3)
# f = interp1d(x, y, kind="cubic")
f = interp1d(x, y, kind="quadratic")
x = np.linspace(x[0], x[-1], num=min(num_frames, 10000), endpoint=True)
y = f(x)
ax.fill_between(x, 0, y, facecolor='magenta')
plt.plot(x, y,
color="black",
linewidth=2)
plt.clf()
plt.cla()
if detection_frequencies is None:
# plot "empty" time series
x = np.linspace(0., 1., num=num_frames)
y = np.zeros((num_frames,))
plt.plot(x, y, color="black", linewidth=2)
else:
x = detection_frequencies[:,0]
y = detection_frequencies[:,1]
if mode == "barplot":
if smoothing:
from scipy.signal import savgol_filter
y = savgol_filter(y, 5, 3)
plt.figure(figsize=figsize)
plt.bar(x, y,
color="magenta",
width=0.8/num_frames,
edgecolor="black",
align="edge",
linewidth=1)
elif mode == "lineplot":
from scipy.interpolate import interp1d
fig, ax = plt.subplots(figsize=figsize)
# p = np.polyfit(x, y, 3)
# f = interp1d(x, y, kind="cubic")
f = interp1d(x, y, kind="quadratic")
x = np.linspace(x[0], x[-1], num=min(num_frames, 10000), endpoint=True)
y = f(x)
ax.fill_between(x, 0, y, facecolor='magenta')
plt.plot(x, y,
color="black",
linewidth=2)
if filename:
assert filename.endswith(".png"), "Only png file format supported!"
plt.axis("off")
Expand Down
4 changes: 2 additions & 2 deletions airutils/video/videowriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,11 @@ def __enter__(self):
if not self.placeholder:
super().init()
self.init()
return self
return self

def __exit__(self, type, value, traceback):
if not self.placeholder:
self.close()
super().close()

def init(self):
if self._running:
Expand All @@ -123,6 +122,7 @@ def close(self):
with self._lock:
self._running = False
self._writer.join()
super().close()

def write(self, frame, title=None):
if not self.placeholder:
Expand Down
9 changes: 4 additions & 5 deletions airutils/video/vidtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,16 @@ def extract_subtitles(video_path, output_path=None, verbose=True):
''' extracts subtitles track from a video file into srt file,
requires ffmpeg installed'''
folder, video_file = os.path.split(video_path)
temp = os.getcwd()
if output_path is None:
os.chdir(folder)
out_file = re.sub(r"\.[a-zA-Z0-9]{3,4}$", ".srt", video_file)
out_file = os.path.join(folder, re.sub(r"\.[a-zA-Z0-9]{3,4}$", ".srt", video_file))
else:
out_file = output_path

cmd = f"ffmpeg -y -i {video_file} {out_file}"
cmd = f"ffmpeg -y -i {video_path} {out_file}"
if not verbose:
with open(os.devnull, "w") as f:
completed = subprocess.run(cmd, shell=True, stdout=f, stderr=f)
else:
completed = subprocess.run(cmd, shell=True)
completed.check_returncode()
os.chdir(temp)
return os.path.join(folder, out_file)
26 changes: 11 additions & 15 deletions video_detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,10 @@

import os
import re
import gc
import cv2
import sys
import time
import argparse
import functools
import itertools
import numpy as np
from collections import deque

# define absolute folder locations
current_dir = os.path.dirname(os.path.realpath(__file__))
Expand Down Expand Up @@ -93,6 +88,15 @@ def resolve_output_type(output):
elif os.path.isdir(output) or "." not in os.path.basename(output) or output.endswith(os.path.sep):
return valid_output_types[3] # images
return valid_output_types[2] # exporter object


def parse_config_file(config_path):
import importlib
config = importlib.import_module("config." + config_path.replace(".py",
"").replace("config", "").replace(os.path.sep, ""))
for key, value in config.__dict__.items():
if not key.startswith("__"):
setattr(Params, key, value)


def parse_args(parser=None):
Expand Down Expand Up @@ -157,12 +161,7 @@ def parse_args(parser=None):
Params.CONFIG_FILE = args.config_file

if Params.CONFIG_FILE:
import importlib
config = importlib.import_module("config." + Params.CONFIG_FILE.replace(".py",
"").replace("config", "").replace(os.path.sep, ""))
for key, value in config.__dict__.items():
if not key.startswith("__"):
setattr(Params, key, value)
parse_config_file(Params.CONFIG_FILE)
else:
if not args.input:
parser.print_help(sys.stderr)
Expand Down Expand Up @@ -332,16 +331,14 @@ def main(exporter=None):
if Params.OUTPUT_TYPE == "video":
out_path = os.path.join(
dir_name, vid_file_name + "_air_output" + vid_file_ext)
elif Params.OUTPUT_TYPE == "json":
elif Params.OUTPUT_TYPE in {"json", "exporter"}:
out_path = os.path.join(
dir_name, vid_file_name + ".json")
elif Params.OUTPUT_TYPE == "images":
out_path = os.path.join(
dir_name, vid_file_name + "_air_output")
if not os.path.exists(out_path):
os.makedirs(out_path, exist_ok=True)
else:
out_path = ""
else:
if not os.path.exists(Params.OUTPUT_PATH):
if Params.OUTPUT_TYPE == "images":
Expand All @@ -360,7 +357,6 @@ def main(exporter=None):
print("\n".join([f"{k}: {v}" for k, v in vars(KalmanConfig).items() if not k.startswith("__")]))
print("")

CHUNK_SIZE = Params.DETECT_EVERY_NTH_FRAME
if Params.PROCESS_NUM_FRAMES is not None:
if Params.FRAME_OFFSET is not None:
END_IDX = Params.PROCESS_NUM_FRAMES + Params.FRAME_OFFSET
Expand Down

0 comments on commit 1f8aff6

Please sign in to comment.