Commit b1793027 authored by Francisco Romero's avatar Francisco Romero

add tail and update README

parent 78ee14b7
# Fish midline extraction form idtracker.ai videos
This repository includes scripts to extract the fish midline from information
stored in the objects created by idtacker.ai after tracking a video.
stored in the data generated by the tracking software [idtracker.ai](idtracker.ai) after.
The pipeline only requires the *video_object.npy* and the *blobs_collection.npy*
from idtracker.ai (see data folder).
from [idtracker.ai](idtracker.ai) (see data folder).
The piple is as indicated in the followin image.
The pipeline is as indicated in the following image.
![Pipeline](fishmidline/scripts/pipeline.png)
For blobs that look like fish (head with lower curvarture than tail). We also have a class *FishContour* that detects the nose, head, and tail of the fish. This points can also be included in the skeleton.
For blobs that look like fish (head with lower curvarture than tail). We also have a class *FishContour* that detects the nose, head, and tail of the fish. This points can also be included in the skeleton. Adding this points makes the extraction of the midline more robust.
![Pipeline](fishmidline/scripts/pipeline_nose.png)
## Requirements
* numpy
* scipy
* skimage
* matplotlib
* tqdm
* idtracker.ai (https://gitlab.com/polavieja_lab/idtrackerai)
## TODO
......
import numpy as np
from skimage.morphology import skeletonize
from scipy import interpolate
from fishmidline.fish_contour import FishContour
......@@ -11,20 +12,23 @@ def get_binary_image(height, width, pxs):
return binary_image
def get_nose_fish(cnt):
def get_nose_head_tail_fish(cnt):
f_cnt = FishContour(cnt)
nose, _, _, _ = f_cnt.find_nose_and_orientation()
return nose
nose, tail, _, head = f_cnt.find_nose_and_orientation()
return nose, head, tail
def distance(p1, p2):
return np.sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2)
def order_midline(midline_x, midline_y, nose):
def order_midline(midline_x, midline_y, nose, head, tail):
points = list(zip(midline_x, midline_y))
midline = []
nose = tuple(nose)
tail = tuple(tail)
if tail not in points:
points.append(tail)
if nose in points:
points.remove(nose)
midline.append(nose)
......@@ -88,10 +92,12 @@ def get_midline_angles(video, blob, plot_flag=False,
midline_y, midline_x = np.where(skeleton == 1)
if use_nose:
# Order midline from nose to tail
nose = get_nose_fish(blob.contour)
midline_x, midline_y = order_midline(midline_x, midline_y, nose)
nose, head, tail = get_nose_head_tail_fish(blob.contour)
midline_x, midline_y = order_midline(midline_x, midline_y,
nose, head, tail)
else:
nose = None
tail = None
# Interpolated and compute equidistant points in the midline
midline_eq_x, midline_eq_y, midline_interp_x, midline_interp_y = \
compute_equidistant_points(midline_x, midline_y,
......@@ -102,7 +108,7 @@ def get_midline_angles(video, blob, plot_flag=False,
if not plot_flag:
return angles
else:
return binary_image, skeleton, nose, blob.contour,\
return binary_image, skeleton, nose, tail, blob.contour,\
(midline_x, midline_y), (midline_interp_x, midline_interp_y),\
(midline_eq_x, midline_eq_y),\
angles
fishmidline/scripts/pipeline.png

66.9 KB | W: | H:

fishmidline/scripts/pipeline.png

72.2 KB | W: | H:

fishmidline/scripts/pipeline.png
fishmidline/scripts/pipeline.png
fishmidline/scripts/pipeline.png
fishmidline/scripts/pipeline.png
  • 2-up
  • Swipe
  • Onion skin
fishmidline/scripts/pipeline_nose.png

77.7 KB | W: | H:

fishmidline/scripts/pipeline_nose.png

82.7 KB | W: | H:

fishmidline/scripts/pipeline_nose.png
fishmidline/scripts/pipeline_nose.png
fishmidline/scripts/pipeline_nose.png
fishmidline/scripts/pipeline_nose.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -5,7 +5,7 @@ import matplotlib.pyplot as plt
from fishmidline import get_midline_angles
def plotter(binary_image, skeleton, nose, contour,
def plotter(binary_image, skeleton, nose, tail, contour,
midline_xy, midline_interp_xy, midline_eq_xy,
use_nose=False):
if use_nose:
......@@ -34,10 +34,11 @@ def plotter(binary_image, skeleton, nose, contour,
contour = np.squeeze(np.asarray(contour))
ax_arr[0, 3].plot(contour[:, 0], contour[:, 1])
ax_arr[0, 3].plot(nose[0], nose[1], 'ro')
ax_arr[0, 3].plot(tail[0], tail[1], 'bo')
ax_arr[0, 3].set_xlim(x_lim), ax_arr[0, 3].set_ylim(y_lim)
ax_arr[0, 3].invert_yaxis()
ax_arr[0, 3].set_aspect('equal')
ax_arr[0, 3].set_title('Contour and\nfish nose')
ax_arr[0, 3].set_title('Contour and\nfish nose\nand tail')
# Plot midline points
ax_arr[1, 0].plot(midline_xy[0], midline_xy[1], '.')
ax_arr[1, 0].invert_yaxis()
......@@ -58,6 +59,7 @@ def plotter(binary_image, skeleton, nose, contour,
ax = ax_arr[1, 3] if use_nose else ax_arr[1, 2]
ax.imshow(binary_image, cmap='gray')
ax.plot(midline_eq_xy[0], midline_eq_xy[1], '-o')
ax.plot(midline_eq_xy[0][0], midline_eq_xy[1][0], 'ro')
ax.set_xlim(x_lim), ax.set_ylim(y_lim)
ax.invert_yaxis()
ax.set_title('Equispaced midline')
......@@ -74,8 +76,8 @@ if __name__ == '__main__':
parser.add_argument("-n", "--use_nose", help="whether to include the nose\
of the fish or not for the midline (only working for \
animals with fish-like shapes, e.g. two curvature points)",
type=bool,
default=False)
type=int,
default=0)
args = parser.parse_args()
session_path = args.session_path
......@@ -89,25 +91,24 @@ if __name__ == '__main__':
list_of_blobs = np.load(blobs_path, encoding='latin1').item()
FOCAL_IDENTITY = 1
for i in range(1):
# FRAME_NUMBER = np.random.randint(0, video.number_of_frames // 2)
FRAME_NUMBER = 194
blobs_in_frame = list_of_blobs.blobs_in_video[FRAME_NUMBER]
identities = [blob.identity for blob in blobs_in_frame]
print(identities)
if FOCAL_IDENTITY in identities:
blob = [blob for blob in blobs_in_frame
if blob.identity == FOCAL_IDENTITY][0]
binary_image, skeleton, nose, contour,\
midline_xy, midline_interp_xy, midline_eq_xy, _ = \
get_midline_angles(video, blob, plot_flag=True,
use_nose=use_nose)
# # Plot images
plotter(binary_image, skeleton, nose, contour,
midline_xy, midline_interp_xy, midline_eq_xy,
use_nose=use_nose)
else:
print("No identity in this frame")
# FRAME_NUMBER = np.random.randint(0, video.number_of_frames)
FRAME_NUMBER = 234
blobs_in_frame = list_of_blobs.blobs_in_video[FRAME_NUMBER]
identities = [blob.identity for blob in blobs_in_frame]
print(identities)
if FOCAL_IDENTITY in identities:
blob = [blob for blob in blobs_in_frame
if blob.identity == FOCAL_IDENTITY][0]
binary_image, skeleton, nose, tail, contour,\
midline_xy, midline_interp_xy, midline_eq_xy, _ = \
get_midline_angles(video, blob, plot_flag=True,
use_nose=use_nose)
# # Plot images
plotter(binary_image, skeleton, nose, tail, contour,
midline_xy, midline_interp_xy, midline_eq_xy,
use_nose=use_nose)
else:
print("No identity in this frame")
if use_nose:
plt.gcf().savefig('pipeline_nose.png')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment