oskarastrom commited on
Commit
d9c7dce
β€’
1 Parent(s): 53af29c
.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 = 1.5 # 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
 
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(file_list, model_id, conf_thresh, iou_thresh, min_hits, max_age, associative_tracker, boost_power, boost_decay, byte_low_conf, byte_high_conf, min_length, max_length, min_travel, output_formats):
 
 
 
 
 
 
 
 
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("Running with:")
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['cancelBtn']: gr.update(visible=True),
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(zip_list, aris_list):
 
 
 
 
 
 
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['cancelBtn']: gr.update(visible=False),
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
- annotation_storage = "<p id='annotation_info' style='display:none'>" + json.dumps(annotation_info) + "</p>"
261
 
262
  return {
263
  annotation_editor: gr.update(),
264
- annotation_progress: gr.update(value=annotation_storage)
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
- with gr.Tab("Annotation Editor", id=2):
360
-
361
- # Draw the annotation loading bar here
362
- annotation_progress.render()
363
-
364
- # Add annotation editor component
365
- annotation_editor = gr.HTML("", visible=False)
366
-
367
- annotation_storage = gr.HTML("", visible=False)
368
-
369
- # Event listener for opening annotation
370
- annotation_progress.change(load_annotation, annotation_progress, [annotation_editor, annotation_progress], _js="""
371
- () => {
372
- info_string = document.getElementById("annotation_info").innerHTML;
373
- info = JSON.parse(info_string);
374
- console.log(info)
375
- if (info.length == 0) {
376
- window.annotation_info = [];
377
- return false;
378
- }
379
- window.annotation_info = window.annotation_info.concat(info)
380
- console.log(window.annotation_info)
381
- return true;
382
- }
383
- """)
384
-
385
- # Event listener for running javascript defined in 'annotation_editor.js'
386
- with open('gradio_scripts/annotation_editor.js', 'r') as f:
387
- annotation_editor.change(lambda x: gr.update(), None, annotation_editor, _js=f.read())
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['cancelBtn'], components['skipBtn']]
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['cancelBtn'].click(cancel_inference, None, inference_comps, cancels=[inference_event])
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['preview_result_btn'].click(
424
- on_result_upload,
 
425
  [components['result_input'], components['result_aris_input']],
426
- vis_components + [master_tabs, tab_labeler]
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
- generate_fish_tracks(pdf, json_result, i)
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'] = (w, h)
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
- vel += fish['path']['V']
250
- log_vel += [math.log(v) for v in fish['path']['V']]
 
 
 
 
 
 
 
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/frame))")
 
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/frame)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
 
260
  pdf.savefig(fig)
261
  plt.close(fig)
262
 
263
 
264
- def generate_fish_tracks(pdf, result, id):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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,1.1,f'Fish {id+1} (frames {start_frame}-{end_frame})',fontsize=40, color="red", horizontalalignment='center', zorder=5)
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 'pdf' in state['outputs']:
 
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
- with gr.Row():
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
- settings = []
23
  with gr.Accordion("Advanced Settings", open=False):
24
  default_model = default_settings.find_model(models)
25
- settings.append(gr.Dropdown(label="Model", value=default_model, choices=list(models.keys())))
26
 
27
  gr.Markdown("Detection Parameters")
28
  with gr.Row():
29
- settings.append(gr.Slider(0, 1, value=default_settings.conf_thresh, label="Confidence Threshold", info="Confidence cutoff for detection boxes"))
30
- settings.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
- settings.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
- settings.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
- settings.append(tracker)
40
  with gr.Row(visible=default_tracker=="Confidence Boost") as track_row:
41
- settings.append(gr.Slider(0, 5, value=default_settings.boost_power, label="Boost Power", info=""))
42
- settings.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
- settings.append(gr.Slider(0, 1, value=default_settings.byte_low_conf, label="Low Conf Threshold", info=""))
46
- settings.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
- settings.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
- settings.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
- settings.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'] = settings
56
 
57
  with gr.Row():
58
- settings.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,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['preview_result_btn'] = gr.Button("View Result")
 
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.associative import Associate
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
- wc = width < max_length
 
 
 
 
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.associative import Associate
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.associative.Associate:
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