Saturday, June 23, 2012

cv2 opens a 12 bits TIF image properly

I tried to open a 12 bits TIFF image with python opencv (cv2) as follow:

# -*- coding: utf-8 -*-
"""
Created on Wed Jun 20 09:35:31 2012

"""
import cv2
import skimage.io as sio
png = cv2.imread('/home/simon/QFISH/JPPAnimal/JPP52/11/DAPI/particles/part9.png')
tif = cv2.imread('/home/simon/QFISH/JPPAnimal/JPP52/11/DAPI/1.TIF')
tiff = sio.imread('/home/simon/QFISH/JPPAnimal/JPP52/11/DAPI/1.TIF')
print png.dtype, type(png)
print tif.dtype, type(tif)
print tiff.dtype, type(tiff)
sio.imshow(tiff)
sio.show()

cv2 recognises the image 1.TIF (12 bits TIFF) as 8 bits image, as the console output is:

uint8 <type 'numpy.ndarray'>
uint8 <type 'numpy.ndarray'>
uint16 <type 'numpy.ndarray'>



may be a flag issue in cv2.imread...

From Stackoverflow, or from the cv2 doc,  the image must be loaded "as it is" with a flag set to -1:
tif = cv2.imread('/home/simon/QFISH/JPPAnimal/JPP52/11/DAPI/1.TIF', -1)

The image loaded with cv2.imread can be then displayed as any numpy.ndarray with skimage:


Sunday, May 20, 2012

FlyFISH:navigation in the ADIR MFISH images database

FlyFISH allows to visualize images of the ADIR MFISH database. FlyFISH is written in python, the GUI is based on pyQt4, images are loaded and displayed with imread, qimage2ndarray. To work properly, FlyFISH requires:
The path to the DatabaseMFISH.xml file must be modified in the script:
root=et.parse('/home/simon/DatabaseMFISH.xml').getroot() 
and the path to database top directory:
workdir="/home/simon/MFISH/"

The script was tested on ubuntu 12.04, to run faster, the image size was reduced on display:

Thanks to ashren.

Wednesday, May 9, 2012

Converting a directories tree to a xml object: test with MFISH dataset

Once the MFISH dataset  reordered properly,   a xml object representing the directories hierarchy is build.
The  MFISH folder contains three subfolders: ASI, PSI and Vysis . Let's build a xml file called ASI. let's find the line 51 in the following python script and modify to fit the path to the ASI folder, for example:

topdir = '/home/user/MFISH/ASI'

then run the script:

# -*- coding: utf-8 -*-
"""
Created on Tue Jan 31 13:30:22 2012

@author: Jean-Patrick Pommier 
    with a huge help of Mont29:
    http://www.developpez.net/forums/u238430/mont29/
"""
import lxml.etree as et
import os,re

def filtreImages(files):
    filtlist=[]
    #a file name ending with  .TIF or .tif
    regex=re.compile('.(TIF|tif)$')
    if len(files)>0:
        for f in files:
            result=regex.search(f)
            if result<>None:
                #print f
                filtlist.append(f)              
    #print filtlist
    return filtlist

def makeNodes(node_dirs, root, leveldirlist, root_level, files):
    # Penser à aérer le code, c’est plus agréable à lire...
    code = {0: 'slide', 1: 'field', 2: 'fluorochrome', 3: 'TooDeep'}
    for d in leveldirlist:
        child = et.Element(code[root_level], name=d)
        if code[root_level] == 'field':
            child.set('ROI', 'x0,y0,x1,y1')
            child.set( 'position','-1,-1')
        nodes_dirs[os.path.join(root, d)] = child
        nodes_dirs[root].append(child)
    # Le "if len(file) > 0" est inutile, si une liste est vide,
    # itérer dessus revient à ne rien faire ;)
    #
    # files est indépendant de leveldirlist, il faut donc boucler dessus
    # "à part"!
    for image in files:
        #print " root:", root, " root_level:", root_level, " image:", image
        child = et.Element("image",name=image, exposure='0.0')
        # Ne surtout pas utiliser d ici! Sinon, on écrase les nœuds définis
        # dans la boucle précédente... image devrait faire l’affaire :p
        nodes_dirs[os.path.join(root, image)] = child
        nodes_dirs[root].append(child)
                  
