diff --git a/video_pos.py b/video_pos.py
new file mode 100644
index 0000000000000000000000000000000000000000..9569366eba41356cf6160384e78215416d3f6776
--- /dev/null
+++ b/video_pos.py
@@ -0,0 +1,205 @@
+import argparse
+import numpy as np
+import matplotlib.pyplot as plt
+from matplotlib.colors import rgb_to_hsv, hsv_to_rgb
+import imageio as io
+import os
+import sys
+from matplotlib.widgets import Button, Slider
+from matplotlib.backend_bases import MouseButton
+import pandas as pd
+
+
+def wb(channel, perc = 0.05):
+    mi, ma = (np.percentile(channel, perc, axis=(0,1)), np.percentile(channel,100.0-perc, axis=(0,1)))
+    channel = np.uint8(np.clip((channel-mi)*255.0/(ma-mi+1e-18), 0, 255))
+    return channel
+
+
+def wb2(channel, per=0.05):
+    hsv = rgb_to_hsv(channel/255)
+    grey = (channel/255).sum(-1)
+    mi, ma = (np.percentile(grey, per), np.percentile(grey, 100-per))
+    if mi > 0.01:
+        hue = (hsv[grey <= mi][..., 0].mean() + hsv[grey >= ma][..., 0].mean())/2
+    else:
+        hue = hsv[grey >= ma][..., 0].mean()
+    hsv[..., 0] += 0.5 - hue
+    hsv[..., 0] %= 1
+    return hsv_to_rgb(hsv)
+
+
+class Callback(object):
+    def __init__(self, inp):
+        self.reader = io.get_reader(inp, format='ffmpeg')
+        self._len = self.reader.count_frames()
+        self.fig = plt.figure(inp, figsize=[16, 9], constrained_layout=True)
+        gs = self.fig.add_gridspec(2, 1, height_ratios=[9, 1])
+        controls = gs[1].subgridspec(2, 5, height_ratios=[1, 3])
+        self.screen = self.fig.add_subplot(gs[0])
+        self.screen.set(xticks=[], yticks=[])
+        self.idx = 0
+        self.img = self.screen.imshow(self.reader.get_data(self.idx))
+        self.bar = Slider(self.fig.add_subplot(controls[0, :], zorder=10),
+                          'frame #', 0, self._len, valinit=0, valstep=1, valfmt='%5d ')
+        self.bar.valtext.set_family('monospace')
+        self.bar.on_changed(self.new_frame)
+        self.resize_b = Button(self.fig.add_subplot(controls[1, 0], zorder=10), 'Resize plot')
+        self.resize_b.on_clicked(self.resize)
+        self.normal_b = Button(self.fig.add_subplot(controls[1, 1], zorder=10), 'Auto\nwhite balance')
+        self.normal_b.on_clicked(self.normalize)
+
+        for v in "fullscreen,home,back,forward,pan,zoom,save,quit,grid,yscale,xscale,all_axes".split(','):
+            plt.rcParams[f'keymap.{v}'] = []
+        self.cid = self.fig.canvas.mpl_connect('key_press_event', self.key_pressed)
+
+        self.cid2 = self.fig.canvas.mpl_connect('button_press_event', self.mouse_press)
+        self.cid3 = self.fig.canvas.mpl_connect('button_release_event', self.mouse_release)
+        self.mouse_pos = np.zeros((2,2)) #left/right click, x/y
+        self.sperm_pos = np.zeros((2,2,2)) #sperm whale, start/stop, x/y
+        self.pos_select = [0, 0]
+        self.screen.set_xlim(self.screen.get_xlim())
+        self.screen.set_ylim(self.screen.get_ylim())
+        self.line1, self.line2 = self.screen.plot([[-100, -100], [-150, -150]], [[0, 0], [0, 0]], c='r', marker='x')
+
+        text_ax = self.fig.add_subplot(controls[1, -2:])
+        self.text = text_ax.text(0.5, 0.5, 'Sperm whale 1 : (     ,      ) - (     ,      )   ratio       -      \n'
+                                           'Sperm whale 2 : (     ,      ) - (     ,      )   angle       °      ',
+                            horizontalalignment='center',
+                            verticalalignment='center', transform=text_ax.transAxes, family='monospace')
+        text_ax.axis('off')
+
+        self.closed = False
+
+        plt.draw()
+        plt.pause(0.2)
+        self.fig.set_constrained_layout(False)
+
+    def new_frame(self, val):
+        self.idx = int(val)
+        self.img.set_data(self.reader.get_data(self.idx))
+        self.line1.set_data([-100, -150], [0,  0])
+        self.line2.set_data([-100, -150], [0,  0])
+        self.sperm_pos[:] = 0
+        self.text.set_text('Sperm whale 1 : (     ,      ) - (     ,      )   ratio       -      \n'
+                           'Sperm whale 2 : (     ,      ) - (     ,      )   angle       °      ')
+        plt.draw()
+
+    def resize(self, event):
+        self.fig.set_constrained_layout(True)
+        plt.draw()
+        plt.pause(0.2)
+        self.fig.set_constrained_layout(False)
+
+    def normalize(self, event):
+        self.img.set_data(wb(wb2(self.reader.get_data(self.idx))))
+        plt.draw()
+
+    def key_pressed(self, event):
+        key = event.key
+        move = 0
+        if key == 'j' or key == 'left':
+            move = -1
+        elif key == 'k' or key == 'right':
+            move = 1
+        elif key == 'up':
+            move = -5
+        elif key == 'pageup':
+            move = -10
+        elif key == 'down':
+            move = 5
+        elif key == 'pagedown':
+            move = 10
+        elif key == 'r':
+            self.resize(None)
+        elif key == 'n':
+            self.normalize(None)
+        if move:
+            self.bar.set_val(min(max(0, self.idx + move), self._len - 1))
+
+    def mouse_press(self, event):
+        if event.inaxes != self.screen or self.fig.canvas.manager.toolbar.mode:
+            return None
+        if event.button == MouseButton.LEFT:
+            self.mouse_pos[0] = event.xdata, event.ydata
+        elif event.button == MouseButton.RIGHT:
+            self.mouse_pos[1] = event.xdata, event.ydata
+
+    def mouse_release(self, event):
+        if event.inaxes != self.screen or self.fig.canvas.manager.toolbar.mode:
+            return None
+        if event.button == MouseButton.LEFT:
+            if np.sqrt(np.square(self.mouse_pos[0] - np.array([event.xdata, event.ydata])).sum(-1)) < 10:
+                self.sperm_pos[0, self.pos_select[0]] = event.xdata, event.ydata
+                self.pos_select[0] ^= 1
+            else:
+                self.sperm_pos[0, 0] = self.mouse_pos[0]
+                self.sperm_pos[0, 1] = event.xdata, event.ydata
+                self.pos_select[0] = 0
+            self.line1.set_data(self.sperm_pos[0].T)
+
+        elif event.button == MouseButton.RIGHT:
+            if np.sqrt(np.square(self.mouse_pos[1] - np.array([event.xdata, event.ydata])).sum(-1)) < 10:
+                self.sperm_pos[1, self.pos_select[1]] = event.xdata, event.ydata
+                self.pos_select[1] ^= 1
+            else:
+                self.sperm_pos[1, 0] = self.mouse_pos[1]
+                self.sperm_pos[1, 1] = event.xdata, event.ydata
+                self.pos_select[1] = 0
+            self.line2.set_data(self.sperm_pos[1].T)
+        vec1 = self.sperm_pos[0, 1] - self.sperm_pos[0, 0]
+        vec2 = self.sperm_pos[1, 1] - self.sperm_pos[1, 0]
+        len1 = np.sqrt(np.square(vec1).sum())
+        len2 = np.sqrt(np.square(vec2).sum())
+        if len2:
+            self.text.set_text(f'Sperm whale 1 : ({self.sperm_pos[0,0,0]:5.0f}, {self.sperm_pos[0,0,1]:5.0f}) '
+                               f'- ({self.sperm_pos[0,1,0]:5.0f}, {self.sperm_pos[0,1,1]:5.0f})'
+                               f'   ratio {len1/len2:5.2f} - {len2/len1:5.2f}\n'
+                               f'Sperm whale 2 : ({self.sperm_pos[1,0,0]:5.0f}, {self.sperm_pos[1,0,1]:5.0f}) '
+                               f'- ({self.sperm_pos[1,1,0]:5.0f}, {self.sperm_pos[1,1,1]:5.0f})'
+                               f'   angle {np.arccos(np.abs(np.dot(vec1,vec2))/(len1*len2))*180/np.pi:5.2f} °      ')
+        else:
+            self.text.set_text(f'Sperm whale 1 : ({self.sperm_pos[0,0,0]:5.0f}, {self.sperm_pos[0,0,1]:5.0f}) '
+                               f'- ({self.sperm_pos[0,1,0]:5.0f}, {self.sperm_pos[0,1,1]:5.0f})   ratio       -      \n'
+                               f'Sperm whale 2 : (     ,      ) - (     ,      )   angle       °      ')
+        plt.draw()
+
+    def close(self):
+        self.reader.close()
+        del self.resize_b
+        self.closed = True
+
+    def __del__(self):
+        if not self.closed:
+            self.close()
+
+
+def main(args):
+    if args.out == '':
+        outpath = args.input.rsplit('.', 1)[0] + '.pred.h5'
+    else:
+        outpath = args.out
+    if os.path.isfile(outpath):
+        if not (args.erase or args.resume):
+            print(f'Out file {outpath} already exist and erase or resume option isn\'t set.')
+            return 1
+    elif args.resume:
+        print(f'Out file {outpath} does not already exist and resume option is set.')
+        return 1
+    callback = Callback(args.input)
+    plt.show()
+    callback.close()
+    return 0
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    parser.add_argument("input", type=str, help="Input file")
+    parser.add_argument("--out", type=str, default='', help="Output file. Default to the input_path'.pred.h5'")
+    group = parser.add_mutually_exclusive_group()
+    group.add_argument("--erase", action='store_true', help="If out file exist and this option is not given,"
+                                                            " the computation will be halted")
+    group.add_argument("--resume", action='store_true', help="If out file exist and this option is given,"
+                                                             " the previous annotation file will be loaded")
+    args = parser.parse_args()
+    sys.exit(main(args))
\ No newline at end of file