Commit 606eaad9 authored by Nicolas Elie's avatar Nicolas Elie
Browse files

Update AnalyzeSequence.ipynb

parent c745f037
Loading
Loading
Loading
Loading
+1 −1
Changes for AnalyzeSequence.ipynb: 1 added line, 1 removed line.
Original line number Diff line number Diff line
%% Cell type:markdown id: tags:

![REDPOL_LOGO](https://git.unicaen.fr/nicolas.elie/redpol-open/-/raw/master/media/REDPOL_LOGO.jpg)
## _Script to analyze our raw image sequences were taken with a colour camera mounted on a stereomicroscope._

Anaïd Gouveneaux (1,2),
Mamoudou Sano (3),
Nicolas Elie (3),
Apolline Chabenat (1,2),
Céline Thomasse (2),
Christelle Jozet-Alves (2),
Anne-Sophie Darmaillacq (2),
Ludovic Dickel(2),
Thomas Knigge (1),
Cécile Bellanger (2),

- 1 Normandie Univ, UNILEHAVRE, UMR-I02, Environmental stress and biomonitoring of aquatic environments (SEBIO), 76600 Le Havre, France
- 2 Normandie Univ, UNICAEN, UMR 6552, Rennes 1-CNRS (EthoS) - Cephalopod cognitive neuroethology (NECC), 14000 Caen, France
- 3 Normandie Univ, UNICAEN, CMAbio3 - Centre de Microscopie Appliquée à la biologie

> The file format is VSI from Olympus

%% Cell type:markdown id: tags:

## ----------------------------------------------------------------------------------

%% Cell type:markdown id: tags:

## Import the required modules

%% Cell type:code id: tags:

``` python
import numpy as np
import os
from csbdeep.utils import normalize
from stardist.models import StarDist2D
import cv2
import javabridge
import bioformats
import pandas as pd
from shapely.geometry import Polygon
from shutil import make_archive,rmtree
from zipfile import ZipFile
axis_norm = (0,1)   # normalize channels independently
from PIL import Image
```

%% Cell type:markdown id: tags:

## Load Model

%% Cell type:code id: tags:

``` python
model = StarDist2D(None, name='stardist_multiclass', basedir='models')
```

%% Output

    Loading network weights from 'weights_best.h5'.
    Loading thresholds from 'thresholds.json'.
    Using default values: prob_thresh=0.65, nms_thresh=0.75.

    2022-11-30 09:00:09.087056: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudnn.so.8'; dlerror: libcudnn.so.8: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /media/elie/2ToenPlus/miniconda3/envs/csbdeepstardist/lib/python3.8/site-packages/cv2/../../lib64:
    2022-11-30 09:00:09.087079: W tensorflow/core/common_runtime/gpu/gpu_device.cc:1850] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform.
    Skipping registering GPU devices...
    2022-11-30 09:00:09.087358: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
    To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.

%% Cell type:markdown id: tags:

## Call java and using bioformat to read vsi files.

%% Cell type:code id: tags:

``` python
def _init_logger():
    """This is so that Javabridge doesn't spill out a lot of DEBUG messages
    during runtime.
    From CellProfiler/python-bioformats.
    """
    rootLoggerName = javabridge.get_static_field("org/slf4j/Logger",
                                         "ROOT_LOGGER_NAME",
                                         "Ljava/lang/String;")

    rootLogger = javabridge.static_call("org/slf4j/LoggerFactory",
                                "getLogger",
                                "(Ljava/lang/String;)Lorg/slf4j/Logger;",
                                rootLoggerName)

    logLevel = javabridge.get_static_field("ch/qos/logback/classic/Level",
                                   "WARN",
                                   "Lch/qos/logback/classic/Level;")

    javabridge.call(rootLogger,
            "setLevel",
            "(Lch/qos/logback/classic/Level;)V",
            logLevel)
```

%% Cell type:markdown id: tags:

## Read metadata of vsi files

%% Cell type:code id: tags:

``` python
def get_metadata(filename):
    """Read the meta data and return the metadata object.
    """
    meta = bioformats.get_omexml_metadata(filename)
    metadata = bioformats.omexml.OMEXML(meta)
    return metadata
```

%% Cell type:markdown id: tags:

## Javabridge: running and interacting with the JVM from Python

%% Cell type:code id: tags:

``` python
javabridge.start_vm(class_path=bioformats.JARS,run_headless=False)
logger = _init_logger()
```

%% Cell type:markdown id: tags:

## Main function: application of the Stardist model on each image of the vsi file, detection and classification of chromatophores, saving of results and creation of optional additional result files.

%% Cell type:code id: tags:

``` python
def AI_OnePile(number,pathFile, output_path, start=None,numberstack=None, OptionS="9",):
    """
    number: number corresponding to vsi file
    pathFile: path of vsi file
    output_path : folder to save data
    start : Index of the first image in stack
    numberstack : Index of the last image in stack

    OptionS : 9 , just file result
              0, add video file
              1, add images files : BINARY
              2, add images files : LABEL
              3, add files pickle to keep indivudial dataframe.

              Example : "0-2" --> add video file and Label images.
    """

    # Create result file
    fileResults=open(output_path + number+'_'+start+'-'+str(numberstack)+"_resultat.csv","w")
    fileResults.write("Sequence;Image area;Number of Light chromatophores;Number of Dark chromatophores;Total area of Light chromatophores;Total area of Dark chromatophores;Average size of Light chromatophores;Average size of Dark chromatophores;Median size of Light chromatophores; Median size of Dark chromatophores;Standard deviation of the size of Light chromatophores;Standard deviation of the size of Dark chromatophores\n")

    # path of image
    fileEXT=pathFile+"/Process_"+number+".vsi"

    # Bioformat reading
    ImageVSI=bioformats.ImageReader(path=fileEXT)

    # Get metadata of vsi file
    metadata = get_metadata(fileEXT)

    # Get number of images of vsi file
    if numberstack is None:
        numberstack=metadata.image(0).Pixels.SizeT
    if start is None:
        start=0

    if "0" in OptionS:
        # Criteria to create video capture *****************************************************************************************
        #FIXME: Dimension of vsi in our example
        unnoyau=[0,0,1544,1038]
        height=unnoyau[3]
        width=unnoyau[2]
        # Define the codec and create VideoWriter object
        frame_size=(width,height)
        fourcc =cv2.VideoWriter_fourcc('M','J','P','G')
        # path of video output
        out2 = cv2.VideoWriter(output_path+number+'_'+start+'-'+str(numberstack)+'.avi', fourcc, 5,frame_size)
        # ***************************************************************************************************************************

    Couleur=[]
    Labels=[]

    # OPTION: To initialise sequence to save images
    if ("1" in OptionS) or ("2" in OptionS):
        multilist1=[]
        multilist2=[]

    if ("2" in OptionS):
        multilist3=[]
        multilist4=[]

    if ("3" in OptionS):
        multilist3=[]
        multilist4=[]
        try:
            os.mkdir(os.path.join(output_path,str(number)))
        except OSError:
            pass

    # Browse images in vsi
    for stack in range(int(start),int(numberstack)):

        image=ImageVSI.read(c=None,t=stack,series=0,rescale=False)
        X=cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
        X1 = normalize(X, 1,99.8, axis=axis_norm)
        label, details = model.predict_instances(X1)
        df = pd.DataFrame()
        df['class']=details['class_id']
        df['coord']=[Polygon(np.squeeze(x)) for x in np.transpose(details['coord'],(0,2,1))]
        df['area']=[x.area for x in df['coord']]

        # Compute all data for chromatophores
        stats = df.groupby('class')['area'].agg(['sum','mean', 'std','median','size'])


        """
        Class 1 : dark chromatophore
        Class 2 : light chromatophore
        """
        if ("0" in OptionS) or ("1" in OptionS) or ("2" in OptionS):


            # Criteria to create video capture *****************************************************************************************
            threshold = details['class_id']==1
            #nbClasse1=np.sum(threshold)
            arr = np.insert(threshold, 0, False, axis=None)
            Class1 = arr[label]


            threshold = details['class_id']==2
            #nbClasse2=np.sum(threshold)
            arr = np.insert(threshold, 0, False, axis=None)
            Class2 = arr[label]


            LabelClass2=label.copy()
            LabelClass2[Class1] = 0
            LabelClass1=label.copy()
            LabelClass1[Class2] = 0

            if ("0" in OptionS):

                Rouge, Vert, Bleu= image.transpose(2, 0, 1)

                Tab1 = np.where(cv2.morphologyEx(np.float32(LabelClass1),cv2.MORPH_GRADIENT,np.ones((3, 3), np.uint8)) >0)
                Rouge[Tab1] = 255
                Vert[Tab1] = 0
                Bleu[Tab1] = 0
                Tab1 = np.where(cv2.morphologyEx(np.float32(LabelClass2),cv2.MORPH_GRADIENT,np.ones((3, 3), np.uint8)) >0)
                Rouge[Tab1] = 0
                Vert[Tab1] = 0
                Bleu[Tab1] = 255
                Icolor = np.ones((height,width,3), 'uint8')
                Icolor[..., 0] = Bleu
                Icolor[..., 1] = Vert
                Icolor[..., 2] = Rouge
                out2.write(Icolor)

            # OPTION: To append binary image, mask of classes
            if ("1" in OptionS):
                multilist1.append(Image.fromarray(Class1))
                multilist2.append(Image.fromarray(Class2))

            # OPTION: To append label classes
            if ("2" in OptionS):
                multilist3.append(Image.fromarray(LabelClass1))
                multilist4.append(Image.fromarray(LabelClass2))


        # ***************************************************************************************************************************

        text=str(stack)+";"+str(1544*1038)+";"+str(stats['size'][2])+";"+str(stats['size'][1])+";"+str(stats['sum'][2])+";"+str(stats['sum'][1])+";"\
        +str(stats['mean'][2])+";"+str(stats['mean'][1])+";"+str(stats['median'][2])+";"+str(stats['median'][1])+";"\
        +str(stats['std'][2])+";"+str(stats['std'][1])\
        +"\n"
        fileResults.write(text)

        if ("3" in OptionS):
            # OPTION: Export data by image 1 image = 1 zip file
            df.to_pickle(os.path.join(output_path,str(number),number+'_'+str(stack)+'.zip')) # to read unpickled_df = pd.read_pickle(file.zip)



    # OPTION: to save image mask
    if ("1" in OptionS) :
        multilist1[0].save(output_path + number+'_'+start+'-'+str(numberstack)+"_dark_binary.tif",compression="tiff_deflate", save_all=True, append_images=multilist1[1:])
        multilist2[0].save(output_path + number+'_'+start+'-'+str(numberstack)+"_light_binary.tif",compression="tiff_deflate", save_all=True, append_images=multilist2[1:])

    if  ("2" in OptionS):
        multilist3[0].save(output_path + number+'_'+start+'-'+str(numberstack)+"_dark_label.tif",compression="tiff_deflate", save_all=True, append_images=multilist3[1:])
        multilist4[0].save(output_path + number+'_'+start+'-'+str(numberstack)+"_light_label.tif",compression="tiff_deflate", save_all=True, append_images=multilist4[1:])



    if ("0" in OptionS):
        out2.release()
    fileResults.close()

    if ("3" in OptionS):
        file = "IndividualDataFrame"  # zip file name
        make_archive(os.path.join(output_path,file), "zip", os.path.join(output_path,str(number)))  # zipping the directory
        rmtree(os.path.join(output_path,str(number)))
```