level={}            
if __name__ == '__main__':
    #topdir = '/home/claire/Applications/ProjetPython/testxml/P'
    topdir = '/home/simon/MFISH/ASI'
    projetxml = et.Element('CytoGenet')  # racine
    parent = projetxml
    nodes_dirs = {topdir: parent}
    ln_root = len(topdir)
    
    for root, dirs, files in os.walk(topdir):
        lvl = root[ln_root:].count(os.path.sep)
        #print nodes_dirs
        filtered=filtreImages(files)
        #print filtered
        makeNodes(nodes_dirs, root, dirs, lvl,filtered)
        
        
            
    print(et.tostring(projetxml,pretty_print=True))
    print projetxml.getchildren()[0].get("name")
    slides=projetxml.getchildren()[0]
    print len(slides)
    print projetxml.getchildren()[1].get("name")
    slides=projetxml.getchildren()
    
    metaphases1=slides[0].getchildren()
    
    metaphases2=slides[1].getchildren()
    for m in metaphases2:
        print m.get("name")
    
   
The script just display the xml object:

<ASI>
  <slide name="A32">
    <field name="01" ROI="x0,y0,x1,y1" position="-1,-1">
      <fluorochrome name="SpGreen">
        <image name="A3201EXG.tif" exposure="0.0"/>
      </fluorochrome>
      <fluorochrome name="SpOrange">
        <image name="A3201EXO.tif" exposure="0.0"/>
      </fluorochrome>
      <fluorochrome name="TexasRed">
        <image name="A3201EXT.tif" exposure="0.0"/>
      </fluorochrome>
      <fluorochrome name="Cy5-5">
        <image name="A3201EX5.tif" exposure="0.0"/>
      </fluorochrome>
      <fluorochrome name="DAPI">
        <image name="A3201EXD.tif" exposure="0.0"/>
      </fluorochrome>
      <fluorochrome name="Cy5">
        <image name="A3201EXC.tif" exposure="0.0"/>
      </fluorochrome>
    </field>

Tuesday, May 8, 2012

gimp 2.8 can't open a 16 bits TIFF image

But no one says that it should...may be next time.

One shot scripts to reorder images in the ASI/PSI/Vysis-MFISH dataset

The images belonging to the MFISH dataset are not ordered in a hierachy of directories defined as project/slides/field_xy/fluorochromes/image.
To navigate through that images database as in the previous post, the images need to be reordered.
The central part of the following image displays the original images arrangement, the right side shows the images after reordering. We have for example a slide called A01 belonging to the ASI MFISH dataset . For this slide, five xy fields were taken (from 01 to 05) . The folder called Kar, contains the segmented image (the chromosome 1 is set to grey level  and so on).


Three dirty python scripts (pylint 1.76/10 !) reorder the MFISH dataset. One for each images subset (ASI, PSI or Vysis). Prior running the scripts:
  • make three folders (ASI, PSI, Vysis) in the top directory (MFISH)
  • select all the slides whose name start by 'A', cut and copy them in the ASI folder and so on the the PSI slides (starting by a 'P') and the Vysis slides (starting by a 'V').
  • modify the path to the top directory inside the script and run the ASI script to reorder the images from ASI images subset.
  • run the PSI script ...
  • run the Vysis script.
To modify the path find the line:

path='/home/simon/MFISH/'+'ASI'
Modify it as:
 
path='/fit/to/your/path/MFISH/'+'ASI'
 
The pygmentized ASI script is shown:

# -*- coding: utf-8 -*-
"""
Created on Thu Apr  5 14:43:39 2012

@author: jean-pat

3   532
5   Cy 5.5
6   568
A   S. Aqua
C   Cy 5
D   DAPI
E   DEAC
F   Far Red
G   S. Green
I   FITC
O   S. Orange
R   S. Red
T   Texas Red
Y   S. Gold

"""

import sys,os
from shutil import move,rmtree
import re

#Choix répertoire ex Vysis ou ASI ou PSI/Cytocell
path='/home/simon/MFISH/'+'ASI'
slidelist=os.listdir(path)

