From b60779f970554e23a970e7efe293b968141c94b9 Mon Sep 17 00:00:00 2001 From: Thibault Tabarin Date: Tue, 28 Jun 2022 16:57:58 -0400 Subject: [PATCH] first commit --- Scripts/Dockerfile | 59 +++ Scripts/Morphology_dev.ipynb | 405 +++++++++++++++ Scripts/Morphology_main.py | 75 +++ Scripts/Traits_class.py | 470 ++++++++++++++++++ Scripts/Usage.txt | 10 + .../__pycache__/Traits_class.cpython-37.pyc | Bin 0 -> 12214 bytes .../__pycache__/Traits_class.cpython-38.pyc | Bin 0 -> 13135 bytes Scripts/morphology.py | 256 ++++++++++ Scripts/morphology_env.yml | 111 +++++ Scripts/test_images/INHS_FISH_000742.json | 1 + .../INHS_FISH_000742_segmented.png | Bin 0 -> 4981 bytes 11 files changed, 1387 insertions(+) create mode 100644 Scripts/Dockerfile create mode 100644 Scripts/Morphology_dev.ipynb create mode 100755 Scripts/Morphology_main.py create mode 100644 Scripts/Traits_class.py create mode 100644 Scripts/Usage.txt create mode 100644 Scripts/__pycache__/Traits_class.cpython-37.pyc create mode 100644 Scripts/__pycache__/Traits_class.cpython-38.pyc create mode 100644 Scripts/morphology.py create mode 100644 Scripts/morphology_env.yml create mode 100755 Scripts/test_images/INHS_FISH_000742.json create mode 100755 Scripts/test_images/INHS_FISH_000742_segmented.png diff --git a/Scripts/Dockerfile b/Scripts/Dockerfile new file mode 100644 index 0000000..6c7dc71 --- /dev/null +++ b/Scripts/Dockerfile @@ -0,0 +1,59 @@ +FROM ubuntu:20.04 + +# Label +LABEL org.opencontainers.image.title="fish cropping and trait morphology" +LABEL org.opencontainers.image.authors=" T. Tabarin" +LABEL org.opencontainers.image.source="https://github.com/hdr-bgnn/BGNN_Snakemake" + +# Install some basic utilities +RUN apt-get update && apt-get install -y \ + curl \ + ca-certificates \ + sudo \ + git \ + bzip2 \ + libx11-6 \ + wget \ + && rm -rf /var/lib/apt/lists/* + +# Create a working directory +RUN mkdir /app +WORKDIR /app + +# Create a non-root user and switch to it +RUN adduser --disabled-password --gecos '' --shell /bin/bash user \ + && chown -R user:user /app +RUN echo "user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/90-user +USER user + +# All users can use /home/user as their home directory +ENV HOME=/home/user +RUN chmod 777 /home/user + +# Set up the Conda environment +ENV CONDA_AUTO_UPDATE_CONDA=false \ + PATH=/home/user/miniconda/bin:$PATH +COPY morphology_env.yml /app/environment.yml +RUN curl -sLo ~/miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-py38_4.9.2-Linux-x86_64.sh \ + && chmod +x ~/miniconda.sh \ + && ~/miniconda.sh -b -p ~/miniconda \ + && rm ~/miniconda.sh \ + && conda env update -n base -f /app/environment.yml \ + && rm /app/environment.yml \ + && conda clean -ya + +WORKDIR /pipeline + +# Setup pipeline specific scripts +ENV PATH="/pipeline/Morphology:${PATH}" +ENV PATH="/pipeline/Crop:${PATH}" +ENV PATH="/pipeline/Merge_files:${PATH}" +ADD Crop_image/Crop_image_main.py /pipeline/Crop/Crop_image_main.py +ADD Morphology/Traits_class.py /pipeline/Morphology/Traits_class.py +ADD Morphology/Morphology_main.py /pipeline/Morphology/Morphology_main.py +ADD Merge_files/Merge_files_main.py /pipeline/Merge_files/Merge_files_main.py + +# Set the default command to a usage statement +CMD echo "Usage crop: Crop_image_main.py \n"\ +"Usage Morphology: Morphology_main.py \n"\ +"Usage Merge_file: Merge_files_main.py " diff --git a/Scripts/Morphology_dev.ipynb b/Scripts/Morphology_dev.ipynb new file mode 100644 index 0000000..bf342e3 --- /dev/null +++ b/Scripts/Morphology_dev.ipynb @@ -0,0 +1,405 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "98a152cd", + "metadata": {}, + "source": [ + "# Development for morphology trait extraction\n", + "\n", + "This notebook gives example and a platform to develop and visualize extraction on morphological traits\n", + "The function framework is based on a class \"Traits_class\" define in the same folder.\n", + "if you modify the \"Traits_class\" reload the module by running the first cell to see the modification appear in the notebook.\n", + "\n", + "**Study case:**\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "602dc370", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# load what you need\n", + "import Traits_class as tc\n", + "import json, sys\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from PIL import Image, ImageDraw, ImageFont\n", + "import importlib\n", + "importlib.reload(tc)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "e620246b", + "metadata": {}, + "outputs": [], + "source": [ + "# load the test image, you can add more test image if you have bug related to specific images.\n", + "segmented_file = 'test_images/INHS_FISH_000742_segmented.png'\n", + "metadata_file = 'test_images/INHS_FISH_000742.json'" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "2289de98", + "metadata": {}, + "outputs": [], + "source": [ + "# Create the object segmented image create by the class during initialisation\n", + "img_seg = tc.segmented_image(segmented_file)\n", + "\n", + "# variable create at initialization time\n", + "measurement = img_seg.measurement\n", + "landmark = img_seg.landmark\n", + "presence_matrix = img_seg.presence_matrix\n", + "img_landmark = img_seg.visualize_landmark()" + ] + }, + { + "cell_type": "markdown", + "id": "070251e3", + "metadata": {}, + "source": [ + "## 2 - Explore the output\n", + "\n", + " 1- Presence Matrix\n", + " 2- Landmark\n", + " 3- Visualize landmark\n", + " 4- measurement" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "ae9eb407", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'dorsal_fin': {'number': 1, 'percentage': 1.0},\n", + " 'adipos_fin': {'number': 0, 'percentage': 0},\n", + " 'caudal_fin': {'number': 1, 'percentage': 1.0},\n", + " 'anal_fin': {'number': 1, 'percentage': 1.0},\n", + " 'pelvic_fin': {'number': 1, 'percentage': 1.0},\n", + " 'pectoral_fin': {'number': 1, 'percentage': 1.0},\n", + " 'head': {'number': 1, 'percentage': 1.0},\n", + " 'eye': {'number': 1, 'percentage': 1.0},\n", + " 'caudal_fin_ray': {'number': 0, 'percentage': 0},\n", + " 'alt_fin_ray': {'number': 0, 'percentage': 0},\n", + " 'trunk': {'number': 2, 'percentage': 0.992120507069956}}" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# presence dictionnary\n", + "presence_matrix" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "ffda5440", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'1': (148, 36),\n", + " '2': (66, 148),\n", + " '3': (21, 301),\n", + " '4': (106, 566),\n", + " '5': (112, 606),\n", + " '6': (150, 622),\n", + " '7': (203, 592),\n", + " '8': (200, 562),\n", + " '9': (242, 478),\n", + " '10': (279, 305),\n", + " '11': (217, 169),\n", + " '12': (162, 187),\n", + " '13': (224, 138),\n", + " '14': (136, 66),\n", + " '15': (134, 96),\n", + " '16': (115, 81),\n", + " '17': (153, 81),\n", + " '18': (135, 81)}" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# landmark dictionnary\n", + "landmark" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "60024ce2", + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (1558273965.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Input \u001b[0;32mIn [29]\u001b[0;36m\u001b[0m\n\u001b[0;31m list_order = [1:19]\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "list_order = [1:19]" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "8b7d1b1a", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Visualize landmarks \n", + "img_landmark" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5eea310", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "6ee0446b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "caudal_fin = img_seg.mask['caudal_fin']\n", + "\n", + "plt.imshow(caudal_fin)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "cf78ee7e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.imshow(img_seg.mask['caudal_fin'])" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "cb94b95f", + "metadata": {}, + "outputs": [], + "source": [ + "_,_,_,_,center_caudal,new_mask_caudal= img_seg.landmark_generic('caudal_fin')\n", + "\n", + "row_caudal = round(center_caudal[0])\n", + "head_horil_line = new_mask_caudal[row_caudal, :]\n", + "#head_length = np.count_nonzero( cleaned_mask[:,col_eye]== 1)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "ed0dc8c6", + "metadata": {}, + "outputs": [], + "source": [ + "def landmark_5_7(img_seg):\n", + " '''\n", + " locate the landmark 5 and 7 of the caudal fin. \n", + " We split the caudal fin upper and lower part (horizontal line through the middle).\n", + " Then, in each case get the mot left point in the half of the caudal fin\n", + " '''\n", + " _,_,_,_,center_caudal,new_mask_caudal= img_seg.landmark_generic('caudal_fin')\n", + " mask_caudal_5 = new_mask_caudal.copy()\n", + " mask_caudal_7 = new_mask_caudal.copy()\n", + " row_caudal = round(center_caudal[0])\n", + "\n", + " mask_caudal_5[row_caudal:,:] = 0\n", + " mask_caudal_7[:row_caudal,:] = 0\n", + " \n", + " lm_5_7=[]\n", + " for temp_mask in [mask_caudal_5,mask_caudal_7]: \n", + " x,y = np.where(temp_mask)\n", + " y_front = y.min()\n", + " x_front = round(np.mean(np.where(temp_mask[:, y_front,])))\n", + " lm_5_7.append((int(x_front),int(y_front)))\n", + " return lm_5_7[0], lm_5_7[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "04909223", + "metadata": {}, + "outputs": [], + "source": [ + "lm_5, lm_7 = landmark_5_7(img_seg)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "f519df18", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "img_arr = img_seg.img_arr\n", + "def visualize_landmark(img_arr,coord):\n", + " text = '5' \n", + " \n", + " img = Image.fromarray(img_arr)\n", + " img1 = ImageDraw.Draw(img)\n", + " \n", + " #\n", + " #fnt = ImageFont.truetype(\"Pillow/Tests/fonts/FreeMono.ttf\", 15)\n", + " fnt = ImageFont.load_default()\n", + "\n", + " x,y = coord\n", + " xy = [(y-9,x-9),(y+9,x+9)]\n", + " img1.ellipse(xy, fill='gray', outline=None, width=1)\n", + " \n", + " img1.text((y-6, x-6), text, font=fnt, fill='black')\n", + " # Display the image created\n", + " \n", + " return img\n", + " \n", + "visualize_landmark(img_arr,lm_7)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fadc18fa", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (Morphology_env)", + "language": "python", + "name": "snakemake" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Scripts/Morphology_main.py b/Scripts/Morphology_main.py new file mode 100755 index 0000000..5bd9f1b --- /dev/null +++ b/Scripts/Morphology_main.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue May 24 09:21:33 2022 + +@author: thibault +""" +import Traits_class as tc +import json, sys + +def get_scale(metadata_file): + + ''' + extract the scale value from metadata file + ''' + + f = open(metadata_file) + data = json.load(f) + metadata_dict = list(data.values())[0] + + if 'scale' in metadata_dict : + + scale = round(metadata_dict['scale'],3) + unit = metadata_dict['unit'] + else: + scale =[None] + unit =[None] + return scale , unit + + +def main(input_file, metadata_file, output_measure, output_landmark, output_presence, + output_lm_image=None): + + img_seg = tc.segmented_image(input_file) + measurement = img_seg.measurement + landmark = img_seg.landmark + presence_matrix = img_seg.presence_matrix + + # Extract the scale from metadata file + # and add it to measurement dict + scale , unit = get_scale(metadata_file) + measurement['scale'] = scale + measurement['unit'] = unit + + # Save the dictionnaries in json file + with open(output_measure, 'w') as f: + json.dump(measurement, f) + + with open(output_landmark, 'w') as f: + json.dump(landmark, f) + + with open(output_presence, 'w') as f: + json.dump(presence_matrix, f) + + if output_lm_image: + + img_landmark = img_seg.visualize_landmark() + img_landmark.save(output_lm_image) + + +if __name__ == '__main__': + + input_file = sys.argv[1] + metadata_file = sys.argv[2] + output_measure = sys.argv[3] + output_landmark = sys.argv[4] + output_presence = sys.argv[5] + output_lm_image = None + + + if len(sys.argv)==7: + output_lm_image = sys.argv[6] + + main(input_file, metadata_file, output_measure, output_landmark, output_presence, + output_lm_image=output_lm_image) diff --git a/Scripts/Traits_class.py b/Scripts/Traits_class.py new file mode 100644 index 0000000..d5814b5 --- /dev/null +++ b/Scripts/Traits_class.py @@ -0,0 +1,470 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Wed May 18 16:02:54 2022 + +@author: thibault +Class definition for morpholopgy analysis +""" +import os, sys, math, json +import numpy as np +from PIL import Image, ImageDraw, ImageFont +from skimage.measure import label, regionprops +from skimage.morphology import reconstruction + +class segmented_image: + + def __init__(self, file_name): + self.file = file_name + self.image_name = os.path.split(file_name)[1] # creates a new empty list for each dog + self.trait_color_dict={'background': [0, 0, 0],'dorsal_fin': [254, 0, 0],'adipos_fin': [0, 254, 0], + 'caudal_fin': [0, 0, 254],'anal_fin': [254, 254, 0],'pelvic_fin': [0, 254, 254], + 'pectoral_fin': [254, 0, 254],'head': [254, 254, 254],'eye': [0, 254, 102], + 'caudal_fin_ray': [254, 102, 102],'alt_fin_ray': [254, 102, 204], + 'trunk': [0, 124, 124]} + self.img_arr = self.import_image(file_name) + self.get_channels_mask() + self.presence_matrix = self.get_presence_matrix() + self.landmark = self.all_landmark() + self.measurement = self.all_measure() + + def import_image(self,file_name): + ''' + import the image from "image_path" and convert to np.array astype uint8 (0-255) + ''' + img = Image.open(file_name) + img_arr = np.array(img, dtype=np.uint8) + + return img_arr + + + def get_channels_mask(self): + ''' Convert the png image (numpy.ndarray, np.uint8) (320, 800, 3) + to a mask_channel (320, 800, 12) Binary map + + input + output + img shape -> (320, 800, 3) if normal=True + else: mask shape -> (11, 320, 800) + we want to output a PIL image with rgb color value + ''' + trait_color_dict = self. trait_color_dict + img = self.img_arr + mask = {} + for i, (trait, color) in enumerate(trait_color_dict.items()): + if trait != "background": + + trait_mask = (img[:, :, 0] == color[0]) &\ + (img[:, :, 1] == color[1]) &\ + (img[:, :, 2] == color[2]) + mask[trait]=trait_mask.astype("uint8") + + self.mask = mask + + def align_fish(self): + ''' + development + To align the fish horizontally + in order to get landmark 5 and 6 + ''' + + img_arr = self.img_arr + traits_to_combine = list(self.trait_color_dict.keys())[1:] + combine_mask = self.combine_trait_mask(traits_to_combine) + region = self.clean_trait_region(combine_mask) + angle_rad = region.orientation + angle_deg = (90-angle_rad*180/math.pi) + image_align = Image.fromarray(img_arr).rotate(angle_deg) + + return image_align + + def visualize_trait(self, trait): + + mask = self.mask + trait_color_dict = self. trait_color_dict + + if trait in list(trait_color_dict.keys()): + return Image.fromarray(mask[trait]*255) + + else: + print(f'trait {trait} is not reference') + + def remove_holes(self, image): + + seed = np.copy(image) + seed[1:-1, 1:-1] = image.max() + mask = image + filled = reconstruction(seed, mask, method='erosion') + return filled + + + def clean_trait_region(self, trait_mask, percent_cut = 0.5): + ''' + Clean the mask_trait (remove holes) + Find the biggest region + return region_trait + ''' + + # remove hole/fill empty area + trait_filled = self.remove_holes(trait_mask) + + # total area of the trait + total_area = np.count_nonzero(trait_filled == 1) + trait_label = label(trait_filled) + trait_region = regionprops(trait_label) + + if total_area>0: + + # Get the biggest instance(blob) of the trait + biggest_region = sorted(trait_region, key=lambda r: r.area, reverse=True)[0] + percent = biggest_region.area/total_area + if percent >=percent_cut: + trait_region = biggest_region + else: + trait_region =[] + return trait_region + + def get_presence_matrix(self): + ''' + Create a matrix with presence, number of blob, percent of the biggest + instance for each trait + ''' + mask = self.mask + presence_matrix = {} + + for i, (trait_name, trait_mask) in enumerate(mask.items()): + + temp_dict = {} + total_area = np.count_nonzero(trait_mask == 1) + label_trait = label(trait_mask) + trait_regions = regionprops(label_trait) + + temp_dict["number"] = len(trait_regions) + + if len(trait_regions) > 0: + biggest_region = sorted(trait_regions, key=lambda r: r.area, reverse=True)[0] + temp_dict["percentage"] = biggest_region.area/total_area + else: + temp_dict["percentage"] = 0 + + presence_matrix[trait_name] = temp_dict + + return presence_matrix + + + def get_one_property_all_trait(self, property_='centroid'): + ''' + Create a dictionnary with key = trait and value the property selected by property_ + example: {'dorsal_fin': (centroid[0], centroid[1]), 'trunk':(centroid[0], centroid[1])....} + ''' + + mask = self.mask + dict_property={} + # enumerate through the dictionary of mask to collect trait_name + for i, (trait_name, trait_mask) in enumerate(mask.items()): + + trait_region = self.clean_trait_region(trait_mask) + + if trait_region: + dict_property[trait_name] = trait_region[property_] + else: + dict_property[trait_name]=None + + return dict_property + + def get_distance(self, a,b): + ''' + measure distance between two points if they are not empty + a and b : tuple (x,y) + + ''' + distance=0 + # a and b are not None calculate the distance + if a and b: + distance = ((a[0] - b[0])**2 + (a[1] - b[1])**2)**0.5 + return distance + + + def get_distance_table(self): + ''' + Create a matrix with distance between centroid of traits + ''' + centroid_dict = self.get_one_property_all_trait() + distance_matrix = {} + + for i, (trait_name, centroid) in enumerate(centroid_dict.items()): + + distance_matrix[trait_name] = {k: self.get_distance(centroid,v) + for i, (k,v) in enumerate(centroid_dict.items())} + + return distance_matrix + + def combine_trait_mask(self, list_trait=['head','trunk']): + + mask = self.mask + combo = np.zeros_like(mask,dtype="uint8") + + for trait in list_trait: + + combo = combo + mask[trait] + + #combo_cleaned = self.remove_holes(combo) + + return combo + + def get_body_len(self): + ''' + body length from snout to back to the trunk + 1- Combine head and trunk + 2- Create a clean trait region clean_trait_region + 3- Measure distance long axis, bbox + ''' + head_trunk = self.combine_trait_mask() + trait_region= self.clean_trait_region(head_trunk) + orientation = trait_region.orientation + xb0, yb0, xb1, yb1 = trait_region.bbox + len1 =(yb1-yb0)/math.sin(orientation) + bbox_len = yb1-yb0 + return len1, bbox_len + + def visualize_major_minor(self): + + trait_mask = self.combine_trait_mask() + trait_region= self.clean_trait_region(trait_mask) + x0, y0 = trait_region.centroid + orientation = trait_region.orientation + xb0, yb0, xb1, yb1 = trait_region.bbox + + # Drawing object + # Create rgb image + trait_mask_rgb = np.stack((trait_mask, trait_mask, trait_mask), axis=2) + #R = np.repeat(mask_line[:,:,np.newaxis],3, axis=2) + img = Image.fromarray(trait_mask_rgb*255) + img1 = ImageDraw.Draw(img) + + # Long axis + x2 = x0 - 0.5 * (yb1-yb0)/math.tan(orientation) + x1 = x0 + 0.5 * (yb1-yb0)/math.tan(orientation) + long_axis = [(yb0, x2), (yb1, x1)] + img1.line(long_axis, fill ="red", width = 2) + + + # Short axis + x1t = x0 + math.sin(orientation) * 0.5 * trait_region.axis_minor_length + y1t = y0 - math.cos(orientation) * 0.5 * trait_region.axis_minor_length + short_axis = [(y0, x0), (y1t, x1t)] #img1.line(shape1, fill ="red", width = 2) + img1.line(short_axis, fill ="red", width = 2) + + # Display the image created + img.show() + + + def landmark_generic(self, trait_name): + ''' + Identify landmark of a trait (trait_name) + front, back, top, bottom of the trait and center + this function works only if the fish is oriented head facing left + ''' + + mask = self.mask[trait_name] + # remove the hole and take the biggest blob + clean_mask = self.clean_trait_region(mask) + # Create new mask with clean mask, remove hole and secondary blob + # use clean_mask (region) to reconstruct a mask + if clean_mask: + bbox = clean_mask.bbox + new_mask = np.zeros_like(mask) + new_mask[bbox[0]:bbox[2],bbox[1]:bbox[3]]=clean_mask.image + + x,y = np.where(new_mask) + # top + x_top=x.min() + y_top = round(np.mean(np.where(new_mask[x_top,:]))) + top_lm = (int(x_top),int(y_top)) + + # bottom + x_bottom=x.max() + y_bottom = round(np.mean(np.where(new_mask[x_bottom,:]))) + bottom_lm = (int(x_bottom),int(y_bottom)) + + #front + y_front = y.min() + x_front = round(np.mean(np.where(new_mask[:, y_front,]))) + front_lm = (int(x_front),int(y_front)) + + #back + y_back=y.max() + x_back = round(np.mean(np.where(new_mask[:, y_back,]))) + back_lm = (int(x_back),int(y_back)) + centroid = clean_mask.centroid + else: + front_lm , back_lm, top_lm, bottom_lm, centroid, new_mask = [], [], [], [], [], [] + + return front_lm, back_lm, top_lm, bottom_lm, centroid, new_mask + + def landmark_5_7(self): + ''' + locate the landmark 5 and 7 of the caudal fin. + We split the caudal fin upper and lower part (horizontal line through the middle). + Then, in each case get the mot left point in the half of the caudal fin + ''' + _,_,_,_,center_caudal,new_mask_caudal= self.landmark_generic('caudal_fin') + mask_caudal_5 = new_mask_caudal.copy() + mask_caudal_7 = new_mask_caudal.copy() + row_caudal = round(center_caudal[0]) + + mask_caudal_5[row_caudal:,:] = 0 + mask_caudal_7[:row_caudal,:] = 0 + + lm_5_7=[] + for temp_mask in [mask_caudal_5,mask_caudal_7]: + x,y = np.where(temp_mask) + y_front = y.min() + x_front = round(np.mean(np.where(temp_mask[:, y_front,]))) + lm_5_7.append((int(x_front),int(y_front))) + return lm_5_7[0], lm_5_7[1] + + def all_landmark(self): + ''' + Calculate of the landmark + front, back, top, bottom, center, new_mask = self.landmark_generic(trait_name) + ''' + landmark={} + #eye + landmark['14'], landmark['15'], landmark['16'], landmark['17'], center_eye, _ = self.landmark_generic('eye') + landmark['18'] = (round(center_eye[0]), round(center_eye[1])) + # head + landmark['1'], landmark['12'], landmark['2'] , landmark['13'], _, new_mask_head = self.landmark_generic('head') + + #landmark #5 and 7 caudal fin + landmark['5'], landmark['7'] = self.landmark_5_7() + + # head length, vertical line of the head passing by the center of the eye + col_eye = round(center_eye[1]) + + if len(new_mask_head): + head_vert_line = new_mask_head[:,col_eye] + #head_length = np.count_nonzero( cleaned_mask[:,col_eye]== 1) + index_head_len= np.where(head_vert_line!=0)[0] + landmark['uk'] = (int(index_head_len[-1]),int(col_eye)) + + + + #trunk + _, landmark['6'],_ ,_ ,_ ,_ = self.landmark_generic('trunk') + + # Fins : ['dorsal_fin', 'anal_fin', 'pelvic_fin', 'pectoral_fin'] + landmark['3'],_ , _, landmark['4'], _, _ = self.landmark_generic('dorsal_fin') + landmark['11'],_ , _,_, _, _ = self.landmark_generic('pectoral_fin') + landmark['10'],_ , _,_, _, _ = self.landmark_generic('pelvic_fin') + landmark['9'], _, landmark['8'] , _, _, _ = self.landmark_generic('anal_fin') + + + # reorder the key + new_landmark={} + list_order = [str(i) for i in range(1,19)] + for key in list_order: + new_landmark[key] = landmark[key] + + return new_landmark + + + def measure_eye_head_ratio(self): + ''' + Create eye head area ratio + 1- Area head after cleaning and filling hole + 2- Area eye after cleaning and filing hole + 3- ratio + ''' + mask = self.mask + head_region = self.clean_trait_region(mask['head']) + eye_region = self.clean_trait_region(mask['eye']) + + eye_head_ratio = eye_region.area/head_region.area + + return eye_head_ratio + + def measure_eye_diameter(self): + ''' + Calculate eye equivalent diameter : diameter of the disk of the same area + (area/pi)^1/2 + ''' + mask = self.mask + eye_region = self.clean_trait_region(mask['eye']) + + eq_diameter = (eye_region.area/math.pi)**0.5 + + return eq_diameter + + def measure_head_length(self): + ''' + Measure vertical length of the head passing by the center of the eye + ''' + landmark = self.landmark + p_2 = landmark['2'] + p_15 = landmark['15'] + head_length = self.get_distance(p_2,p_15) + + return head_length + + def measure_head_depth(self): + ''' + Measure vertical length of the head passing by the center of the eye + ''' + #eye + _, _, _, _, center_eye, _ = self.landmark_generic('eye') + + # head + _, _, _, _, _, new_mask_head = self.landmark_generic('head') + # landmark 15 + # head length, vertical line of the head passing by the center of the eye + row_eye = round(center_eye[0]) + + head_hori_line = new_mask_head[row_eye,:] + head_depth = np.count_nonzero( head_hori_line) + + return head_depth + + + def all_measure(self): + ''' + Collect all the measurment for the fish + ''' + landmark = self.landmark + measure={} + # Standard length body length + measure['A'] = self.get_distance(landmark['1'],landmark['6']) + measure['B'] = self.measure_eye_head_ratio() + measure['C'] = self.measure_eye_diameter() + measure['D'] = self.measure_head_depth() + # Head length landmark 2 to 15 + measure['E'] = self.get_distance(landmark['2'],landmark['15']) + # + measure['F'] = self.get_distance(landmark['1'],landmark['14']) + # + measure['G'] = self.get_distance(landmark['1'],landmark['6']) + return measure + + def visualize_landmark(self): + + + landmark = self.all_landmark() + img_arr = self.img_arr + img = Image.fromarray(img_arr) + img1 = ImageDraw.Draw(img) + + # + #fnt = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 15) + fnt = ImageFont.load_default() + for i,(k,v) in enumerate(landmark.items()): + if v: + x,y = v + xy = [(y-9,x-9),(y+9,x+9)] + img1.ellipse(xy, fill='gray', outline=None, width=1) + + img1.text((y-6, x-6), k, font=fnt, fill='black') + # Display the image created + + return img + + diff --git a/Scripts/Usage.txt b/Scripts/Usage.txt new file mode 100644 index 0000000..2307534 --- /dev/null +++ b/Scripts/Usage.txt @@ -0,0 +1,10 @@ +#!/usr/bin/bash + +# Usage : python Morphology_main.py +# : segmented_ image in png : INHS_122505_segmented.png +# : ouput file name for measure {'A':x,'B':y...} +# : ouput file name for landmark dictionary {'1':[x,y],'2':[x,y]....} +# : presence dictionary {"dorsal_fin":{number:2 , percent:0.96 },'trunk':{}...} +# : image with landmark + +python Morphology_main.py INHS_122505_segmented.png measure.json landmark.json presence.json image_lm.png diff --git a/Scripts/__pycache__/Traits_class.cpython-37.pyc b/Scripts/__pycache__/Traits_class.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe0aae71fcfb6f44acca4c8ba6c31c39d4bd52a5 GIT binary patch literal 12214 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 (320, 800, 3) if normal=True + else: mask shape -> (12, 320, 800) + we want to output a PIL image with rgb color value + ''' + + mask = {} + for color, trait in enumerate(trait_color_dict): + if trait != "background": + + mask[trait] = get_one_trait_mask( + img, trait_color_dict, trait).astype("uint8") + + return mask + +def get_region_prop(mask, trait_name): + + + label_trait = label(mask[trait_name]) + regions_trait = regionprops(label_trait) + + return regions_trait + +def get_presence_matrix(mask): + ''' + Create a matrix with presence, number of blob, percent of the biggest + ''' + presence_matrix = {} + for i, (trait_name, trait_mask) in enumerate(mask.items()): + + temp_dict = {} + total_area = sum(sum(trait_mask)) + label_trait = label(trait_mask) + regions_trait = regionprops(label_trait) + + temp_dict["number"] = len(regions_trait) + + if len(regions_trait) > 0: + biggest_region = sorted(regions_trait, key=lambda r: r.area, reverse=True)[0] + temp_dict["percentage"] = biggest_region.area/total_area + else: + temp_dict["percentage"] = 0 + + presence_matrix[trait_name] = temp_dict + + return presence_matrix + +def get_one_property_all_trait(mask, property_): + + dict_property={} + for i, (trait_name, trait_mask) in enumerate(mask.items()): + + dict_property[trait_name]=None + + label_trait = label(trait_mask) + regions_trait = regionprops(label_trait) + + if regions_trait : + + biggest_region = sorted(regions_trait, key=lambda r: r.area, reverse=True)[0] + dict_property[trait_name] = biggest_region[property_] + + return dict_property + +def get_distance(a,b): + ''' + measure distance between to point + + ''' + distance=None + if a and b: + distance = ((a[0] - b[0])**2 + (a[1] - b[1])**2)**0.5 + return distance + +def get_distance_matrix(dict_centroid): + ''' + Create a matrix with distance between centroid of traits + ''' + distance_matrix = {} + dict_temp = dict_centroid.copy() + for i, trait_name in enumerate(dict_centroid): + + centroid = dict_temp.pop(trait_name) + + if centroid: + dist_temp = {k: (get_distance(centroid,v) if v!=None else None) + for i, (k,v) in enumerate(dict_temp.items())} + else: + dist_temp = None + + distance_matrix[trait_name] = dist_temp + + return distance_matrix + +def get_Ed(): + + ''' + measure equivalent eye diameter (area/pi)^1/2 + ''' + + + + +def get_scale(metadata_file): + + ''' + extract the scale value from metadata file + ''' + + f = open(metadata_file) + data = json.load(f) + first_value = list(data.values())[0] + + if first_value['ruler']==True : + + scale = round(first_value['scale'],3) + unit = first_value['unit'] + else: + scale =[None] + unit =[None] + return scale , unit + + +def get_morphology_one_trait(trait_key, mask, parameter=None): + + trait_mask = mask[trait_key] + total_area = sum(sum(trait_mask)) + label_trait = label(trait_mask) + regions_trait = regionprops(label_trait) + + result={"area":[], "percent" : [],"centroid":[], "bbox":[]} + # iterate throught the region sorted by area size + for region in sorted(regions_trait, key=lambda r: r.area, reverse=True): + + # choose what you want to see + result["area"].append(region.area) + result["percent"].append(region.area/total_area) + result["centroid"].append(region.centroid) + result["bbox"].append(region.bbox) + + return result, regions_trait + + +def compare_head_eye(result_head, head, result_eye, eye, metadata_file, name=None): + + # Checked if there is a major big blob + if result_head["percent"][0] > 0.85 and result_eye["percent"][0] > 0.85: + + head = head[0] + eye = eye[0] + ratio_eye_head = eye.area/(head.area + eye.area) + + coord_head = head.centroid + coord_eye = eye.centroid + + distance_eye_snout = abs(head.bbox[1]-eye.bbox[1]) + scale , unit = get_scale(metadata_file) + + return {name:{"eye_head_ratio" : round(ratio_eye_head,3), + "snout_eye_distance": round(distance_eye_snout,3), "scale":scale, "scale_unit":unit}} + +def main(image_path, metadata_file, output_json, name): + + + img = import_segmented_image(image_path) + + mask = get_channels_mask(img, trait_color_dict) + + # Create your own function + res_head, head = get_morphology_one_trait("head", mask, parameter=None) + res_eye, eye = get_morphology_one_trait("eye", mask, parameter=None) + + result = compare_head_eye(res_head, head, res_eye, eye, metadata_file, name) + + with open(output_json, 'w') as f: + json.dump(result, f) + +if __name__ == '__main__': + + input_file = sys.argv[1] + metadata_file = sys.argv[2] + output_json = sys.argv[3] + name = sys.argv[4] + main(input_file, metadata_file, output_json, name) diff --git a/Scripts/morphology_env.yml b/Scripts/morphology_env.yml new file mode 100644 index 0000000..5c8d213 --- /dev/null +++ b/Scripts/morphology_env.yml @@ -0,0 +1,111 @@ +name: morphology +channels: + - bioconda + - conda-forge + - defaults +dependencies: + - _libgcc_mutex=0.1=conda_forge + - _openmp_mutex=4.5=1_gnu + - aom=3.3.0=h27087fc_1 + - blosc=1.21.0=h9c3ff4c_0 + - brotli=1.0.9=h166bdaf_7 + - brotli-bin=1.0.9=h166bdaf_7 + - brunsli=0.1=h9c3ff4c_0 + - bzip2=1.0.8=h7f98852_4 + - c-ares=1.18.1=h7f98852_0 + - c-blosc2=2.0.4=h5f21a17_1 + - ca-certificates=2021.10.8=ha878542_0 + - certifi=2021.10.8=py38h578d9bd_2 + - cfitsio=4.1.0=hd9d235c_0 + - charls=2.3.4=h9c3ff4c_0 + - cloudpickle=2.0.0=pyhd8ed1ab_0 + - cycler=0.11.0=pyhd8ed1ab_0 + - cytoolz=0.11.2=py38h0a891b7_2 + - dask-core=2022.4.0=pyhd8ed1ab_0 + - fonttools=4.32.0=py38h0a891b7_0 + - freetype=2.10.4=h0708190_1 + - fsspec=2022.3.0=pyhd8ed1ab_0 + - giflib=5.2.1=h36c2ea0_2 + - imagecodecs=2022.2.22=py38hf887e2c_3 + - imageio=2.16.1=pyhcf75d05_0 + - jbig=2.1=h7f98852_2003 + - jpeg=9e=h7f98852_0 + - jxrlib=1.1=h7f98852_2 + - keyutils=1.6.1=h166bdaf_0 + - kiwisolver=1.4.2=py38h43d8883_1 + - krb5=1.19.3=h08a2579_0 + - lcms2=2.12=hddcbb42_0 + - ld_impl_linux-64=2.36.1=hea4e1c9_2 + - lerc=3.0=h9c3ff4c_0 + - libaec=1.0.6=h9c3ff4c_0 + - libavif=0.10.0=h166bdaf_1 + - libblas=3.9.0=14_linux64_openblas + - libbrotlicommon=1.0.9=h166bdaf_7 + - libbrotlidec=1.0.9=h166bdaf_7 + - libbrotlienc=1.0.9=h166bdaf_7 + - libcblas=3.9.0=14_linux64_openblas + - libcurl=7.82.0=h2283fc2_0 + - libdeflate=1.10=h7f98852_0 + - libedit=3.1.20191231=he28a2e2_2 + - libev=4.33=h516909a_1 + - libffi=3.4.2=h7f98852_5 + - libgcc-ng=11.2.0=h1d223b6_15 + - libgfortran-ng=11.2.0=h69a702a_15 + - libgfortran5=11.2.0=h5c6108e_15 + - libgomp=11.2.0=h1d223b6_15 + - liblapack=3.9.0=14_linux64_openblas + - libnghttp2=1.47.0=he49606f_0 + - libnsl=2.0.0=h7f98852_0 + - libopenblas=0.3.20=pthreads_h78a6416_0 + - libpng=1.6.37=h21135ba_2 + - libssh2=1.10.0=ha35d2d1_2 + - libstdcxx-ng=11.2.0=he4da1e4_15 + - libtiff=4.3.0=h542a066_3 + - libuuid=2.32.1=h7f98852_1000 + - libwebp=1.2.2=h3452ae3_0 + - libwebp-base=1.2.2=h7f98852_1 + - libxcb=1.13=h7f98852_1004 + - libzlib=1.2.11=h166bdaf_1014 + - libzopfli=1.0.3=h9c3ff4c_0 + - locket=0.2.0=py_2 + - lz4-c=1.9.3=h9c3ff4c_1 + - matplotlib-base=3.5.1=py38hf4fb855_0 + - munkres=1.0.7=py_1 + - ncurses=6.3=h27087fc_1 + - networkx=2.8=pyhd8ed1ab_0 + - numpy=1.22.3=py38h1d589f8_2 + - openjpeg=2.4.0=hb52868f_1 + - openssl=3.0.2=h166bdaf_1 + - packaging=21.3=pyhd8ed1ab_0 + - pandas=1.4.2=py38h47df419_1 + - partd=1.2.0=pyhd8ed1ab_0 + - pillow=9.1.0=py38h0ee0e06_0 + - pip=22.0.4=pyhd8ed1ab_0 + - pthread-stubs=0.4=h36c2ea0_1001 + - pyparsing=3.0.8=pyhd8ed1ab_0 + - python=3.8.13=ha86cf86_0_cpython + - python-dateutil=2.8.2=pyhd8ed1ab_0 + - python_abi=3.8=2_cp38 + - pytz=2022.1=pyhd8ed1ab_0 + - pywavelets=1.3.0=py38h71d37f0_1 + - pyyaml=6.0=py38h0a891b7_4 + - readline=8.1=h46c0cb4_0 + - scikit-image=0.19.2=py38h43a58ef_0 + - scipy=1.8.0=py38h56a6a73_1 + - setuptools=62.1.0=py38h578d9bd_0 + - six=1.16.0=pyh6c4a22f_0 + - snappy=1.1.8=he1b5a44_3 + - sqlite=3.37.1=h4ff8645_0 + - tifffile=2022.4.8=pyhd8ed1ab_0 + - tk=8.6.12=h27826a3_0 + - toolz=0.11.2=pyhd8ed1ab_0 + - unicodedata2=14.0.0=py38h0a891b7_1 + - wheel=0.37.1=pyhd8ed1ab_0 + - xorg-libxau=1.0.9=h7f98852_0 + - xorg-libxdmcp=1.1.3=h7f98852_0 + - xz=5.2.5=h516909a_1 + - yaml=0.2.5=h7f98852_2 + - zfp=0.5.5=h9c3ff4c_8 + - zlib=1.2.11=h166bdaf_1014 + - zstd=1.5.2=ha95c52a_0 +prefix: /home/thibault/anaconda3/envs/morphology diff --git a/Scripts/test_images/INHS_FISH_000742.json b/Scripts/test_images/INHS_FISH_000742.json new file mode 100755 index 0000000..ac3b8f4 --- /dev/null +++ b/Scripts/test_images/INHS_FISH_000742.json @@ -0,0 +1 @@ +{"INHS_FISH_000742": {"fish": [{"foreground": {"mean": 101.51651269772098, "std": 47.10516827998412}, "background": {"mean": 251.69058542827787, "std": 10.624290298301899}, "bbox": [512, 960, 3395, 2159], "pixel_analysis_failed": false, "extent": 0.6166612050146891, "eccentricity": 0.9260924090676843, "solidity": 0.8211629938593639, "skew": [0.2516110156342582, -0.06843302479073322], "kurtosis": [-0.7564431763847876, -0.7845615155024706], "std": [659.4310811152554, 249.01180564724643], "mask": {"start_coord": [1328.0, 2075.0], "encoding": "7667777677655666765655655566666666667607607775467770707676707777677777767777707677676766770757765553243433447075467671777677666677667767677757776767676766543447677777765777777675554466677777770776667676677776666767765443347777777767767070707077070770707707077070770777077070077771007654447767607600767077775533333343367767767776776754666667707070070776776777677677776776544476667077770776767767707077677767666676676667667676767676776776776767613321700776776754432336576767717560776676776777677767776777676767776666761322212101021112233110100013112217607666655446656654666556666665657666666566676676576601221221766665666766667772107771322222222233243124333222321131221102111221766666677767677665334322224334456667654667767766767667666677675007576770767507657754753466771766670077607577767776000767607617122223322432222323322210767576607767676777766555466667660754756607565776666717654772107677766766667676776075677667676677666766707666776667766655007677076676534676776676677676676776676767107677677766760777776766675471077534776676777677767765666665776771700776567777777776767776767776546666776767677776077707767770077767677760777677777767077707777777770776770777777777770767077607777707770777077677700776777766766767676777607707077770770707707707700707007007007000770070000700000000000000101011112212110000000700000700007000007000070000000000000100100101111123110101001010100101010110111111111121111121112111212112121221212212122122122122221121121111211112111211121211121111211211211212112112121121211211212121121211221211212121121212121112112122121212121212121212121212121121221112212122112221212111122212112221212121212112121211101243121211212112121211221121211212121212112121212112121212121212112212121212121212112110212212112121122121212121212112212112121211212212121211222112112221212112112122121121211121221211221121212311112111111221211212112111211211213172312121221212111121121211212121212212111212121112212211211212212121221212122122122122112112121211212122122121222212122121222212122122221221222212222122121222121212212212212212122212221221222122122212221222122221222221221222221222212212222122212212221221222212222122221222212222221222222122222122212221222221222122212222122221222122222222222221222222122222212222222122222222122212212221222222213221222222222221222222222122221222222221222212222122222212222222122222122222221222222222122222222221222222212222222122222212222212222122222212222122212212221221221222122212221222221221222122122212222122122212222123122221222122221222122222122212221222222122221222221222122222222122222222222222222212222222122212222122222212212222222222122222212222222122222222122222221222222212222212222222122222122222122222212222221222222121212222212222222322122212222222222222131222222212222222222212222223212246576532533232232232354566666656666565545445444434343223222222122222222122222221222222222223222222222222232222222222222212222222122122222322222322222222122322322222222222222222222223222222322222222222232223222222222322322223222322223222322223222322232222322322232223223223223232322223222223222232223222323232322232222322232322232433232223223222333323322222222222232222222322222222232223222323234654436676766667572222222221776766666666667655323366566666566676653332322222223440766666765666665454600765540776543460076654476076545440707675467554776555076655076655446007675476657675666666567665766665765667547665566607656565607556666656666665566766665666665434312122123222123221221043321210024322313221224434331007703222122455335467754576553432134432102231143210433110312214447553131111234322222222104321246556556665676546076544443443310722344565444543111353212317033222331222212222321133210221445446767555560776554507766566666666666656666666666666544432313122232433110722433222212231100044432221003432221231104331217707024433210104322124335322177000433431170224454311010144443466656665667656665566756654353222321231222133100332117022543124312223222221223122213311222222222222221233121322231212444665776543350767775445077554554454535311012121234323455444343222221043222122221232212323101332214554465565331023443100002432217712343322310243210003332456665666666665666566666544470766656654322223322210214335311024431211210024444321323221224465667755666667654444431224321007143343321171433222104322310232211033344676653577765555400176545533223310122211445321022123431013333222311013453212223223112102433446600754565465443310024531323122321003432102211322243246765665765457654076665566665433222224310023433102243101321023102445754322222170334312210024532223444331100770210443444432123222122223346566665476576557675536576532332210044433232102331100104434331002353222103432210332110024444325331317710243532317110443244332231222432217222431022335565666666665656657675532322232232122432343110343110007243345332566776546666655332443113332317023434456553124311024321343112321325431223100766022324433114443122322103222310332222222222232222222222232222221322223221223222222222222222232222222222222222222232223110776766766666666722222221072323333334444332222322232323266676666676666676666776666666676666676666666665667666666665666666667556600076553466676556075566547667665665434431124332122314322232223232232222223222232312232222312231232222222223222232222232222447666666766576755776576567666756666566666666665466607656654322322122322132457577654675332322332232244443311444321232223231256675667567765675532232222322232234533232223235436076567666766667666666676666766676666765332232323222323223222232223222222323221032243332322232232223232222323223232232323232322323232323323333432223222232222322223222322222232222223222222322222222223222222232222232222322222223222212232222322222212222212222122221222212222121221221221212221212212221221221221222122121222122122122221222222221221222122212121212212221222212222221212212212212122122122121221221221221212212222222122121221212212212121212212212212122212221221212212212212222212221222122122221221222112121212212122122122122122122122212212212212212212221221221222122212221221221222122222122212221221222122212212222122212222122222122122122212122221222122221221221221221222122212212212212221222212222222222222122221222212222212222122212222213122221222212222222122222222222122222222223233332212122222222222213235665666656656666546544544443323133656565656667566655666565656666675666556656665666656666575556666566555765666666656656566666565665666555332221221311113232122322221121222213223434454443666666765556656665666656565655666666656665565766665656565545432221221122121222222222222133221222122212223222222122121122222222212222135756656656656656656676575556665756565665565553322222222221222212221321222223143223134347566666676545455766766566555566666665655566676666565655656607566665654434322323217022212144665554313221221132102111031224331222131322221212212122222222222222122117666667671122122212222322222234333221210712122245445532322213665665665656665666665676566665666666566656666666665655467666756656544557757076666665434365432322121222212322222221213244543653243556666566566666656566547765666555433324432131131232213100171122322235323222212232123222222222122222222222222223446544434345466077001007675666665766566666566566666666666666566666576565766766666565665666666656566666755653323231222221212323224655343210217004332222231221224344665545345676666666656666666665554532432212122222222212222223232225545313222212123222222213221107665666666667567131221221122322222222222213465666543432323255656567666666665656666655532321246665653444465666565666767666676776217766676566544456656756665666765765466656566566567666656654532235457670754665565665432213321333243222324666665666654653332235322265753324312432222310221323336566665577656675566666666556532312222221322223210212223232322222221322223321223243665576666656532223214332346565532332232232322222232222324346666666665666655455545466666667666666756567666667666666656766766665667665331322322221322223232222222222323222222222224544407566767666666655333223213226547666675665432235656655546565666666676666666666666666666666666666666666666666666666756666766666666666665666666666666665666566665565322446653347700750765443654665766556555455677546544324322133446554432221243107007222344453223221102145433222222322232221113122233223212100212222235443232231222222222222221322222232123122221222132232232432554431223232221346666656666666566756765666776667665666001322212222211077666666676656666666566766575757540766566665667656767566654556760765656767776656675675665443446657777543253313653547665665476676533322213222232222322223122122123210122322322132212332332102365434661075756566655766543222243122312231232222322222222212332222221322322221222221232131222143114322322322321122231223212212222222212222121222222312222656665566665666666665666566667666666566576666765555432332222122223244534431332222222322222222222222222222221222231222224432566665666666666575665666666666533123245443223222313222222132231223566665667666666665666545433235666567667656766666765655555665666667566655666676766566676655465322432243244434323122322213323322223212222231232332222222232222222232213223212222223222231322123222222223222222222222222222222222222232366665666666666666675566677575667666676665675076565654433245666766621010076766666666667566666766656676666543232222223222222243212123466666665654776766665776766667676666666667667656544543323221223222232322332221213322222232223222323132223213466754776667666566676755755675607544443133221312223221322232444665677667666656777567566665667654322256565444343332313235476076544400075544676607665432323223243432322223222456667656544454322466666660767656766666607666666555432432432313221123344322232232322233223232231323222223222322323222223223266666656654444666000776666666655324332223222332232322332322322232222322232323232222232222333456566777676677667666766676766767667667667667666767666767667667667667666666666666666766766666766675654323323222322223222322322222232323223323123222222233132322323322222246666676676766667666567676607666756666666767766766666766766677656676707567667675667676766666766675434343222233222323223223322222233221432122223124332322223322102532323323323222232323322223236766666666667657667665754657710765476076675366575755322133332322222243233222232223332223232433131435431123314454446756666567666776675075475677676667666666676776667666554543232322222323222233133232132212343322232223232232232322323222222232223233223222322232232222222322222323222222332222322232222322232222217760032243532232222322223222117670222223231222222223232321232222246675667666666543322223222232222234666666666666766666567577566543345654534465766766666755546656667566671221076677656675676667666666666676667665766666766666676666776666766676766767666767676676676666766666766766767666676666667657676666676666666567676766754433332223211433533323243222211432222332322333223222656766676666676666676666766666675766667666766766766766667667666766766766766766766766767667676676766766767666767667667676766766766676676676767676676676676676676766767666776676667766676676766766766767666766676666677666767676766767667676676766767667667676766766776676676676676766767667667676766766766676677667676767667667667676766767676676676667667666766766676676676676667676667667667676676667667666766767667667666676766676676667676676676676666767666766666767666677665666676667666666666666676676666676666666667666666666666666666666666666665433322223223243334323344454534434455454443466662110077766545767756566566656656565666566656666565666656666656566656665666566665665666666665666656666666656666756566654666655660775656665560766566665432213222223212232122213222222122211222322322222321231222222212221212222222212222221222212221222221222221222221222221032531112222123122123122112222122170233323232322346554666654566666566665661765446667544666507666544467566544322222222222222266655765656666675467655666600722433100022221077765665600755444457753334566566666566666654432222221213231012443211322114432122312222222222222122222122222122221222122212222122222210761343223323232354444546565656666661766666656666666666656666665667555456666755676657566666575665656756665666666665540766566754446007656666667565766665322365667656665666534443322222222223231243331001032443122317132221143322222222222431002331122244325766567546676566666765666666666666666566666666666666566666667566666666666656666566665656556601100767766665566656765576676547766666656765576755444447701177554076565666653435346777776765535776765655656533331001323222222232344665666667676666666535432456071077565576566666666666666657655754443434666665660765407754446776560767212317001224432212222310100000754543560000076565344476701176566076544607755461765654671075575507666666657653450717575553122433455312434676544667665433322221243214312133123222222223222222223222222222232122223222222223222222222222222222222222123222122322222122222222222222222221322222222222222222222223224667666667656675666666666666666666666675667656666666666666666665666666666666666666666666766666666667666666666666667576666666666666666666756766666666665675756666666766666666666666665666666656666666222176666666666666667766655667676665766667566653232322231222224666666666666666666666656666666666676666667667666666666665666666566666666566666665666666565666656567554666556653222444455555445565546655665446566666666666666676667665656665665665656666566666566656556665766675656566565666665656665665665665656566656665665665665666656656666566566566566566566656665665666656665666566566665666666656666665666656666566656566656666666566665323132665466665531222222132222122332223665665666654322212222222222221231222134322121323122222222243343665556667546656566566766666556543222567665566656656666666566666666666566566656666656665566766566666565676666665666666566666656666656666656666656666666656666656666665666666566666665666665666566666666665675666666656666666666666656667566666666666666666666666666666666666666666666656666666666666666666567653676666666666665666666666666666666566666665666666756666766665676666567656666666666666666666566666666666666666665665666567653246566011766666656665454565666666677654566656665676666666666766666666666665666666667666666666657666566666667666666666657666666667666666666666666666576666666676656667666666666766667666666666666766666667667666666666666667575766766665322323223666766766666666666766666666767545666665444354454565566533455566666556566545"}, "cont_length": 9.609884501526398, "cont_width": 3.748910986859199, "area": 23.970412653992632, "feret_diameter_max": 10.009851923063295, "major_axis_length": 9.286044221196532, "minor_axis_length": 3.503594456459641, "convex_area": 29.190809660497088, "perimeter": 63.41433465544191, "oriented_length": 0.0347943033466916, "oriented_width": 0.013679811572203535, "centroid": [1818, 1532], "has_eye": true, "eye_center": [684, 1475], "side": "left", "clock_value": 9, "primary_axis": [-0.9998769834130162, 0.015684962253283346], "score": 0.9205734729766846}], "has_fish": true, "ruler_bbox": [735, 2510, 5218, 3387], "has_ruler": true, "scale": 284.08249855306553, "unit": "cm", "fish_count": 1, "detected_fish_count": 1}} \ No newline at end of file diff --git a/Scripts/test_images/INHS_FISH_000742_segmented.png b/Scripts/test_images/INHS_FISH_000742_segmented.png new file mode 100755 index 0000000000000000000000000000000000000000..99e2a882f0809a1e2d100796d05f716d8ec2858e GIT binary patch literal 4981 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