%% Cell type:code id: tags:

``` python
# Browse and find all vsi images inside folders and sub-folders
def listdirectory(path):
    fichier=[]
    for root, dirs, files in os.walk(path):
        for i in files:
            if ".vsi" in i:
                path,ext=os.path.splitext(i)
                if (os.path.isfile(os.path.join(root, path+".vsi"))):
                    fichier.append(os.path.join(root, i))
    return sorted(fichier)
```

%% Cell type:code id: tags:

``` python
# path where images are stored
pathchemin="Examples"

# path where files results are recorded
output_path="Examples/"

# call function to find vsi files
listfile=listdirectory(pathchemin)

for fileVSI in listfile:
    # get number of vsi files
    # all files in our example are this format : number_Process.vsi
    number=fileVSI.split("/")[-1].split(".")[0].replace("Process_","")

    # test if vsi file are not aleardy process
    if not os.path.isfile(output_path+number+"_resultat.csv"):
        pathFile = os.path.dirname(fileVSI)
        try:
            print("Process Image number", number)
            AI_OnePile(number,pathFile, output_path,"0","3",OptionS="9")
            AI_OnePile(number,pathFile, output_path,start="0",numberstack="3",OptionS="9")
        except:
            print("erreur :",pathFile,number)
            pass

print("End process")

```

%% Output

    Process Image number 13
    1/1 [==============================] - 1s 629ms/step
    1/1 [==============================] - 0s 405ms/step
    1/1 [==============================] - 0s 410ms/step
    End process