The Estimate White plugin now takes the selected stack as input instead of asking the user the sequence
This makes Estimate White plugin's UI more in line with imagej's plugin conventions.
This commit is contained in:
parent
44dacc1a97
commit
7973cfc3ec
|
@ -1,6 +1,7 @@
|
|||
#@ Integer (label="open size (in pixels)", value=75, style="slider") OPEN_SIZE
|
||||
#@ Integer (label="close size (in pixels)", value=75, style="slider") CLOSE_SIZE
|
||||
#@ Integer (label="average size (in pixels)", value=75, style="slider") AVERAGE_SIZE
|
||||
#@ ImagePlus (label="the input image stack") INPUT_STACK
|
||||
#@ Integer (label="open size (in pixels)", value=75, min=0, max=500, style="slider") OPEN_SIZE
|
||||
#@ Integer (label="close size (in pixels)", value=75, min=0, max=500, style="slider") CLOSE_SIZE
|
||||
#@ Integer (label="average size (in pixels)", value=75, min=0, max=500, style="slider") AVERAGE_SIZE
|
||||
|
||||
#@output ImagePlus WHITE_ESTIMATE
|
||||
"""This script is supposed to be launched from fiji's jython interpreter
|
||||
|
@ -26,7 +27,7 @@ from lipase.settings import UserSettings
|
|||
# sys.path.append(lipase_src_root_path) # pylint: disable=undefined-variable
|
||||
|
||||
# from lipase import Lipase, ImageLogger
|
||||
from lipase.imageengine import IImageEngine
|
||||
from lipase.imageengine import IImageEngine, PixelType, StackImageFeeder
|
||||
from lipase.imagej.ijimageengine import IJImageEngine
|
||||
from lipase.preprocessing import WhiteEstimator
|
||||
from lipase.catalog import ImageCatalog
|
||||
|
@ -45,65 +46,15 @@ from java.awt.event import ItemListener
|
|||
# # event's attributes : ['ACTION_EVENT_MASK', 'ADJUSTMENT_EVENT_MASK', 'COMPONENT_EVENT_MASK', 'CONTAINER_EVENT_MASK', 'DESELECTED', 'FOCUS_EVENT_MASK', 'HIERARCHY_BOUNDS_EVENT_MASK', 'HIERARCHY_EVENT_MASK', 'ID', 'INPUT_METHOD_EVENT_MASK', 'INVOCATION_EVENT_MASK', 'ITEM_EVENT_MASK', 'ITEM_FIRST', 'ITEM_LAST', 'ITEM_STATE_CHANGED', 'KEY_EVENT_MASK', 'MOUSE_EVENT_MASK', 'MOUSE_MOTION_EVENT_MASK', 'MOUSE_WHEEL_EVENT_MASK', 'PAINT_EVENT_MASK', 'RESERVED_ID_MAX', 'SELECTED', 'TEXT_EVENT_MASK', 'WINDOW_EVENT_MASK', 'WINDOW_FOCUS_EVENT_MASK', 'WINDOW_STATE_EVENT_MASK', '__class__', '__copy__', '__deepcopy__', '__delattr__', '__doc__', '__ensure_finalizer__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__subclasshook__', '__unicode__', 'class', 'equals', 'getClass', 'getID', 'getItem', 'getItemSelectable', 'getSource', 'getStateChange', 'hashCode', 'item', 'itemSelectable', 'notify', 'notifyAll', 'paramString', 'setSource', 'source', 'stateChange', 'toString', 'wait']
|
||||
|
||||
|
||||
class SequenceChoiceListener(ItemListener):
|
||||
|
||||
def __init__(self, channel_choice, catalog):
|
||||
ItemListener.__init__(self)
|
||||
self.channel_choice = channel_choice
|
||||
self.catalog = catalog
|
||||
|
||||
def itemStateChanged(self, event):
|
||||
IJ.log("SequenceChoiceListener : Something was changed (event = %s)" % event)
|
||||
# SequenceChoiceListener : Something was changed (event = java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item=res_soleil2018/DARK/DARK_40X_60min_1 im pae min_1/Pos0,stateChange=SELECTED] on choice3)
|
||||
IJ.log("SequenceChoiceListener : event's attributes : %s" % str(dir(event)))
|
||||
# SequenceChoiceListener : event's attributes : ['ACTION_EVENT_MASK', 'ADJUSTMENT_EVENT_MASK', 'COMPONENT_EVENT_MASK', 'CONTAINER_EVENT_MASK', 'DESELECTED', 'FOCUS_EVENT_MASK', 'HIERARCHY_BOUNDS_EVENT_MASK', 'HIERARCHY_EVENT_MASK', 'ID', 'INPUT_METHOD_EVENT_MASK', 'INVOCATION_EVENT_MASK', 'ITEM_EVENT_MASK', 'ITEM_FIRST', 'ITEM_LAST', 'ITEM_STATE_CHANGED', 'KEY_EVENT_MASK', 'MOUSE_EVENT_MASK', 'MOUSE_MOTION_EVENT_MASK', 'MOUSE_WHEEL_EVENT_MASK', 'PAINT_EVENT_MASK', 'RESERVED_ID_MAX', 'SELECTED', 'TEXT_EVENT_MASK', 'WINDOW_EVENT_MASK', 'WINDOW_FOCUS_EVENT_MASK', 'WINDOW_STATE_EVENT_MASK', '__class__', '__copy__', '__deepcopy__', '__delattr__', '__doc__', '__ensure_finalizer__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__subclasshook__', '__unicode__', 'class', 'equals', 'getClass', 'getID', 'getItem', 'getItemSelectable', 'getSource', 'getStateChange', 'hashCode', 'item', 'itemSelectable', 'notify', 'notifyAll', 'paramString', 'setSource', 'source', 'stateChange', 'toString', 'wait']
|
||||
IJ.log("SequenceChoiceListener : event.item : %s" % str(event.item))
|
||||
IJ.log("SequenceChoiceListener : type(event.item) : %s" % str(type(event.item)))
|
||||
selected_sequence_id = event.item
|
||||
selected_sequence = self.catalog.sequences[selected_sequence_id]
|
||||
channel_ids = selected_sequence.get_channel_names()
|
||||
|
||||
self.channel_choice.removeAll()
|
||||
for channel_id in channel_ids:
|
||||
self.channel_choice.add(channel_id)
|
||||
|
||||
|
||||
def ask_for_sequence(catalog):
|
||||
title = 'select the sequence to process'
|
||||
gd = GenericDialog(title)
|
||||
# gd.addDialogListener(MyListener())
|
||||
sequence_ids = catalog.sequences.keys()
|
||||
assert len(sequence_ids) > 0
|
||||
default_sequence_id = sequence_ids[0]
|
||||
gd.addChoice('sequence', sequence_ids, default_sequence_id)
|
||||
channel_ids = catalog.sequences[default_sequence_id].get_channel_names()
|
||||
gd.addChoice('channel', channel_ids, channel_ids[0])
|
||||
choices = gd.getChoices()
|
||||
IJ.log("choices = %s" % choices)
|
||||
sequence_choice = choices[0]
|
||||
channel_choice = choices[1]
|
||||
sequence_choice.addItemListener(SequenceChoiceListener(channel_choice, catalog))
|
||||
gd.showDialog()
|
||||
if gd.wasCanceled():
|
||||
return {}
|
||||
selected_sequence_id = sequence_ids[gd.getNextChoiceIndex()] # eg 'res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos2'
|
||||
selected_channel_id = catalog.sequences[selected_sequence_id].get_channel_names()[gd.getNextChoiceIndex()] # eg 'DM300_327-353_fluo'
|
||||
print("chosen sequence : %s" % selected_sequence_id)
|
||||
print("chosen channel : %s" % selected_channel_id)
|
||||
return {'sequence': catalog.sequences[selected_sequence_id], 'channel_id':selected_channel_id}
|
||||
|
||||
|
||||
def run_script():
|
||||
user_settings = UserSettings()
|
||||
IImageEngine.set_instance(IJImageEngine())
|
||||
catalog = ImageCatalog(user_settings.raw_images_root_path)
|
||||
user_selection = ask_for_sequence(catalog)
|
||||
if len(user_selection) == 0:
|
||||
return
|
||||
sequence = user_selection['sequence']
|
||||
channel_id = user_selection['channel_id']
|
||||
src_hyperstack = IImageEngine.get_instance().create_hyperstack(width=1, height=1, num_channels=1, num_slices=1, num_frames=1, pixel_type=PixelType.U8)
|
||||
src_hyperstack.hyperstack = INPUT_STACK
|
||||
image_set = StackImageFeeder(src_hyperstack)
|
||||
white_estimator = WhiteEstimator(open_size=OPEN_SIZE, close_size=CLOSE_SIZE, average_size=AVERAGE_SIZE)
|
||||
white_estimate = white_estimator.estimate_white([sequence], [channel_id])
|
||||
white_estimate = white_estimator.estimate_white_from_image_set(image_set)
|
||||
print(type(white_estimate))
|
||||
global WHITE_ESTIMATE
|
||||
WHITE_ESTIMATE = white_estimate.ij_image
|
||||
|
|
|
@ -51,6 +51,19 @@ class IHyperStack(ABC):
|
|||
def height(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def num_slices(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def num_frames(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def num_channels(self):
|
||||
pass
|
||||
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_image(self, image, frame_index=0, slice_index=0, channel_index=0):
|
||||
"""
|
||||
|
@ -58,6 +71,101 @@ class IHyperStack(ABC):
|
|||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_image(self, frame_index=0, slice_index=0, channel_index=0):
|
||||
"""
|
||||
:param IImage image:
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class IImageFeeder(ABC):
|
||||
"""An object that generates a collection of images of the same size and same format
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def __iter__(self):
|
||||
"""
|
||||
for iterator
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def next(self):
|
||||
"""returns the nex image in the collection
|
||||
for iterator
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class FileImageFeeder(IImageFeeder):
|
||||
|
||||
def __init__(self):
|
||||
self.image_filepaths = []
|
||||
self.next_image_index = 0
|
||||
|
||||
def __iter__(self):
|
||||
self.next_image_index = 0
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
if self.next_image_index < len(self.image_filepaths):
|
||||
image_filepath = self.image_filepaths[self.next_image_index]
|
||||
self.next_image_index += 1
|
||||
image = IImageEngine.get_instance().load_image(image_filepath)
|
||||
return image
|
||||
raise StopIteration
|
||||
|
||||
def add_image(self, image_filepath):
|
||||
self.image_filepaths.append(image_filepath)
|
||||
|
||||
|
||||
class StackImageFeeder(IImageFeeder):
|
||||
|
||||
def __init__(self, hyperstack):
|
||||
"""
|
||||
:param IHyperStack hyperstack
|
||||
"""
|
||||
self.hyperstack = hyperstack
|
||||
|
||||
def _init_iter(self):
|
||||
self.next_frame_index = 0
|
||||
self.next_slice_index = 0
|
||||
self.next_channel_index = 0
|
||||
self.end_is_reached = False
|
||||
|
||||
def __iter__(self):
|
||||
self._init_iter()
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
print(self.next_channel_index, self.next_frame_index, self.next_slice_index)
|
||||
print(self.hyperstack.num_channels, self.hyperstack.num_frames, self.hyperstack.num_slices)
|
||||
if self.end_is_reached:
|
||||
raise StopIteration
|
||||
else:
|
||||
image = self.hyperstack.get_image(frame_index=self.next_frame_index, slice_index=self.next_slice_index, channel_index=self.next_channel_index)
|
||||
|
||||
# compute next image index
|
||||
if self.next_slice_index < self.hyperstack.num_slices():
|
||||
self.next_slice_index += 1
|
||||
else:
|
||||
self.next_slice_index = 0
|
||||
if self.next_frame_index < self.hyperstack.num_frames():
|
||||
self.next_frame_index += 1
|
||||
else:
|
||||
self.next_frame_index = 0
|
||||
if self.next_channel_index < self.hyperstack.num_channels():
|
||||
self.next_channel_index += 1
|
||||
else:
|
||||
self.end_is_reached = True
|
||||
|
||||
return image
|
||||
|
||||
def add_image(self, image_filepath):
|
||||
self.image_filepaths.append(image_filepath)
|
||||
|
||||
|
||||
|
||||
|
||||
class IImageEngine(ABC):
|
||||
|
@ -107,10 +215,10 @@ class IImageEngine(ABC):
|
|||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def compute_max(self, images_file_path):
|
||||
def compute_max(self, image_feeder):
|
||||
"""Compute for each pixel position the maximum at this position in all input images.
|
||||
|
||||
:param list(str) images_file_path:
|
||||
:param IImageFeeder image_feeder:
|
||||
:rtype IImage:
|
||||
"""
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"""
|
||||
|
||||
from ..imageengine import IImage, IHyperStack, IImageEngine, PixelType
|
||||
from ij import IJ # pylint: disable=import-error
|
||||
from ij import IJ, ImagePlus # pylint: disable=import-error
|
||||
from ij.plugin import ImageCalculator # pylint: disable=import-error
|
||||
from ijopencv.ij import ImagePlusMatConverter # pylint: disable=import-error
|
||||
from ijopencv.opencv import MatImagePlusConverter # pylint: disable=import-error
|
||||
|
@ -30,9 +30,10 @@ class IJImage(IImage):
|
|||
|
||||
class IJHyperStack(IHyperStack):
|
||||
|
||||
def __init__(self, width, height, num_channels, num_slices, num_frames, pixel_type):
|
||||
def __init__(self, image_engine, width, height, num_channels, num_slices, num_frames, pixel_type):
|
||||
"""
|
||||
"""
|
||||
self.image_engine = image_engine
|
||||
stack_name = ''
|
||||
self.hyperstack = IJ.createHyperStack(stack_name, width, height, num_channels, num_slices, num_frames, PixelType.get_num_bits(pixel_type))
|
||||
|
||||
|
@ -40,12 +41,35 @@ class IJHyperStack(IHyperStack):
|
|||
self.hyperstack.setPositionWithoutUpdate(channel_index + 1, slice_index + 1, frame_index + 1)
|
||||
self.hyperstack.setProcessor(image.ij_image.getProcessor())
|
||||
|
||||
def get_image(self, frame_index=0, slice_index=0, channel_index=0):
|
||||
self.hyperstack.setPositionWithoutUpdate(channel_index + 1, slice_index + 1, frame_index + 1)
|
||||
stack_name = ''
|
||||
image_plus = IJ.createHyperStack(stack_name, self.width(), self.height(), 1, 1, 1, PixelType.get_num_bits(self.get_pixel_type()))
|
||||
image_plus.setProcessor(self.hyperstack.getProcessor())
|
||||
ij_image = IJImage(self.image_engine, image_plus)
|
||||
return ij_image
|
||||
|
||||
def width(self):
|
||||
return self.hyperstack.width
|
||||
|
||||
def height(self):
|
||||
return self.hyperstack.height
|
||||
|
||||
def num_slices(self):
|
||||
return self.hyperstack.getNSlices()
|
||||
|
||||
def num_frames(self):
|
||||
return self.hyperstack.getNFrames()
|
||||
|
||||
def num_channels(self):
|
||||
return self.hyperstack.getNChannels()
|
||||
|
||||
def get_pixel_type(self):
|
||||
ij_pixel_type = self.hyperstack.getType()
|
||||
|
||||
return { ImagePlus.GRAY8: PixelType.U8, ImagePlus.GRAY16: PixelType.U16 }[ij_pixel_type]
|
||||
|
||||
|
||||
|
||||
def imagej_run_image_command(image, command, options):
|
||||
"""performs the given imagej command on the given image
|
||||
|
@ -143,7 +167,7 @@ class IJImageEngine(IImageEngine):
|
|||
pass
|
||||
|
||||
def create_hyperstack(self, width, height, num_channels, num_slices, num_frames, pixel_type):
|
||||
return IJHyperStack(width, height, num_channels, num_slices, num_frames, pixel_type)
|
||||
return IJHyperStack(self, width, height, num_channels, num_slices, num_frames, pixel_type)
|
||||
|
||||
def load_image(self, src_image_file_path):
|
||||
image_plus = IJ.openImage(src_image_file_path)
|
||||
|
@ -157,21 +181,27 @@ class IJImageEngine(IImageEngine):
|
|||
result_image = ic.run("Divide create float", numerator_image.ij_image, denominator_image.ij_image)
|
||||
return IJImage(self, result_image)
|
||||
|
||||
def compute_max(self, images_file_path):
|
||||
def compute_max(self, image_feeder):
|
||||
#def compute_max(self, images_file_path):
|
||||
"""Computes for each pixel position the maximum at this position in all input images.
|
||||
|
||||
:param list(str) images_file_path:
|
||||
:param IImageFeeder image_feeder:
|
||||
:rtype IJImage:
|
||||
"""
|
||||
assert len(images_file_path) > 1
|
||||
max_image = IJ.openImage(images_file_path[0])
|
||||
print('max_image', max_image)
|
||||
it = iter(image_feeder)
|
||||
|
||||
for image_file_path in images_file_path[2:-1]:
|
||||
other_image = IJ.openImage(image_file_path)
|
||||
# assert len(images_file_path) > 1
|
||||
max_image = it.next().ij_image
|
||||
|
||||
#max_image = IJ.openImage(images_file_path[0])
|
||||
#print('max_image', max_image)
|
||||
|
||||
# for image_file_path in images_file_path[2:-1]:
|
||||
for other_image in it:
|
||||
# other_image = IJ.openImage(image_file_path)
|
||||
print('other_image', other_image)
|
||||
ic = ImageCalculator()
|
||||
ic.run("max", max_image, other_image)
|
||||
ic.run("max", max_image, other_image.ij_image)
|
||||
print('max_image', max_image)
|
||||
return IJImage(self, max_image)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""preprocessing of synchrotron images based on telemosToolbox."""
|
||||
|
||||
from catalog import ImageCatalog, Sequence
|
||||
from imageengine import IImageEngine, PixelType
|
||||
from imageengine import IImageEngine, PixelType, FileImageFeeder
|
||||
|
||||
class WhiteEstimator(object):
|
||||
|
||||
|
@ -25,8 +25,6 @@ class WhiteEstimator(object):
|
|||
|
||||
: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
|
||||
|
@ -116,16 +114,26 @@ class WhiteEstimator(object):
|
|||
% 27 mai 2019 : offset dark
|
||||
% 4 juin 2019 : replace exist by isfolder or isfile
|
||||
% 14 juin : close figure at the end
|
||||
"""
|
||||
images_file_path = []
|
||||
"""
|
||||
image_set = FileImageFeeder()
|
||||
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 slice_index in range(sequence.num_slices):
|
||||
images_file_path.append(sequence.get_image_file_path(channel_index, frame_index, slice_index))
|
||||
image_set.add_image(sequence.get_image_file_path(channel_index, frame_index, slice_index))
|
||||
|
||||
white_estimate = IImageEngine.get_instance().compute_max(images_file_path)
|
||||
white_estimate = self.estimate_white_from_image_set(image_set, dark)
|
||||
return white_estimate
|
||||
|
||||
def estimate_white_from_image_set(self, image_set, dark=None):
|
||||
"""Estimation of the white fluorescence image shape of synchrotron light from experimental images of Telemos microscope.
|
||||
|
||||
:param IImageFeeder image_set: the set of input images to consider
|
||||
:param WhiteEstimatorSettings white_estimator_settings:
|
||||
|
||||
"""
|
||||
white_estimate = IImageEngine.get_instance().compute_max(image_set)
|
||||
|
||||
# modify spurious pixels on the side of the images
|
||||
try:
|
||||
|
|
Loading…
Reference in New Issue