Spaces:
Runtime error
Runtime error
Commit
β’
d9c7dce
1
Parent(s):
53af29c
Bug fixes
Browse files- .gitignore +1 -0
- InferenceConfig.py +1 -1
- app.py +62 -46
- gradio_scripts/pdf_handler.py +116 -14
- gradio_scripts/result_ui.py +4 -4
- gradio_scripts/upload_ui.py +17 -17
- inference.py +6 -2
- lib/fish_eye/{associative.py β bytetrack.py} +0 -0
- lib/fish_eye/tracker.py +2 -2
- multipage_pdf.pdf +0 -0
.gitignore
CHANGED
@@ -13,4 +13,5 @@ models/*
|
|
13 |
*.jpg
|
14 |
*.aris
|
15 |
*.log
|
|
|
16 |
*.DS_STORE
|
|
|
13 |
*.jpg
|
14 |
*.aris
|
15 |
*.log
|
16 |
+
*.pdf
|
17 |
*.DS_STORE
|
InferenceConfig.py
CHANGED
@@ -20,7 +20,7 @@ NMS_IOU = 0.25 # NMS IOU
|
|
20 |
MAX_AGE = 20 # time until missing fish get's new id
|
21 |
MIN_HITS = 11 # minimum number of frames with a specific fish for it to count
|
22 |
MIN_LENGTH = 0.3 # minimum fish length, in meters
|
23 |
-
MAX_LENGTH =
|
24 |
IOU_THRES = 0.01 # IOU threshold for tracking
|
25 |
MIN_TRAVEL = 0 # Minimum distance a track has to travel
|
26 |
DEFAULT_TRACKER = TrackerType.BYTETRACK
|
|
|
20 |
MAX_AGE = 20 # time until missing fish get's new id
|
21 |
MIN_HITS = 11 # minimum number of frames with a specific fish for it to count
|
22 |
MIN_LENGTH = 0.3 # minimum fish length, in meters
|
23 |
+
MAX_LENGTH = 0 # maximum fish length, in meters
|
24 |
IOU_THRES = 0.01 # IOU threshold for tracking
|
25 |
MIN_TRAVEL = 0 # Minimum distance a track has to travel
|
26 |
DEFAULT_TRACKER = TrackerType.BYTETRACK
|
app.py
CHANGED
@@ -17,6 +17,8 @@ from InferenceConfig import InferenceConfig
|
|
17 |
|
18 |
WEBAPP_VERSION = "1.0"
|
19 |
|
|
|
|
|
20 |
#Initialize State & Result
|
21 |
state = {
|
22 |
'files': [],
|
@@ -31,7 +33,15 @@ result = {}
|
|
31 |
|
32 |
|
33 |
# Called when an Aris file is uploaded for inference
|
34 |
-
def on_aris_input(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
print(output_formats)
|
37 |
|
@@ -61,20 +71,25 @@ def on_aris_input(file_list, model_id, conf_thresh, iou_thresh, min_hits, max_ag
|
|
61 |
state['config'].enable_sort_track()
|
62 |
|
63 |
print(" ")
|
64 |
-
print("
|
65 |
print(state['config'].to_dict())
|
66 |
print(" ")
|
67 |
|
68 |
# Update loading_space to start inference on first file
|
69 |
return {
|
70 |
inference_handler: gr.update(value = str(np.random.rand()), visible=True),
|
71 |
-
components['
|
72 |
-
components['skipBtn']: gr.update(visible=True),
|
73 |
master_tabs: gr.update(selected=1)
|
74 |
}
|
75 |
|
76 |
# Called when a result zip file is uploaded for result review
|
77 |
-
def on_result_upload(
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
|
79 |
if (zip_list == None):
|
80 |
zip_list = [("static/example/example_result.zip", None)]
|
@@ -87,7 +102,6 @@ def on_result_upload(zip_list, aris_list):
|
|
87 |
state['outputs'] = ["Annotated Video", "Manual Marking", "PDF"]
|
88 |
|
89 |
component_updates = {
|
90 |
-
master_tabs: gr.update(selected=1),
|
91 |
tab_labeler: gr.update(value = len(zip_list))
|
92 |
}
|
93 |
|
@@ -214,8 +228,7 @@ def cancel_inference():
|
|
214 |
return {
|
215 |
master_tabs: gr.update(selected=0),
|
216 |
inference_handler: gr.update(visible=False),
|
217 |
-
components['
|
218 |
-
components['skipBtn']: gr.update(visible=False)
|
219 |
}
|
220 |
|
221 |
|
@@ -257,11 +270,11 @@ def load_annotation(_, progress=gr.Progress()):
|
|
257 |
annotation_info, state['frame_index'] = init_frames(annotation_dataset, result['json_result'][result_index], state['frame_index'], gp=set_progress)
|
258 |
|
259 |
# save as html element
|
260 |
-
|
261 |
|
262 |
return {
|
263 |
annotation_editor: gr.update(),
|
264 |
-
annotation_progress: gr.update(value=
|
265 |
}
|
266 |
|
267 |
# If complete, start annotation editor
|
@@ -296,7 +309,7 @@ demo = gr.Blocks()
|
|
296 |
with demo:
|
297 |
with gr.Blocks() as inner_body:
|
298 |
|
299 |
-
# Title of page
|
300 |
gr.HTML(
|
301 |
"""
|
302 |
<h1 align="center" style="font-size:xxx-large">Caltech Fisheye</h1>
|
@@ -349,6 +362,9 @@ with demo:
|
|
349 |
|
350 |
|
351 |
# Define annotation progress bar for event listeres, but unrender since it will be displayed later on
|
|
|
|
|
|
|
352 |
annotation_progress = gr.HTML("", visible=False).unrender()
|
353 |
components['annotation_progress'] = annotation_progress
|
354 |
|
@@ -356,35 +372,35 @@ with demo:
|
|
356 |
vis_components = Result_Gradio(prepare_annotation, components)
|
357 |
|
358 |
# Master Tab for annotation editing
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
|
389 |
# Disclaimer at the bottom of page
|
390 |
gr.HTML(
|
@@ -403,7 +419,7 @@ with demo:
|
|
403 |
tab_labeler = components['tab_labeler']
|
404 |
|
405 |
|
406 |
-
inference_comps = [inference_handler, master_tabs, components['
|
407 |
|
408 |
# When a file is uploaded to the input, tell the inference_handler to start inference
|
409 |
input.upload(on_aris_input, [input] + components['hyperparams'], inference_comps)
|
@@ -416,14 +432,14 @@ with demo:
|
|
416 |
result_handler.change(on_result_ready, None, vis_components + [inference_handler])
|
417 |
|
418 |
# Cancel and skip buttons
|
419 |
-
components['
|
420 |
-
components['skipBtn'].click(cancel_inference, None, inference_comps, cancels=[inference_event])
|
421 |
|
422 |
# Button to load a previous result and view visualization
|
423 |
-
components['
|
424 |
-
|
|
|
425 |
[components['result_input'], components['result_aris_input']],
|
426 |
-
vis_components + [
|
427 |
)
|
428 |
|
429 |
demo.queue().launch()
|
|
|
17 |
|
18 |
WEBAPP_VERSION = "1.0"
|
19 |
|
20 |
+
enable_annotation_editor = False
|
21 |
+
|
22 |
#Initialize State & Result
|
23 |
state = {
|
24 |
'files': [],
|
|
|
33 |
|
34 |
|
35 |
# Called when an Aris file is uploaded for inference
|
36 |
+
def on_aris_input(
|
37 |
+
file_list,
|
38 |
+
model_id,
|
39 |
+
conf_thresh, iou_thresh,
|
40 |
+
min_hits, max_age,
|
41 |
+
associative_tracker, boost_power, boost_decay, byte_low_conf, byte_high_conf,
|
42 |
+
min_length, max_length, min_travel,
|
43 |
+
output_formats
|
44 |
+
):
|
45 |
|
46 |
print(output_formats)
|
47 |
|
|
|
71 |
state['config'].enable_sort_track()
|
72 |
|
73 |
print(" ")
|
74 |
+
print("Inference with:")
|
75 |
print(state['config'].to_dict())
|
76 |
print(" ")
|
77 |
|
78 |
# Update loading_space to start inference on first file
|
79 |
return {
|
80 |
inference_handler: gr.update(value = str(np.random.rand()), visible=True),
|
81 |
+
components['cancel_btn']: gr.update(visible=True),
|
|
|
82 |
master_tabs: gr.update(selected=1)
|
83 |
}
|
84 |
|
85 |
# Called when a result zip file is uploaded for result review
|
86 |
+
def on_result_upload():
|
87 |
+
return {
|
88 |
+
master_tabs: gr.update(selected=1),
|
89 |
+
result_uploader: gr.update(value=str(np.random.rand()))
|
90 |
+
}
|
91 |
+
|
92 |
+
def on_result_upload_finish(zip_list, aris_list):
|
93 |
|
94 |
if (zip_list == None):
|
95 |
zip_list = [("static/example/example_result.zip", None)]
|
|
|
102 |
state['outputs'] = ["Annotated Video", "Manual Marking", "PDF"]
|
103 |
|
104 |
component_updates = {
|
|
|
105 |
tab_labeler: gr.update(value = len(zip_list))
|
106 |
}
|
107 |
|
|
|
228 |
return {
|
229 |
master_tabs: gr.update(selected=0),
|
230 |
inference_handler: gr.update(visible=False),
|
231 |
+
components['cancel_btn']: gr.update(visible=False)
|
|
|
232 |
}
|
233 |
|
234 |
|
|
|
270 |
annotation_info, state['frame_index'] = init_frames(annotation_dataset, result['json_result'][result_index], state['frame_index'], gp=set_progress)
|
271 |
|
272 |
# save as html element
|
273 |
+
annotation_content = "<p id='annotation_info' style='display:none'>" + json.dumps(annotation_info) + "</p>"
|
274 |
|
275 |
return {
|
276 |
annotation_editor: gr.update(),
|
277 |
+
annotation_progress: gr.update(value=annotation_content)
|
278 |
}
|
279 |
|
280 |
# If complete, start annotation editor
|
|
|
309 |
with demo:
|
310 |
with gr.Blocks() as inner_body:
|
311 |
|
312 |
+
# Title of page + style
|
313 |
gr.HTML(
|
314 |
"""
|
315 |
<h1 align="center" style="font-size:xxx-large">Caltech Fisheye</h1>
|
|
|
362 |
|
363 |
|
364 |
# Define annotation progress bar for event listeres, but unrender since it will be displayed later on
|
365 |
+
result_uploader = gr.HTML("", visible=False)
|
366 |
+
components['result_uploader'] = result_uploader
|
367 |
+
|
368 |
annotation_progress = gr.HTML("", visible=False).unrender()
|
369 |
components['annotation_progress'] = annotation_progress
|
370 |
|
|
|
372 |
vis_components = Result_Gradio(prepare_annotation, components)
|
373 |
|
374 |
# Master Tab for annotation editing
|
375 |
+
if enable_annotation_editor:
|
376 |
+
with gr.Tab("Annotation Editor", id=2):
|
377 |
+
|
378 |
+
# Draw the annotation loading bar here
|
379 |
+
annotation_progress.render()
|
380 |
+
|
381 |
+
# Add annotation editor component
|
382 |
+
annotation_editor = gr.HTML("", visible=False)
|
383 |
+
|
384 |
+
# Event listener for opening annotation
|
385 |
+
annotation_progress.change(load_annotation, annotation_progress, [annotation_editor, annotation_progress], _js="""
|
386 |
+
() => {
|
387 |
+
info_string = document.getElementById("annotation_info").innerHTML;
|
388 |
+
info = JSON.parse(info_string);
|
389 |
+
console.log(info)
|
390 |
+
if (info.length == 0) {
|
391 |
+
window.annotation_info = [];
|
392 |
+
return false;
|
393 |
+
}
|
394 |
+
window.annotation_info = window.annotation_info.concat(info)
|
395 |
+
console.log(window.annotation_info)
|
396 |
+
return true;
|
397 |
+
}
|
398 |
+
""")
|
399 |
+
|
400 |
+
# Event listener for running javascript defined in 'annotation_editor.js'
|
401 |
+
# show_annotation
|
402 |
+
with open('gradio_scripts/annotation_editor.js', 'r') as f:
|
403 |
+
annotation_editor.change(lambda x: gr.update(), None, annotation_editor, _js=f.read())
|
404 |
|
405 |
# Disclaimer at the bottom of page
|
406 |
gr.HTML(
|
|
|
419 |
tab_labeler = components['tab_labeler']
|
420 |
|
421 |
|
422 |
+
inference_comps = [inference_handler, master_tabs, components['cancel_btn']]
|
423 |
|
424 |
# When a file is uploaded to the input, tell the inference_handler to start inference
|
425 |
input.upload(on_aris_input, [input] + components['hyperparams'], inference_comps)
|
|
|
432 |
result_handler.change(on_result_ready, None, vis_components + [inference_handler])
|
433 |
|
434 |
# Cancel and skip buttons
|
435 |
+
components['cancel_btn'].click(cancel_inference, None, inference_comps, cancels=[inference_event])
|
|
|
436 |
|
437 |
# Button to load a previous result and view visualization
|
438 |
+
components['open_result_btn'].click(on_result_upload, None, [result_uploader, master_tabs])
|
439 |
+
components['result_uploader'].change(
|
440 |
+
on_result_upload_finish,
|
441 |
[components['result_input'], components['result_aris_input']],
|
442 |
+
vis_components + [tab_labeler]
|
443 |
)
|
444 |
|
445 |
demo.queue().launch()
|
gradio_scripts/pdf_handler.py
CHANGED
@@ -42,7 +42,7 @@ def make_pdf(i, state, result, table_headers):
|
|
42 |
draw_combined_fish_graphs(pdf, json_result)
|
43 |
|
44 |
for i, fish in enumerate(json_result['fish']):
|
45 |
-
|
46 |
|
47 |
# We can also set the file's metadata via the PdfPages object:
|
48 |
d = pdf.infodict()
|
@@ -166,6 +166,7 @@ def calculate_fish_paths(result, dataset, id):
|
|
166 |
fish = result['metadata']['FISH'][id]
|
167 |
start_frame = fish['START_FRAME']
|
168 |
end_frame = fish['END_FRAME']
|
|
|
169 |
|
170 |
# Extract base frame (first frame for that fish)
|
171 |
w, h = 1, 2
|
@@ -175,13 +176,15 @@ def calculate_fish_paths(result, dataset, id):
|
|
175 |
images = dataset.didson.load_frames(start_frame=start_frame, end_frame=start_frame+1)
|
176 |
img = images[0]
|
177 |
|
|
|
|
|
178 |
frame_height = 2
|
179 |
scale_factor = frame_height / h
|
180 |
h = frame_height
|
181 |
w = int(scale_factor*w)
|
182 |
|
183 |
fish['base_frame'] = img
|
184 |
-
fish['scaled_frame_size'] = (
|
185 |
|
186 |
|
187 |
# Find frames for this fish
|
@@ -214,7 +217,7 @@ def calculate_fish_paths(result, dataset, id):
|
|
214 |
last_y = Y[-1]
|
215 |
dx = result['image_meter_width']*(last_x - x)/(missed+1)
|
216 |
dy = result['image_meter_height']*(last_y - y)/(missed+1)
|
217 |
-
v = math.sqrt(dx*dx + dy*dy)
|
218 |
|
219 |
# Interpolate over missing frames
|
220 |
if missed > 0:
|
@@ -243,30 +246,72 @@ def calculate_fish_paths(result, dataset, id):
|
|
243 |
|
244 |
|
245 |
def draw_combined_fish_graphs(pdf, result):
|
|
|
246 |
vel = []
|
247 |
log_vel = []
|
|
|
248 |
for fish in result['metadata']['FISH']:
|
249 |
-
|
250 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
|
252 |
-
fig, axs = plt.subplots(2, 2, sharey=True, figsize=STANDARD_FIG_SIZE)
|
253 |
axs[0,0].hist(log_vel, bins=20)
|
254 |
axs[0,0].set_title('Fish Log-Velocities between frames')
|
255 |
-
axs[0,0].set_xlabel("Log-Velocity (log(m/
|
|
|
256 |
axs[0,1].hist(vel, bins=20)
|
257 |
axs[0,1].set_title('Fish Velocities between frames')
|
258 |
-
axs[0,1].set_xlabel("Velocity (m/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
|
260 |
pdf.savefig(fig)
|
261 |
plt.close(fig)
|
262 |
|
263 |
|
264 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
265 |
|
266 |
fish = result['metadata']['FISH'][id]
|
267 |
start_frame = fish['START_FRAME']
|
268 |
end_frame = fish['END_FRAME']
|
269 |
|
|
|
|
|
270 |
fig, ax = plt.subplots(figsize=STANDARD_FIG_SIZE)
|
271 |
plt.axis('off')
|
272 |
|
@@ -277,7 +322,7 @@ def generate_fish_tracks(pdf, result, id):
|
|
277 |
plt.imshow(img, extent=(0, h, 0, w), cmap=plt.colormaps['Greys'])
|
278 |
|
279 |
# Title
|
280 |
-
plt.text(h/2,
|
281 |
|
282 |
X = fish['path']['X']
|
283 |
Y = fish['path']['Y']
|
@@ -302,9 +347,6 @@ def generate_fish_tracks(pdf, result, id):
|
|
302 |
colors.append(col)
|
303 |
ax.plot([h*(1-Y[i-1]), h*(1-Y[i])], [w*(1-X[i-1]), w*(1-X[i])], color=col, linewidth=1)
|
304 |
|
305 |
-
print(len(X))
|
306 |
-
print(len(Y))
|
307 |
-
print(len(colors))
|
308 |
for i in range(1, len(X)):
|
309 |
ax.plot(h*(1-Y[i]), w*(1-X[i]), color=colors[i], marker='o', markersize=3)
|
310 |
|
@@ -312,4 +354,64 @@ def generate_fish_tracks(pdf, result, id):
|
|
312 |
plt.ylim([0, w])
|
313 |
plt.xlim([0, h])
|
314 |
pdf.savefig(fig)
|
315 |
-
plt.close(fig)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
draw_combined_fish_graphs(pdf, json_result)
|
43 |
|
44 |
for i, fish in enumerate(json_result['fish']):
|
45 |
+
draw_fish_tracks(pdf, json_result, dataset, i)
|
46 |
|
47 |
# We can also set the file's metadata via the PdfPages object:
|
48 |
d = pdf.infodict()
|
|
|
166 |
fish = result['metadata']['FISH'][id]
|
167 |
start_frame = fish['START_FRAME']
|
168 |
end_frame = fish['END_FRAME']
|
169 |
+
fps = result['metadata']['FRAME_RATE']
|
170 |
|
171 |
# Extract base frame (first frame for that fish)
|
172 |
w, h = 1, 2
|
|
|
176 |
images = dataset.didson.load_frames(start_frame=start_frame, end_frame=start_frame+1)
|
177 |
img = images[0]
|
178 |
|
179 |
+
w, h = img.shape
|
180 |
+
|
181 |
frame_height = 2
|
182 |
scale_factor = frame_height / h
|
183 |
h = frame_height
|
184 |
w = int(scale_factor*w)
|
185 |
|
186 |
fish['base_frame'] = img
|
187 |
+
fish['scaled_frame_size'] = (h, w)
|
188 |
|
189 |
|
190 |
# Find frames for this fish
|
|
|
217 |
last_y = Y[-1]
|
218 |
dx = result['image_meter_width']*(last_x - x)/(missed+1)
|
219 |
dy = result['image_meter_height']*(last_y - y)/(missed+1)
|
220 |
+
v = math.sqrt(dx*dx + dy*dy) * fps
|
221 |
|
222 |
# Interpolate over missing frames
|
223 |
if missed > 0:
|
|
|
246 |
|
247 |
|
248 |
def draw_combined_fish_graphs(pdf, result):
|
249 |
+
|
250 |
vel = []
|
251 |
log_vel = []
|
252 |
+
eps = 0.00000000001
|
253 |
for fish in result['metadata']['FISH']:
|
254 |
+
for v in fish['path']['V']:
|
255 |
+
vel += [v]
|
256 |
+
if v > 0:
|
257 |
+
log_vel += [math.log(v)]
|
258 |
+
|
259 |
+
fig, axs = plt.subplots(2, 2, sharex=False, sharey=False, figsize=STANDARD_FIG_SIZE)
|
260 |
+
|
261 |
+
# Title
|
262 |
+
fig.suptitle('Fish velocities', fontsize=40, horizontalalignment='center', weight='bold')
|
263 |
|
|
|
264 |
axs[0,0].hist(log_vel, bins=20)
|
265 |
axs[0,0].set_title('Fish Log-Velocities between frames')
|
266 |
+
axs[0,0].set_xlabel("Log-Velocity (log(m/s))")
|
267 |
+
|
268 |
axs[0,1].hist(vel, bins=20)
|
269 |
axs[0,1].set_title('Fish Velocities between frames')
|
270 |
+
axs[0,1].set_xlabel("Velocity (m/s)")
|
271 |
+
|
272 |
+
for fish in result['metadata']['FISH']:
|
273 |
+
data = []
|
274 |
+
for v in fish['path']['V']:
|
275 |
+
if v > 0: data += [math.log(v)]
|
276 |
+
n, bin_c = make_hist(data)
|
277 |
+
axs[1,0].plot(bin_c, n)
|
278 |
+
axs[1,0].set_title('Fish Log-Velocities between frames (per fish)')
|
279 |
+
axs[1,0].set_xlabel("Log-Velocity (log(m/s))")
|
280 |
+
|
281 |
+
for fish in result['metadata']['FISH']:
|
282 |
+
data = fish['path']['V']
|
283 |
+
n, bin_c = make_hist(data)
|
284 |
+
axs[1,1].plot(bin_c, n)
|
285 |
+
axs[1,1].set_title('Fish Velocities between frames (per fish)')
|
286 |
+
axs[1,1].set_xlabel("Velocity (m/s)")
|
287 |
|
288 |
pdf.savefig(fig)
|
289 |
plt.close(fig)
|
290 |
|
291 |
|
292 |
+
def make_hist(data):
|
293 |
+
'''histogram and return vectors for plotting'''
|
294 |
+
|
295 |
+
# figure out the bins
|
296 |
+
min_bin = np.min(data)
|
297 |
+
max_bin = np.max(data)
|
298 |
+
PTS_PER_BIN = 6 #np.sqrt(len(data)) #300
|
299 |
+
bin_sz = (max_bin-min_bin)/(len(data)/PTS_PER_BIN)
|
300 |
+
bins = np.arange(min_bin-bin_sz,max_bin+2*bin_sz,bin_sz)
|
301 |
+
bin_centers = (bins[0:-1]+bins[1:])/2 # bin centers
|
302 |
+
|
303 |
+
# compute the histogram
|
304 |
+
n,b = np.histogram(data,bins=bins,density=False)
|
305 |
+
return n,bin_centers
|
306 |
+
|
307 |
+
def draw_fish_tracks(pdf, result, dataset, id):
|
308 |
|
309 |
fish = result['metadata']['FISH'][id]
|
310 |
start_frame = fish['START_FRAME']
|
311 |
end_frame = fish['END_FRAME']
|
312 |
|
313 |
+
print(fish)
|
314 |
+
|
315 |
fig, ax = plt.subplots(figsize=STANDARD_FIG_SIZE)
|
316 |
plt.axis('off')
|
317 |
|
|
|
322 |
plt.imshow(img, extent=(0, h, 0, w), cmap=plt.colormaps['Greys'])
|
323 |
|
324 |
# Title
|
325 |
+
plt.text(h/2,2,f'Fish {id+1} (frames {start_frame}-{end_frame})',fontsize=40, color="black", horizontalalignment='center', zorder=5)
|
326 |
|
327 |
X = fish['path']['X']
|
328 |
Y = fish['path']['Y']
|
|
|
347 |
colors.append(col)
|
348 |
ax.plot([h*(1-Y[i-1]), h*(1-Y[i])], [w*(1-X[i-1]), w*(1-X[i])], color=col, linewidth=1)
|
349 |
|
|
|
|
|
|
|
350 |
for i in range(1, len(X)):
|
351 |
ax.plot(h*(1-Y[i]), w*(1-X[i]), color=colors[i], marker='o', markersize=3)
|
352 |
|
|
|
354 |
plt.ylim([0, w])
|
355 |
plt.xlim([0, h])
|
356 |
pdf.savefig(fig)
|
357 |
+
plt.close(fig)
|
358 |
+
|
359 |
+
|
360 |
+
|
361 |
+
|
362 |
+
|
363 |
+
|
364 |
+
|
365 |
+
if (dataset is not None):
|
366 |
+
indices = [start_frame, int(2/3*start_frame + end_frame/3), int(1/3*start_frame + 2/3*end_frame), end_frame]
|
367 |
+
fig, axs = plt.subplots(2, len(indices), sharex=False, sharey=False, figsize=STANDARD_FIG_SIZE)
|
368 |
+
|
369 |
+
print("id", id)
|
370 |
+
print('indices', indices)
|
371 |
+
for i, frame_index in enumerate(indices):
|
372 |
+
img = dataset.didson.load_frames(start_frame=frame_index, end_frame=frame_index+1)[0]
|
373 |
+
box = None
|
374 |
+
for fi in range(frame_index, min(frame_index+10, len(result['frames']))):
|
375 |
+
for ann in result['frames'][fi]['fish']:
|
376 |
+
if ann['fish_id'] == id+1:
|
377 |
+
box = ann['bbox']
|
378 |
+
frame_index = fi
|
379 |
+
break
|
380 |
+
|
381 |
+
batch_i = math.floor(frame_index/32)
|
382 |
+
fi = frame_index - batch_i*32
|
383 |
+
batch = dataset[batch_i]
|
384 |
+
(rgb_img, _, shapes) = batch[fi]
|
385 |
+
rgb_img = rgb_img.permute(1, 2, 0)
|
386 |
+
print(type(batch))
|
387 |
+
print(type(rgb_img))
|
388 |
+
print(rgb_img.shape)
|
389 |
+
|
390 |
+
print("box", i, box)
|
391 |
+
if box is not None:
|
392 |
+
h, w = img.shape
|
393 |
+
print(w, h)
|
394 |
+
x1, x2, y1, y2 = int(box[0]*w), int(box[2]*w), int(box[1]*h), int(box[3]*h)
|
395 |
+
cx, cy = int((x2 + x1)/2), int((y2 + y1)/2)
|
396 |
+
s = min(int(max(x2 - x1, y2 - y1)*5/2), cx, cy, w-cx, h-cy)
|
397 |
+
print(x1, x2, y1, y2)
|
398 |
+
print(cx, cy, s)
|
399 |
+
cropped_img = img[cy-s:cy+s, cx-s:cx+s]
|
400 |
+
axs[0, i].imshow(cropped_img, extent=(cx-s, cx+s, cy-s, cy+s), cmap=plt.colormaps['Greys_r'])
|
401 |
+
axs[0, i].plot([x1, x1, x2, x2, x1], [y1, y2, y2, y1, y1], color="red")
|
402 |
+
axs[0, i].set_title('Frame ' + str(frame_index))
|
403 |
+
|
404 |
+
h, w, _ = rgb_img.shape
|
405 |
+
print(w, h)
|
406 |
+
x1, x2, y1, y2 = int(box[0]*w), int(box[2]*w), int(box[1]*h), int(box[3]*h)
|
407 |
+
cx, cy = int((x2 + x1)/2), int((y2 + y1)/2)
|
408 |
+
s = min(int(max(x2 - x1, y2 - y1)*5/2), cx, cy, w-cx, h-cy)
|
409 |
+
print(x1, x2, y1, y2)
|
410 |
+
print(cx, cy, s)
|
411 |
+
cropped_img = rgb_img[cy-s:cy+s, cx-s:cx+s, :]
|
412 |
+
axs[1, i].imshow(cropped_img, extent=(cx-s, cx+s, cy-s, cy+s), cmap=plt.colormaps['Greys_r'])
|
413 |
+
axs[1, i].plot([x1, x1, x2, x2, x1], [y1, y2, y2, y1, y1], color="red")
|
414 |
+
axs[1, i].set_title('Frame ' + str(frame_index))
|
415 |
+
|
416 |
+
pdf.savefig(fig)
|
417 |
+
plt.close(fig)
|
gradio_scripts/result_ui.py
CHANGED
@@ -41,8 +41,10 @@ def update_result(i, state, result, inference_handler):
|
|
41 |
|
42 |
annotation_avaliable = not (result["aris_input"][i] == None)
|
43 |
|
44 |
-
if '
|
|
|
45 |
make_pdf(state['index']-1, state, result, table_headers)
|
|
|
46 |
|
47 |
# Check if files exist
|
48 |
video_path = result["path_video"][i]
|
@@ -78,9 +80,7 @@ def Result_Gradio(prepare_annotation, components):
|
|
78 |
components['tab_labeler'] = gr.Text(value="", visible=False, elem_id="tab_labeler")
|
79 |
components['tab_labeler'].change(lambda x: x, None, None, _js=js_update_tab_labels)
|
80 |
|
81 |
-
|
82 |
-
components['cancelBtn'] = gr.Button("Cancel Inference", visible=False)
|
83 |
-
components['skipBtn'] = gr.Button("Skip this file", visible=False)
|
84 |
|
85 |
# List of all UI components that will recieve outputs from the result_handler
|
86 |
visual_components = []
|
|
|
41 |
|
42 |
annotation_avaliable = not (result["aris_input"][i] == None)
|
43 |
|
44 |
+
if 'PDF' in state['outputs']:
|
45 |
+
print("making pdf")
|
46 |
make_pdf(state['index']-1, state, result, table_headers)
|
47 |
+
print("done pdf")
|
48 |
|
49 |
# Check if files exist
|
50 |
video_path = result["path_video"][i]
|
|
|
80 |
components['tab_labeler'] = gr.Text(value="", visible=False, elem_id="tab_labeler")
|
81 |
components['tab_labeler'].change(lambda x: x, None, None, _js=js_update_tab_labels)
|
82 |
|
83 |
+
components['cancel_btn'] = gr.Button("Cancel Inference", visible=False)
|
|
|
|
|
84 |
|
85 |
# List of all UI components that will recieve outputs from the result_handler
|
86 |
visual_components = []
|
gradio_scripts/upload_ui.py
CHANGED
@@ -19,43 +19,43 @@ def Upload_Gradio(gradio_components):
|
|
19 |
gr.HTML("<p align='center' style='font-size: large;font-style: italic;'>Submit an .aris file to analyze result.</p>")
|
20 |
|
21 |
default_settings = InferenceConfig()
|
22 |
-
|
23 |
with gr.Accordion("Advanced Settings", open=False):
|
24 |
default_model = default_settings.find_model(models)
|
25 |
-
|
26 |
|
27 |
gr.Markdown("Detection Parameters")
|
28 |
with gr.Row():
|
29 |
-
|
30 |
-
|
31 |
|
32 |
gr.Markdown("Tracking Parameters")
|
33 |
with gr.Row():
|
34 |
-
|
35 |
-
|
36 |
|
37 |
default_tracker = TrackerType.toString(default_settings.associative_tracker)
|
38 |
tracker = gr.Dropdown(["None", "Confidence Boost", "ByteTrack"], value=default_tracker, label="Associative Tracking")
|
39 |
-
|
40 |
with gr.Row(visible=default_tracker=="Confidence Boost") as track_row:
|
41 |
-
|
42 |
-
|
43 |
tracker.change(lambda x: gr.update(visible=(x=="Confidence Boost")), tracker, track_row)
|
44 |
with gr.Row(visible=default_tracker=="ByteTrack") as track_row:
|
45 |
-
|
46 |
-
|
47 |
tracker.change(lambda x: gr.update(visible=(x=="ByteTrack")), tracker, track_row)
|
48 |
|
49 |
gr.Markdown("Other")
|
50 |
with gr.Row():
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
|
55 |
-
gradio_components['hyperparams'] =
|
56 |
|
57 |
with gr.Row():
|
58 |
-
|
59 |
|
60 |
#Input field for aris submission
|
61 |
gradio_components['input'] = File(file_types=[".aris", ".ddf"], type="binary", label="ARIS Input", file_count="multiple")
|
@@ -74,4 +74,4 @@ def Upload_Gradio(gradio_components):
|
|
74 |
gradio_components['result_aris_input'] = File(file_types=[".aris", ".ddf"], type="binary", label="Upload aris file (optional)", file_count="multiple")
|
75 |
|
76 |
# Button for initializing review
|
77 |
-
gradio_components['
|
|
|
19 |
gr.HTML("<p align='center' style='font-size: large;font-style: italic;'>Submit an .aris file to analyze result.</p>")
|
20 |
|
21 |
default_settings = InferenceConfig()
|
22 |
+
hyperparams = []
|
23 |
with gr.Accordion("Advanced Settings", open=False):
|
24 |
default_model = default_settings.find_model(models)
|
25 |
+
hyperparams.append(gr.Dropdown(label="Model", value=default_model, choices=list(models.keys())))
|
26 |
|
27 |
gr.Markdown("Detection Parameters")
|
28 |
with gr.Row():
|
29 |
+
hyperparams.append(gr.Slider(0, 1, value=default_settings.conf_thresh, label="Confidence Threshold", info="Confidence cutoff for detection boxes"))
|
30 |
+
hyperparams.append(gr.Slider(0, 1, value=default_settings.nms_iou, label="NMS IoU", info="IoU threshold for non-max suppression"))
|
31 |
|
32 |
gr.Markdown("Tracking Parameters")
|
33 |
with gr.Row():
|
34 |
+
hyperparams.append(gr.Slider(0, 100, value=default_settings.min_hits, label="Min Hits", info="Minimum number of frames a fish has to appear in to count"))
|
35 |
+
hyperparams.append(gr.Slider(0, 100, value=default_settings.max_age, label="Max Age", info="Max age of occlusion before track is split"))
|
36 |
|
37 |
default_tracker = TrackerType.toString(default_settings.associative_tracker)
|
38 |
tracker = gr.Dropdown(["None", "Confidence Boost", "ByteTrack"], value=default_tracker, label="Associative Tracking")
|
39 |
+
hyperparams.append(tracker)
|
40 |
with gr.Row(visible=default_tracker=="Confidence Boost") as track_row:
|
41 |
+
hyperparams.append(gr.Slider(0, 5, value=default_settings.boost_power, label="Boost Power", info=""))
|
42 |
+
hyperparams.append(gr.Slider(0, 1, value=default_settings.boost_decay, label="Boost Decay", info=""))
|
43 |
tracker.change(lambda x: gr.update(visible=(x=="Confidence Boost")), tracker, track_row)
|
44 |
with gr.Row(visible=default_tracker=="ByteTrack") as track_row:
|
45 |
+
hyperparams.append(gr.Slider(0, 1, value=default_settings.byte_low_conf, label="Low Conf Threshold", info=""))
|
46 |
+
hyperparams.append(gr.Slider(0, 1, value=default_settings.byte_high_conf, label="High Conf Threshold", info=""))
|
47 |
tracker.change(lambda x: gr.update(visible=(x=="ByteTrack")), tracker, track_row)
|
48 |
|
49 |
gr.Markdown("Other")
|
50 |
with gr.Row():
|
51 |
+
hyperparams.append(gr.Slider(0, 3, value=default_settings.min_length, label="Min Length", info="Minimum length of fish (meters) in order for it to count"))
|
52 |
+
hyperparams.append(gr.Slider(0, 3, value=default_settings.max_length, label="Max Length", info="Maximum length of fish (meters) in order for it to count"))
|
53 |
+
hyperparams.append(gr.Slider(0, 10, value=default_settings.min_travel, label="Min Travel", info="Minimum travel distance of track (meters) in order for it to count"))
|
54 |
|
55 |
+
gradio_components['hyperparams'] = hyperparams
|
56 |
|
57 |
with gr.Row():
|
58 |
+
hyperparams.append(gr.CheckboxGroup(["Annotated Video", "Manual Marking", "PDF"], label="Output formats", interactive=True, value=["Annotated Video", "Manual Marking"]))
|
59 |
|
60 |
#Input field for aris submission
|
61 |
gradio_components['input'] = File(file_types=[".aris", ".ddf"], type="binary", label="ARIS Input", file_count="multiple")
|
|
|
74 |
gradio_components['result_aris_input'] = File(file_types=[".aris", ".ddf"], type="binary", label="Upload aris file (optional)", file_count="multiple")
|
75 |
|
76 |
# Button for initializing review
|
77 |
+
gradio_components['open_result_btn'] = gr.Button("View Result")
|
inference.py
CHANGED
@@ -19,7 +19,7 @@ import torchvision
|
|
19 |
|
20 |
from InferenceConfig import InferenceConfig, TrackerType
|
21 |
from lib.fish_eye.tracker import Tracker
|
22 |
-
from lib.fish_eye.
|
23 |
|
24 |
|
25 |
### Configuration options
|
@@ -458,7 +458,11 @@ def non_max_suppression(
|
|
458 |
# width filter
|
459 |
pix2width = image_meter_width/image_pixel_width
|
460 |
width = prediction[..., 2]*pix2width
|
461 |
-
|
|
|
|
|
|
|
|
|
462 |
|
463 |
|
464 |
# Settings
|
|
|
19 |
|
20 |
from InferenceConfig import InferenceConfig, TrackerType
|
21 |
from lib.fish_eye.tracker import Tracker
|
22 |
+
from lib.fish_eye.bytetrack import Associate
|
23 |
|
24 |
|
25 |
### Configuration options
|
|
|
458 |
# width filter
|
459 |
pix2width = image_meter_width/image_pixel_width
|
460 |
width = prediction[..., 2]*pix2width
|
461 |
+
if max_length > 0:
|
462 |
+
wc = width < max_length
|
463 |
+
else:
|
464 |
+
# If max_length is 0, ignore
|
465 |
+
wc = width > max_length
|
466 |
|
467 |
|
468 |
# Settings
|
lib/fish_eye/{associative.py β bytetrack.py}
RENAMED
File without changes
|
lib/fish_eye/tracker.py
CHANGED
@@ -6,7 +6,7 @@ import numpy as np
|
|
6 |
|
7 |
from fish_length import Fish_Length
|
8 |
from lib.fish_eye.sort import Sort
|
9 |
-
from lib.fish_eye.
|
10 |
import lib
|
11 |
|
12 |
class Tracker:
|
@@ -36,7 +36,7 @@ class Tracker:
|
|
36 |
if (score < min_score):
|
37 |
min_score = score
|
38 |
conf = det[4]
|
39 |
-
elif type(self.algorithm) == lib.fish_eye.
|
40 |
for det in dets[0]:
|
41 |
score = sum(abs(det[0:4] - track[0:4]))
|
42 |
if (score < min_score):
|
|
|
6 |
|
7 |
from fish_length import Fish_Length
|
8 |
from lib.fish_eye.sort import Sort
|
9 |
+
from lib.fish_eye.bytetrack import Associate
|
10 |
import lib
|
11 |
|
12 |
class Tracker:
|
|
|
36 |
if (score < min_score):
|
37 |
min_score = score
|
38 |
conf = det[4]
|
39 |
+
elif type(self.algorithm) == lib.fish_eye.bytetrack.Associate:
|
40 |
for det in dets[0]:
|
41 |
score = sum(abs(det[0:4] - track[0:4]))
|
42 |
if (score < min_score):
|
multipage_pdf.pdf
CHANGED
Binary files a/multipage_pdf.pdf and b/multipage_pdf.pdf differ
|
|