fluoASI={'5':'Cy5-5','C':'Cy5','D':'DAPI','G':'SpGreen','O':'SpOrange','T':'TexasRed','K':'Kar'}
fluoPSI={'C':'Cy5','D':'DAPI','E':'DEAC','I':'FITC','3':'532','6':'568','K':'Kar'}
fluoVysis={'A':'SpAqua','D':'DAPI','F':'FarRed','G':'SpGreen','R':'SpRed','Y':'SpGold','K':'Kar'}
print "slidelist[0]",slidelist[0]
for apv_slide in slidelist:
    #listfield=os.listdir(os.path.join(path,slidelist[0]))
    listfield=os.listdir(os.path.join(path,apv_slide))
    print listfield
    #cherchons le numero des images dans le nom des fichiers
    #contient V au début et .tif à la fin
    slidecode=apv_slide[0:1]#V for vysis, A for ASI, P for PSI
    motif=re.compile('.tif$')
    imagelist=[]
    for image in listfield:
        if not(motif.search(image)==None):
            imagelist.append(image)
    #print imagelist
    #obtenir le numero des images
    imagenumberlist=[]
    for image in imagelist:
        number=image[3:5]
        if number not in imagenumberlist:
            imagenumberlist.append(number)
    #print imagenumberlist
    #créer un répertoire correspondant au numéro de l'image(métaphase)
    for imNb in imagenumberlist:
        metaphasepath=os.path.join(path,apv_slide,imNb)
        os.makedirs(metaphasepath)
        #puis déplacer les images imNb dedans
        imagesToMove=[item for item in imagelist if item[3:5]==imNb]
        #print imagesToMove
        #print 'MOVING ',imNb, '************'
        for fluo in imagesToMove:
            sourceimage=os.path.join(path,apv_slide,fluo)
            destimage=os.path.join(path,apv_slide,imNb,fluo)
            #os.renames(sourceimage,destimage)
            #print fluo
            #print fluo[7:8],'component:',fluoVysis[fluo[7:8]]
            #make fluorochrome directories
            os.makedirs(os.path.join(path,apv_slide,fluoASI[fluo[7:8]]))
            #print 'Source',sourceimage,os.path.exists(sourceimage)
            #print 'Dest',destimage,os.path.exists(destimage)
            #move component image into component directory
            destComponentImage=os.path.join(path,apv_slide,fluoASI[fluo[7:8]],fluo)
            #print ' **** move compenent images into comp dirs'
            move(sourceimage,destComponentImage)
            #print ' **** ----move compenent dir into metaphase dirs'
            sourceCompDir=os.path.join(path,apv_slide,fluoASI[fluo[7:8]])
            destMetaphaseDir=metaphasepath
            move(sourceCompDir,destMetaphaseDir)
    #fusionner les dossiers correspondant à une même lame
    ## ex V29_62 et V29_63 dans V29

mfishSlidesList=os.listdir(path)
print mfishSlidesList
slidecode='A'#apv_slide[0:1]#V for vysis, A for ASI, P for PSI
    #store the number of each slide V29_62 et V29_63 -> 29
#==============================================================================
#     #For a given slide ex V29_62
#==============================================================================
dirtomake=[]
for slide in mfishSlidesList:
    slidenumber=slide[1:3]# ex 13, 14...29 for vysis
    #print slidenumber
    if slidenumber not in dirtomake:
        dirtomake.append(slidenumber)
        
for d in dirtomake:
    slidename=slidecode+d
    print "makedir " , os.path.join(path,slidename)
    os.makedirs(os.path.join(path,slidename))
    
for newdir in dirtomake:
    slidename=slidecode+newdir
    #find all slides starting by slidename
    slides_content_to_move=[] #ex all V29_xx
    #print "moving slides starting by " , slidename
    for movingslide in mfishSlidesList:        
        
        if movingslide[0:3]==slidename:
            slides_content_to_move.append(movingslide)
        
        for moving in slides_content_to_move:
            current_content=os.listdir(os.path.join(path,moving))
            #print "current content of" , movingslide , "is =" , current_content
            
            for cc in current_content:
                source=os.path.join(path , movingslide , cc)
                dest=os.path.join(path , slidename , cc)
                print "move ", source, "-> dest" , dest
                move(source,dest)
    #print "end",mfishSlidesList
    
#supprimer les lames vides
for empty_slide in mfishSlidesList:
    curpath=os.path.join(path,empty_slide)
    print empty_slide
    print "remove(",os.path.join(path,empty_slide),")"
    print 'dir?',os.path.isdir(curpath),'vide?',os.listdir(curpath)
    os.removedirs(curpath)

Thursday, April 5, 2012

Navigation in an images database with a PyQt application

When recording images taken in a FISH assay, it is convenient to store them hierarchically to take into account the project, the slides, the image location on the slide, the fluorochromes used, the image itself with possible variable exposure time and possibly the variable z value  if 3D imaging is performed (only 2D will be considered).

In a previous post, a xml tree structure was proposed to store that hierarchy.
To navigate through that tree a PyQt4 widget was developed mirroring the tree:
Cascading menus are used in the GUI to navigate in the xml tree
It looks like that:
For this trial the xml tree was not complete. There are two projects, applied or vysis, but only the "applied" project has a complete slide (s1).

Version 002 of the script is here