added nearly all of estimate_white's post processing (particles removal)

As a result, the implementation of estimate_white is getting closer to completion. However, the performance of fiji's gray morphology is very poor, which makes it practically unusable with the default settings provided in the original code (estimateWhiteFluoImageTelemos)

Bug 2623 - Faire un traitement automatique pour les images du projet lipase
This commit is contained in:
Guillaume Raffy 2019-09-13 15:15:01 +02:00
parent 40d1fdd34b
commit e8523efd18
2 changed files with 191 additions and 113 deletions

View File

@ -5,6 +5,21 @@ from ij.plugin import ImageCalculator
from catalog import ImageCatalog, Sequence
def imagej_run_image_command(image, command, options):
"""performs the given imagej command on the given image
:param ImagePlus image:
:param str command: imagej command (eg "Gray Morphology")
:param str options: imagej options (eg "radius=1 type=square operator=open")
wrapper around IJ.run (https://imagej.nih.gov/ij/developer/api/ij/IJ.html#run-ij.ImagePlus-java.lang.String-java.lang.String-) which raises an exception on error
"""
IJ.run(image, command, options)
error_message = IJ.getErrorMessage()
if error_message is not None:
raise Exception('The command "%s" with options "%s" failed because of the following error : %s' % (command, options, error_message))
def compute_max(images_file_path):
"""Computes for each pixel position the maximum at this position in all input images.
@ -45,120 +60,179 @@ def replace_outer_frame(image, band_width):
return image
def estimate_white(sequences, channel_ids, dark=None):
"""Estimation of the white fluorescence image shape of synchrotron light from experimental images of Telemos microscope.
:param list(Sequence) sequences:
:param list(str) channel_ids:
:param ImagePlus or None dark:
:rtype ImagePlus:
Code adapted from matlab telemosToolbx's estimatedwhiteFluoImageTelemos function
% this function is specific of Telemos images (DISCO line SOLEIL)
% acquired using micromanager software linked to imageJ
%% input
% nothing : interactive function
%% output
% nothing : the final reference fluorescence image is saved on disk
%% principe
% NB: MICROMANAGER save images in a structured file folder architecture :
%
% root folder : name given by the user
%
% subfolders roi(n)_tile1 : n folders for each selected roi
% or pos(n) : n folders for each selected position
%
% display_and_comments.txt : file describing the channels acquired
%
% in each subfolder roi(n)_tile1 or Pos(n) :
% images files with name img_00000000(n)_DM300_327-353_00(p).tif
% n = number of time
% p = z focal plane
% DM300_327-353 = name of the channel
% metadata.txt : files describing all metadata associated with the
% acquisition : x, y, z position, camera settings .... etc.
%
% (Nb: depending on the date of acquisition, an extension fluo is found or
% not in the name of fluorescence image. This extension is given in
% contrast to the visible image.)
%
% IMAGES : fluorescence images are considered
%
%
% IMPORTANT:
% it is expected that in the folders at least several images cover the whole field of view
% illuminated by the synchrtron light
% IF IT IS NOT THE CASE, IT WON'T WORK
%
% BASIC: the estimated white image is the MAX of the selected images
% when interactive mode is selected, only first time and first z are
% proposed
% for automatic computing, all images are taken into account
%
% WHAT IS DONE:
% 0 - the user chosse the channels that are considered in the estimation of the
% white fluorescence image
%
% 1 - spurious pixels (three lines and columns around the image) are not taken
% in filtering and replaced by line and column number 4 and end-3
%
% 2 - Filtering
% the estimated dark image is filtered :
% opening to remove white regions brighter than the low frequency signal that should correspond to synchrotron light shape (should be small)
% closing to remove black regions that remains (should be small to avoid synchrotron light shape deformation)
% average filtering
% the image computed should be used to
% - to find the best white z plane from the reference white stack
% acquired for ex. using the so called "Matthieu lame"%
% - correct images for intensities
%% use
% estimatedwhiteFluoImageTelemos
%% Comments
% adapted from proposals 20161050 and 20171187
%% Author
% MF Devaux
% INRA BIA
% PVPP
%% date
% 5 octobre 2017:
% 23 mars 2018
% 3 septembre 2018 : comments and general case
% 16 avril 2019: name of function and default filtering values
% 29 avril 2019 : new comments and spurious pixels
% 27 mai 2019 : offset dark
% 4 juin 2019 : replace exist by isfolder or isfile
% 14 juin : close figure at the end
def perform_gray_morphology(image, operator, structuring_element_shape, structuring_element_radius):
"""
images_file_path = []
for sequence in sequences:
for channel_id in channel_ids:
channel_index = sequence.get_channel_index(channel_id)
for frame_index in range(sequence.num_frames):
for z_index in range(sequence.num_slices):
images_file_path.append(sequence.get_image_file_path(channel_index, frame_index, z_index))
white_estimate = compute_max(images_file_path)
:param ImagePlus image:
:param str operator: eg 'open'
:param str structuring_element_shape: eg 'square'
:param int structuring_element_radius:
"""
assert operator not in ['fast open', 'fast erode'], "as of 13/09/2019, fast operators such as 'fast erode' seem broken in fiji (the resulting image is not at all similar to their slow equivalent)"
# modifiy spurious pixels on the side of the images
try:
replace_outer_frame(white_estimate, 3)
except NotImplementedError as error:
print('warning: replace_outer_frame is not implemented yet')
processor = image.getProcessor()
convert_to_byte = False
if processor.getBitDepth() != 8:
convert_to_byte = True
min_value = processor.getMin()
max_value = processor.getMax()
print("warning: downgrading image to byte as imagej's Gray Morphology processing doesn't handle 16bit images (range=[%d, %d])" % (min_value, max_value))
do_scaling = True
image.setProcessor(processor.convertToByte(do_scaling))
print("before gray morphology")
assert structuring_element_radius < 11, "the radius of the structuring element is too big (%d); using it with Fiji's 'Gray Morphology' tool would result in very long computations." % structuring_element_radius
imagej_run_image_command(image, "Gray Morphology", "radius=%d type=%s operator=%s" % (structuring_element_radius, structuring_element_shape, operator))
print("after gray morphology")
return white_estimate
class WhiteEstimator(object):
def __init__(self, open_size, close_size, average_size):
self.open_size = open_size
self.close_size = close_size
self.average_size = average_size
def _remove_particles(self, white_estimate):
perform_gray_morphology(white_estimate, operator='open', structuring_element_shape='square', structuring_element_radius=(self.open_size + 1)/2)
perform_gray_morphology(white_estimate, operator='close', structuring_element_shape='square', structuring_element_radius=(self.close_size + 1)/2)
def estimate_white(self, sequences, channel_ids, dark=None):
"""Estimation of the white fluorescence image shape of synchrotron light from experimental images of Telemos microscope.
:param list(Sequence) sequences: the sequences to consider
:param list(str) channel_ids: the channels to consider, eg ['DM300_327-353_fluo']
:param WhiteEstimatorSettings white_estimator_settings:
:param ImagePlus or None dark:
:rtype ImagePlus:
Code adapted from matlab telemosToolbx's estimatedwhiteFluoImageTelemos function
% this function is specific of Telemos images (DISCO line SOLEIL)
% acquired using micromanager software linked to imageJ
%% input
% nothing : interactive function
%% output
% nothing : the final reference fluorescence image is saved on disk
%% principe
% NB: MICROMANAGER save images in a structured file folder architecture :
%
% root folder : name given by the user
%
% subfolders roi(n)_tile1 : n folders for each selected roi
% or pos(n) : n folders for each selected position
%
% display_and_comments.txt : file describing the channels acquired
%
% in each subfolder roi(n)_tile1 or Pos(n) :
% images files with name img_00000000(n)_DM300_327-353_00(p).tif
% n = number of time
% p = z focal plane
% DM300_327-353 = name of the channel
% metadata.txt : files describing all metadata associated with the
% acquisition : x, y, z position, camera settings .... etc.
%
% (Nb: depending on the date of acquisition, an extension fluo is found or
% not in the name of fluorescence image. This extension is given in
% contrast to the visible image.)
%
% IMAGES : fluorescence images are considered
%
%
% IMPORTANT:
% it is expected that in the folders at least several images cover the whole field of view
% illuminated by the synchrtron light
% IF IT IS NOT THE CASE, IT WON'T WORK
%
% BASIC: the estimated white image is the MAX of the selected images
% when interactive mode is selected, only first time and first z are
% proposed
% for automatic computing, all images are taken into account
%
% WHAT IS DONE:
% 0 - the user chosse the channels that are considered in the estimation of the
% white fluorescence image
%
% 1 - spurious pixels (three lines and columns around the image) are not taken
% in filtering and replaced by line and column number 4 and end-3
%
% 2 - Filtering
% the estimated dark image is filtered :
% opening to remove white regions brighter than the low frequency signal that should correspond to synchrotron light shape (should be small)
% closing to remove black regions that remains (should be small to avoid synchrotron light shape deformation)
% average filtering
% the image computed should be used to
% - to find the best white z plane from the reference white stack
% acquired for ex. using the so called "Matthieu lame"%
% - correct images for intensities
%% use
% estimatedwhiteFluoImageTelemos
%% Comments
% adapted from proposals 20161050 and 20171187
%% Author
% MF Devaux
% INRA BIA
% PVPP
%% date
% 5 octobre 2017:
% 23 mars 2018
% 3 septembre 2018 : comments and general case
% 16 avril 2019: name of function and default filtering values
% 29 avril 2019 : new comments and spurious pixels
% 27 mai 2019 : offset dark
% 4 juin 2019 : replace exist by isfolder or isfile
% 14 juin : close figure at the end
"""
images_file_path = []
for sequence in sequences:
for channel_id in channel_ids:
channel_index = sequence.get_channel_index(channel_id)
for frame_index in range(sequence.num_frames):
for z_index in range(sequence.num_slices):
images_file_path.append(sequence.get_image_file_path(channel_index, frame_index, z_index))
white_estimate = compute_max(images_file_path)
# modify spurious pixels on the side of the images
try:
replace_outer_frame(white_estimate, 3)
except NotImplementedError as error:
print('warning: replace_outer_frame is not implemented yet')
self._remove_particles(white_estimate)
return white_estimate
class InteractiveWhiteEstimator(WhiteEstimator):
def __init__(self, open_size, close_size, average_size):
WhiteEstimator.__init__(self, open_size, close_size, average_size)
def _remove_particles(self, white):
"""shows the image to a user so that he can visually check that the particles have been removed correctly in the given image
"""
raise NotImplementedError()
# part_rem_settings_are_good = False
# while part_rem_settings_are_good == False:
# # perform opening to remove white particles
# IJ.run( white_estimate, "Gray Morphology", "radius=1 type=square operator=open" )
# # run("Gray Morphology", "radius=1 type=square operator=open");
# # IJ.run( input_image_plus_copy, "Skeletonize (2D/3D)", "" )
# # perform
# if white_estimator_settings.particles_are_removed():
# part_rem_settings_are_good = true
# else
# white_estimator_settings.ask
def find_white_reference_image(white_estimate, white_z_stack):
@ -263,7 +337,8 @@ def test_preprocessing():
"""Test preprocessing."""
catalog = ImageCatalog('/Users/graffy/ownCloud/ipr/lipase/raw-images')
sequence = catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos2']
white_estimate = estimate_white([sequence], ['DM300_327-353_fluo'])
white_estimator = WhiteEstimator(open_size=75, close_size=75, average_size=75)
white_estimate = white_estimator.estimate_white([sequence], ['DM300_327-353_fluo'])
find_white_reference_image(white_estimate, sequence.get_white())

View File

@ -16,12 +16,15 @@ sys.path.append(lipase_src_root_path) # necessary if run from fiji as script ot
from ij import IJ
from lipase import Lipase, ImageLogger
from catalog import ImageCatalog
from preprocessing import WhiteEstimator
def run_script():
catalog = ImageCatalog(raw_images_root_path) # eg '/Users/graffy/ownCloud/ipr/lipase/raw-images'
lipase = Lipase(catalog, debugger=ImageLogger())
sequence = catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos2']
white_estimate = lipase.estimate_white(sequence, 'DM300_327-353_fluo')
# white_estimator = WhiteEstimator(open_size=75, close_size=75, average_size=75)
white_estimator = WhiteEstimator(open_size=3, close_size=3, average_size=3)
white_estimate = white_estimator.estimate_white([sequence], ['DM300_327-353_fluo'])
print(white_estimate)
IJ.saveAsTiff(white_estimate, './white_estimate.tiff')
print('end')