oskarastrom's picture
Update pdf_handler.py
738002f
raw
history blame
10.4 kB
import datetime
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
from matplotlib import collections as mc
import matplotlib.pyplot as plt
import math
from aris import BEAM_WIDTH_DIR
import cv2
from dataloader import create_dataloader_aris
STANDARD_FIG_SIZE = (16, 9)
OUT_PDF_FILE_NAME = 'multipage_pdf.pdf'
def make_pdf(i, state, result, table_headers):
fish_info = result["fish_info"][i]
fish_table = result["fish_table"][i]
json_result = result['json_result'][i]
metadata = json_result['metadata']
aris_input = result["aris_input"][i]
with PdfPages(OUT_PDF_FILE_NAME) as pdf:
plt.rcParams['text.usetex'] = False
generate_title_page(pdf, metadata, state)
generate_global_result(pdf, fish_info)
generate_fish_list(pdf, table_headers, fish_table)
dataset = None
if (aris_input is not None):
dataloader, dataset = create_dataloader_aris(aris_input, BEAM_WIDTH_DIR, None)
for i, fish in enumerate(json_result['fish']):
calculate_fish_paths(json_result, dataset, i)
draw_combined_fish_graphs(pdf, json_result)
for i, fish in enumerate(json_result['fish']):
generate_fish_tracks(pdf, json_result, i)
# We can also set the file's metadata via the PdfPages object:
d = pdf.infodict()
d['Title'] = 'Multipage PDF Example'
d['Author'] = 'Oskar Åström'
d['Subject'] = 'How to create a multipage pdf file and set its metadata'
d['Keywords'] = ''
d['CreationDate'] = datetime.datetime.today()
d['ModDate'] = datetime.datetime.today()
def generate_title_page(pdf, metadata, state):
# set up figure that will be used to display the opening banner
fig = plt.figure(figsize=STANDARD_FIG_SIZE)
plt.axis('off')
title_font_size = 40
minor_font_size = 20
# stuff to be printed out on the first page of the report
plt.text(0.5,-0.5,f'{metadata["FILE_NAME"].split("/")[-1]}',fontsize=title_font_size, horizontalalignment='center')
plt.text(0,1,f'Duration: {metadata["TOTAL_TIME"]}',fontsize=minor_font_size)
plt.text(0,1.5,f'Frames: {metadata["TOTAL_FRAMES"]}',fontsize=minor_font_size)
plt.text(0,2,f'Frame Rate: {metadata["FRAME_RATE"]}',fontsize=minor_font_size)
plt.text(0.5,1,f'Time of filming: {metadata["DATE"]} ({metadata["START"]} - {metadata["END"]})',fontsize=minor_font_size)
plt.text(0.5,1.5,f'Web app version: {state["version"]}',fontsize=minor_font_size)
plt.text(1.1,4.5,f'PDF generated on {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}',fontsize=minor_font_size, horizontalalignment='right')
plt.ylim([-1, 4])
plt.xlim([0, 1])
plt.gca().invert_yaxis()
pdf.savefig(fig)
plt.close(fig)
def generate_global_result(pdf, fish_info):
# set up figure that will be used to display the opening banner
fig = plt.figure(figsize=STANDARD_FIG_SIZE)
plt.axis('off')
# stuff to be printed out on the first page of the report
minor_font_size = 18
headers = ["Result", "Camera Info", "Hyperparameters"]
info_col_1 = []
info_col_2 = []
info_col = info_col_1
row_state = -1
for row in fish_info:
if row_state >= 0:
info_col.append([row[0].replace("**","").replace("_", " ").lower(), row[1], 'normal'])
if (row[0] == "****"):
row_state += 1
if row_state == 2: info_col = info_col_2
info_col.append([headers[row_state], "", 'bold'])
for row_i, row in enumerate(info_col_1):
h = -1 + 5*row_i/len(info_col_1)
plt.text(0, h, row[0], fontsize=minor_font_size, weight=row[2])
plt.text(0.25, h, row[1], fontsize=minor_font_size, weight=row[2])
for row_i, row in enumerate(info_col_2):
h = -1 + 5*row_i/len(info_col_2)
plt.text(0.5, h, row[0], fontsize=minor_font_size, weight=row[2])
plt.text(0.75, h, row[1], fontsize=minor_font_size, weight=row[2])
plt.ylim([-1, 4])
plt.xlim([0, 1])
plt.gca().invert_yaxis()
pdf.savefig(fig)
plt.close(fig)
def generate_fish_list(pdf, table_headers, fish_table):
# set up figure that will be used to display the opening banner
fig = plt.figure(figsize=STANDARD_FIG_SIZE)
plt.axis('off')
# stuff to be printed out on the first page of the report
title_font_size = 40
header_font_size = 12
body_font_size = 20
# Title
plt.text(0.5,-1.3,f'{"Identified Fish"}',fontsize=title_font_size, horizontalalignment='center', weight='bold')
# Identified fish
row_h = 0.25
col_start = 0
row_l = 1
dropout_i = None
for col_i, col in enumerate(table_headers):
x = col_start + row_l*(col_i+0.5)/len(table_headers)
if col == "TOTAL": col = "ID"
if col == "DETECTION_DROPOUT":
col = "frame drop rate"
dropout_i = col_i
col = col.lower().replace("_", " ")
plt.text(x, -1, col, fontsize=header_font_size, horizontalalignment='center', weight="bold")
plt.plot([col_start*2, -col_start*2 + row_l], [-1 + 0.05, -1 + 0.05], color='black')
for row_i, row in enumerate(fish_table):
y = -1 + (row_i+1)*row_h
plt.plot([col_start*2, -col_start*2 + row_l], [y+0.05, y+0.05], color='black')
for col_i, col in enumerate(row):
x = col_start + row_l*(col_i+0.5)/len(row)
if (col_i == dropout_i and type(col) is not str):
col = str(int(col*100)) + "%"
elif type(col) == float:
col = "{:.4f}".format(col)
plt.text(x, y, col, fontsize=body_font_size, horizontalalignment='center')
plt.ylim([-1, 4])
plt.xlim([0, 1])
plt.gca().invert_yaxis()
pdf.savefig(fig)
plt.close(fig)
def calculate_fish_paths(result, dataset, id):
fish = result['metadata']['FISH'][id]
start_frame = fish['START_FRAME']
end_frame = fish['END_FRAME']
# Extract base frame (first frame for that fish)
w, h = 1, 2
img = None
if (dataset is not None):
images = dataset.didson.load_frames(start_frame=start_frame, end_frame=start_frame+1)
img = images[0]
frame_height = 2
scale_factor = frame_height / h
h = frame_height
w = int(scale_factor*w)
fish['base_frame'] = img
fish['scaled_frame_size'] = (w, h)
# Find frames for this fish
bboxes = []
for frame in result['frames'][start_frame:end_frame+1]:
bbox = None
for ann in frame['fish']:
if ann['fish_id'] == id+1:
bbox = ann
bboxes.append(bbox)
# Calculate tracks through frames
missed = 0
X = []
Y = []
V = []
certainty = []
for bbox in bboxes:
if bbox is not None:
# Find fish centers
x = (bbox['bbox'][0] + bbox['bbox'][2])/2
y = (bbox['bbox'][1] + bbox['bbox'][3])/2
# Calculate velocity
v = None
if len(X) > 0:
last_x = X[-1]
last_y = Y[-1]
dx = result['image_meter_width']*(last_x - x)/(missed+1)
dy = result['image_meter_height']*(last_y - y)/(missed+1)
v = math.sqrt(dx*dx + dy*dy)
# Interpolate over missing frames
if missed > 0:
for i in range(missed):
p = (i+1)/(missed+1)
X.append(last_x*(1-p) + p*x)
Y.append(last_y*(1-p) + p*y)
V.append(v)
certainty.append(False)
# Append new track frame
X.append(x)
Y.append(y)
if v is not None: V.append(v)
certainty.append(True)
missed = 0
else:
missed += 1
fish['path'] = {
'X': X,
'Y': Y,
'certainty': certainty,
'V': V
}
def draw_combined_fish_graphs(pdf, result):
vel = []
log_vel = []
for fish in result['metadata']['FISH']:
vel += fish['path']['V']
log_vel += [math.log(v) for v in fish['path']['V']]
fig, axs = plt.subplots(2, 2, sharey=True, figsize=STANDARD_FIG_SIZE)
axs[0,0].hist(log_vel, bins=20)
axs[0,0].set_title('Fish Log-Velocities between frames')
axs[0,0].set_xlabel("Log-Velocity (log(m/frame))")
axs[0,1].hist(vel, bins=20)
axs[0,1].set_title('Fish Velocities between frames')
axs[0,1].set_xlabel("Velocity (m/frame)")
pdf.savefig(fig)
plt.close(fig)
def generate_fish_tracks(pdf, result, id):
fish = result['metadata']['FISH'][id]
start_frame = fish['START_FRAME']
end_frame = fish['END_FRAME']
fig, ax = plt.subplots(figsize=STANDARD_FIG_SIZE)
plt.axis('off')
w, h = fish['scaled_frame_size']
if (fish['base_frame'] is not None):
img = fish['base_frame']
img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
plt.imshow(img, extent=(0, h, 0, w), cmap=plt.colormaps['Greys'])
# Title
plt.text(h/2,1.1,f'Fish {id+1} (frames {start_frame}-{end_frame})',fontsize=40, color="red", horizontalalignment='center', zorder=5)
X = fish['path']['X']
Y = fish['path']['Y']
certainty = fish['path']['certainty']
plt.text(h*(1-Y[0]), w*(1-X[0]), "Start", fontsize=15, weight="bold")
plt.text(h*(1-Y[-1]), w*(1-X[-1]), "End", fontsize=15, weight="bold")
colors = [""]
for i in range(1, len(X)):
certain = certainty[i]
fully_certain = certain
half_certain = certain
if i > 0:
fully_certain &= certainty[i-1]
half_certain |= certainty[i-1]
#color = 'yellow' if certain else 'orangered'
#plt.plot(h*(1-y), w*(1-x), marker='o', markersize=3, color=color, zorder=3)
col = 'yellow' if fully_certain else ('darkorange' if half_certain else 'orangered')
colors.append(col)
ax.plot([h*(1-Y[i-1]), h*(1-Y[i])], [w*(1-X[i-1]), w*(1-X[i])], color=col, linewidth=1)
print(len(X))
print(len(Y))
print(len(colors))
for i in range(1, len(X)):
ax.plot(h*(1-Y[i]), w*(1-X[i]), color=colors[i], marker='o', markersize=3)
plt.ylim([0, w])
plt.xlim([0, h])
pdf.savefig(fig)
plt.close(fig)