now Compute_Globules_Area displays the images of detected particles
- this allows the user to check if the image processing settings are correct - fixes #5
This commit is contained in:
parent
71b1ed5b8b
commit
4dba5a99af
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#@output ImagePlus OUTPUT_PLOT
|
#@output ImagePlus OUTPUT_PLOT
|
||||||
"""This script is supposed to be launched from fiji's jython interpreter
|
"""This script is supposed to be launched from fiji's jython interpreter
|
||||||
|
This plugin estimates the global area of globules
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,16 +16,41 @@ print('python version %s' % sys.version) # prints python version
|
||||||
from lipase.settings import UserSettings
|
from lipase.settings import UserSettings
|
||||||
|
|
||||||
# from lipase import Lipase, ImageLogger
|
# from lipase import Lipase, ImageLogger
|
||||||
from lipase.imageengine import IImageEngine, PixelType, StackImageFeeder
|
from lipase.imageengine import IImageEngine, PixelType, StackImageFeeder, IImageProcessingDebugger
|
||||||
from lipase.imagej.ijimageengine import IJImageEngine
|
from lipase.imagej.ijimageengine import IJImageEngine
|
||||||
from lipase.lipase import UserProvidedBackground, GlobulesAreaEstimator
|
from lipase.lipase import UserProvidedBackground, GlobulesAreaEstimator
|
||||||
|
# from lipase.improc.improlis import IMovieProcessListener
|
||||||
# from ij import IJ # pylint: disable=import-error
|
# from ij import IJ # pylint: disable=import-error
|
||||||
# from ij.gui import GenericDialog, DialogListener # pylint: disable=import-error
|
# from ij.gui import GenericDialog, DialogListener # pylint: disable=import-error
|
||||||
# from java.awt.event import ItemListener # pylint: disable=import-error
|
# from java.awt.event import ItemListener # pylint: disable=import-error
|
||||||
import ij.gui
|
import ij.gui
|
||||||
from jarray import zeros, array
|
from jarray import zeros, array
|
||||||
|
|
||||||
|
|
||||||
|
class IsParticleCollector(IImageProcessingDebugger):
|
||||||
|
|
||||||
|
def __init__(self, num_frames):
|
||||||
|
IImageProcessingDebugger.__init__(self)
|
||||||
|
ie = IImageEngine.get_instance()
|
||||||
|
self.is_particle = None
|
||||||
|
self.num_frames = num_frames
|
||||||
|
self.frame_index = 0
|
||||||
|
|
||||||
|
def on_image(self, image, image_id):
|
||||||
|
# print('IsParticleCollector.on_image : image_id = %s' % image_id)
|
||||||
|
if image_id == 'is_particle':
|
||||||
|
ie = IImageEngine.get_instance()
|
||||||
|
if self.is_particle is None:
|
||||||
|
self.is_particle = ie.create_hyperstack(width=image.get_width(), height=image.get_height(), num_channels=1, num_slices=1, num_frames=self.num_frames, pixel_type=PixelType.U8)
|
||||||
|
self.is_particle.set_image(image=image, frame_index=self.frame_index)
|
||||||
|
print("IsParticleCollector.on_image : %f %f" % image.get_value_range())
|
||||||
|
self.is_particle.set_image(image=image, frame_index=self.frame_index)
|
||||||
|
self.frame_index += 1
|
||||||
|
|
||||||
|
def on_hyperstack(self, hyperstack, hyperstack_id):
|
||||||
|
# print('IsParticleCollector.on_hyperstack : hyperstack_id = %s' % hyperstack_id)
|
||||||
|
pass
|
||||||
|
|
||||||
def run_script():
|
def run_script():
|
||||||
global INPUT_STACK # pylint:disable=global-variable-not-assigned
|
global INPUT_STACK # pylint:disable=global-variable-not-assigned
|
||||||
global INPUT_BACKGROUND # pylint:disable=global-variable-not-assigned
|
global INPUT_BACKGROUND # pylint:disable=global-variable-not-assigned
|
||||||
|
@ -41,8 +67,8 @@ def run_script():
|
||||||
|
|
||||||
background_estimator = UserProvidedBackground(background_image=src_background)
|
background_estimator = UserProvidedBackground(background_image=src_background)
|
||||||
processor = GlobulesAreaEstimator(background_estimator=background_estimator, particle_threshold=PARTICLE_THRESHOLD) # pylint: disable=undefined-variable
|
processor = GlobulesAreaEstimator(background_estimator=background_estimator, particle_threshold=PARTICLE_THRESHOLD) # pylint: disable=undefined-variable
|
||||||
|
is_particle_collector = IsParticleCollector(num_frames = src_hyperstack.num_frames())
|
||||||
results = processor.detect_particles(src_hyperstack)
|
results = processor.detect_particles(src_hyperstack, image_proc_debugger=is_particle_collector)
|
||||||
# save_hdf5_file('results.h5', results)
|
# save_hdf5_file('results.h5', results)
|
||||||
# results file could be checked with "h5dump --xml ./lipase.git/results.h5"
|
# results file could be checked with "h5dump --xml ./lipase.git/results.h5"
|
||||||
|
|
||||||
|
@ -50,8 +76,16 @@ def run_script():
|
||||||
x = array(results['frame index'].elements, 'f')
|
x = array(results['frame index'].elements, 'f')
|
||||||
y = array(results['globules_area_ratio'].elements, 'f')
|
y = array(results['globules_area_ratio'].elements, 'f')
|
||||||
|
|
||||||
plot = ij.gui.Plot('my_title', 'frame', 'globules area ratio', x, y)
|
plot = ij.gui.Plot('globules area graph', 'frame', 'globules area ratio', x, y)
|
||||||
plot.show()
|
plot.show()
|
||||||
|
|
||||||
|
print("Compute_Globules_Area is_particle_collector.is_particle size : %d" % (is_particle_collector.is_particle.num_frames()))
|
||||||
|
first_frame = is_particle_collector.is_particle.get_image(frame_index=0, slice_index=0, channel_index=0)
|
||||||
|
print("Compute_Globules_Area is_particle_collector.is_particle size : %f %f" % first_frame.get_value_range())
|
||||||
|
|
||||||
|
is_particle_collector.is_particle.hyperstack.setTitle('is_particle')
|
||||||
|
is_particle_collector.is_particle.hyperstack.show()
|
||||||
|
|
||||||
OUTPUT_PLOT = plot
|
OUTPUT_PLOT = plot
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
from .improlis import MovieProcessDebugger
|
|
|
@ -1,106 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
installation des modules nécéssaires sur macos x :
|
|
||||||
sudo port install opencv +python27
|
|
||||||
sudo port install py-pyqt4
|
|
||||||
sudo port install py-matplotlib
|
|
||||||
|
|
||||||
"""
|
|
||||||
from matplotlib import pyplot
|
|
||||||
from matplotlib.backends.backend_pdf import PdfPages
|
|
||||||
|
|
||||||
def setLatexLookingFonts():
|
|
||||||
import matplotlib
|
|
||||||
matplotlib.rcParams['mathtext.fontset'] = 'stix'
|
|
||||||
matplotlib.rcParams['font.family'] = 'STIXGeneral'
|
|
||||||
#matplotlib.pyplot.title(r'ABC123 vs $\mathrm{ABC123}^{123}$')
|
|
||||||
|
|
||||||
class Signal:
|
|
||||||
def __init__(self, signal, name=None):
|
|
||||||
self.m_signalValues = signal
|
|
||||||
self.m_name = name
|
|
||||||
|
|
||||||
class Point2D(object):
|
|
||||||
def __init__(self, x, y):
|
|
||||||
self.m_x = x
|
|
||||||
self.m_y = y
|
|
||||||
@property
|
|
||||||
def x(self):
|
|
||||||
return self.m_x
|
|
||||||
@property
|
|
||||||
def y(self):
|
|
||||||
return self.m_y
|
|
||||||
|
|
||||||
class ScatterPlot(object):
|
|
||||||
def __init__(self, xAxisDesc = None, yAxisDesc = None):
|
|
||||||
self.m_points = []
|
|
||||||
self.m_xAxisDesc = xAxisDesc
|
|
||||||
self.m_yAxisDesc = yAxisDesc
|
|
||||||
def append(self, point2d ):
|
|
||||||
self.m_points.append(point2d)
|
|
||||||
@property
|
|
||||||
def xAxisDesc(self):
|
|
||||||
return self.m_xAxisDesc
|
|
||||||
@property
|
|
||||||
def yAxisDesc(self):
|
|
||||||
return self.m_yAxisDesc
|
|
||||||
|
|
||||||
def setXAxisDesc(self, description):
|
|
||||||
self.m_xAxisDesc = description
|
|
||||||
def setYAxisDesc(self, description):
|
|
||||||
self.m_yAxisDesc = description
|
|
||||||
def __iter__(self):
|
|
||||||
return iter(self.m_points)
|
|
||||||
|
|
||||||
def saveScatterPlot( scatterPlot, pdfFileName):
|
|
||||||
setLatexLookingFonts()
|
|
||||||
fig = pyplot.figure()
|
|
||||||
pyplot.subplot(1,1,1)
|
|
||||||
x = []
|
|
||||||
y = []
|
|
||||||
for point in scatterPlot:
|
|
||||||
x.append( point.x )
|
|
||||||
y.append( point.y )
|
|
||||||
pyplot.scatter(x, y, marker='x')
|
|
||||||
if scatterPlot.xAxisDesc is not None:
|
|
||||||
pyplot.xlabel(scatterPlot.xAxisDesc)
|
|
||||||
if scatterPlot.yAxisDesc is not None:
|
|
||||||
pyplot.ylabel(scatterPlot.yAxisDesc)
|
|
||||||
|
|
||||||
#print('saving to '+pdfFileName)
|
|
||||||
pp = PdfPages(pdfFileName)
|
|
||||||
pp.savefig( fig )
|
|
||||||
pp.close()
|
|
||||||
pyplot.close(fig)
|
|
||||||
|
|
||||||
|
|
||||||
def saveGraph(signal, pdfFileName):
|
|
||||||
setLatexLookingFonts()
|
|
||||||
fig = pyplot.figure()
|
|
||||||
pyplot.subplot(1,1,1)
|
|
||||||
pyplot.plot(signal, marker='x')
|
|
||||||
|
|
||||||
print('saving to '+pdfFileName)
|
|
||||||
pp = PdfPages(pdfFileName)
|
|
||||||
pp.savefig( fig )
|
|
||||||
pp.close()
|
|
||||||
pyplot.close(fig)
|
|
||||||
|
|
||||||
def saveMultiGraph(signals, pdfFileName):
|
|
||||||
setLatexLookingFonts()
|
|
||||||
fig = pyplot.figure()
|
|
||||||
pyplot.subplot(1,1,1)
|
|
||||||
for signal in signals:
|
|
||||||
print('plotting signal %s' % str(signal.m_signalValues.shape))
|
|
||||||
pyplot.plot(signal.m_signalValues, label=signal.m_name)
|
|
||||||
print('saving to '+pdfFileName)
|
|
||||||
pyplot.legend()
|
|
||||||
pp = PdfPages(pdfFileName)
|
|
||||||
pp.savefig( fig )
|
|
||||||
pp.close()
|
|
||||||
pyplot.close(fig)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,238 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
installation des modules nécéssaires sur macos x :
|
|
||||||
sudo port install opencv +python27
|
|
||||||
sudo port install py-pyqt4
|
|
||||||
sudo port install py-matplotlib
|
|
||||||
|
|
||||||
"""
|
|
||||||
#from PyQt4.QtGui import *
|
|
||||||
#from PyQt4.QtCore import *
|
|
||||||
#import sys
|
|
||||||
|
|
||||||
import cv2
|
|
||||||
#from cv2 import cv
|
|
||||||
import numpy
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
#from matplotlib import pyplot as plt
|
|
||||||
#from matplotlib.backends.backend_pdf import PdfPages
|
|
||||||
|
|
||||||
sys.path.append('../Libraries/python')
|
|
||||||
import scene2d
|
|
||||||
import graphing
|
|
||||||
|
|
||||||
class Line2D(object):
|
|
||||||
def __init__( self, point1, point2 ):
|
|
||||||
self.m_point1 = point1
|
|
||||||
self.m_point2 = point2
|
|
||||||
|
|
||||||
class IImageProcessListener(object):
|
|
||||||
"""
|
|
||||||
an abstract base class that handle events that happen during an image processing. This provides a flexible way to debug image processing
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self.m_imageIndex = 0
|
|
||||||
def onSignal(self, signal, signalName):
|
|
||||||
"""
|
|
||||||
a new signal (1d array) has just been computed
|
|
||||||
"""
|
|
||||||
assert( False )
|
|
||||||
def onImage(self, image, imageName):
|
|
||||||
"""
|
|
||||||
a new image has just been computed
|
|
||||||
"""
|
|
||||||
assert( False )
|
|
||||||
|
|
||||||
class NullImageProcessListener(IImageProcessListener):
|
|
||||||
def __init__(self):
|
|
||||||
IImageProcessListener.__init__( self )
|
|
||||||
def onSignal(self, signal, signalName):
|
|
||||||
pass
|
|
||||||
def onBaseImage(self, image, imageName=''):
|
|
||||||
pass
|
|
||||||
def onImage(self, image, imageName):
|
|
||||||
pass
|
|
||||||
def onPoint(self, point, layerPath, label=None ):
|
|
||||||
pass
|
|
||||||
def onLine(self, line, layerPath, label=None ):
|
|
||||||
pass
|
|
||||||
def onCircle(self, circle, layerPath, label=None ):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class ImageProcessDebugger(IImageProcessListener):
|
|
||||||
def __init__(self, outputFolder='./debug'):
|
|
||||||
IImageProcessListener.__init__( self )
|
|
||||||
self.m_scene = None
|
|
||||||
self.m_baseImageName = None
|
|
||||||
self.setOutputFolder(outputFolder)
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
#assert( self.m_scene is not None )
|
|
||||||
if self.m_scene:
|
|
||||||
self.m_scene.saveAsSvg('%s/%s.svg' % (self.m_outputFolder, self.m_baseImageName))
|
|
||||||
self.m_scene = None
|
|
||||||
def setOutputFolder(self, outputFolderPath):
|
|
||||||
if self.m_scene:
|
|
||||||
self.m_scene.saveAsSvg('%s/%s.svg' % (self.m_outputFolder, self.m_baseImageName))
|
|
||||||
self.m_scene = None
|
|
||||||
self.m_outputFolder = outputFolderPath
|
|
||||||
pathParts = self.m_outputFolder.split('/')
|
|
||||||
path = ''
|
|
||||||
for i in range(len(pathParts)):
|
|
||||||
if i != 0:
|
|
||||||
path += '/'
|
|
||||||
path += pathParts[i]
|
|
||||||
try:
|
|
||||||
os.mkdir(path)
|
|
||||||
except (OSError): # this exception is raised if the folder already exists
|
|
||||||
pass
|
|
||||||
def onSignal(self, signal, signalName):
|
|
||||||
graphing.saveGraph(signal, '%s/%s.pdf' % (self.m_outputFolder, signalName))
|
|
||||||
def onSignals(self, signals, signalName):
|
|
||||||
graphing.saveMultiGraph(signals, '%s/%s.pdf' % (self.m_outputFolder, signalName))
|
|
||||||
def onImage(self, image, imageName):
|
|
||||||
#plt.subplot(1,1,1),plt.imshow(contourImage,cmap = 'gray')
|
|
||||||
#plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
|
|
||||||
#plt.show()
|
|
||||||
filePath = '%s/%s.tif' % (self.m_outputFolder, imageName)
|
|
||||||
saveImage( image, filePath )
|
|
||||||
def onBaseImage(self, image, imageName=''):
|
|
||||||
assert(imageName != '')
|
|
||||||
self.m_baseImageName=imageName
|
|
||||||
filePath = '%s/%s.png' % (self.m_outputFolder, imageName)
|
|
||||||
saveImage( image, filePath )
|
|
||||||
self.m_scene = scene2d.Scene()
|
|
||||||
assert( self.m_scene is not None )
|
|
||||||
if self.m_scene:
|
|
||||||
self.m_scene.setBaseImage(scene2d.Image(filePath))
|
|
||||||
def onPoint(self, point, layerPath, label=None ):
|
|
||||||
assert( self.m_scene )
|
|
||||||
self.m_scene.getLayer(layerPath).addChild(scene2d.Point(point, label))
|
|
||||||
def onLine(self, line, layerPath, label=None ):
|
|
||||||
assert( self.m_scene )
|
|
||||||
self.m_scene.getLayer(layerPath).addChild(scene2d.Line(line, label))
|
|
||||||
def onCircle(self, circle, layerPath, label=None ):
|
|
||||||
assert( self.m_scene )
|
|
||||||
self.m_scene.getLayer(layerPath).addChild(scene2d.Circle(circle, label))
|
|
||||||
|
|
||||||
|
|
||||||
class IMovieProcessListener(object):
|
|
||||||
"""
|
|
||||||
an abstract base class that handle events that happen durin a movie image processing. This provides a flexible way to debug imageprocessing
|
|
||||||
"""
|
|
||||||
def __init__(self, imageProcessListener ):
|
|
||||||
self.m_imageIndex = 0
|
|
||||||
self.m_imageProcessListener = imageProcessListener
|
|
||||||
def onImageProcessingStart(self):
|
|
||||||
"""
|
|
||||||
the processing of a new image starts
|
|
||||||
"""
|
|
||||||
self.m_imageIndex += 1
|
|
||||||
def onImageProcessingEnd(self):
|
|
||||||
"""
|
|
||||||
the processing of a new image ends
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
def onSignal(self, signal, signalName):
|
|
||||||
"""
|
|
||||||
a new signal (1d array) has just been computed
|
|
||||||
"""
|
|
||||||
self.m_imageProcessListener.onSignal( signal, signalName )
|
|
||||||
def onImage(self, image, imageName):
|
|
||||||
"""
|
|
||||||
a new image has just been computed
|
|
||||||
"""
|
|
||||||
self.m_imageProcessListener.onImage( image, imageName )
|
|
||||||
|
|
||||||
class NullMovieProcessListener(IMovieProcessListener):
|
|
||||||
def __init__(self):
|
|
||||||
IMovieProcessListener.__init__( self, NullImageProcessListener() )
|
|
||||||
def onSignal(self, signal, signalName):
|
|
||||||
pass
|
|
||||||
def onImage(self, image, imageName):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def saveImage(image, filePath):
|
|
||||||
print('%s original image type : %s range=(%f:%f)' % (filePath, str(image.dtype), image.min(), image.max()))
|
|
||||||
if image.dtype == numpy.bool:
|
|
||||||
cv2.imwrite(filePath, image.astype(numpy.uint8)*255)
|
|
||||||
elif image.dtype == numpy.uint16:
|
|
||||||
fileExt = filePath.split('.')[-1]
|
|
||||||
if fileExt == 'tif':
|
|
||||||
# tif file format supports 16 bits per pixel
|
|
||||||
cv2.imwrite(filePath, image)
|
|
||||||
else:
|
|
||||||
u8Image = cv2.normalize(image, alpha=0.0, beta=255.0, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
|
|
||||||
cv2.imwrite(filePath, u8Image)
|
|
||||||
elif image.dtype == numpy.float32 or image.dtype == numpy.float64:
|
|
||||||
print('image range : %d-%d' % (image.min(), image.max()))
|
|
||||||
u8Image = cv2.normalize(image, numpy.array(image.shape, dtype=numpy.uint8), alpha=0.0, beta=255.0, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
|
|
||||||
print('u8Image range : %d-%d' % (u8Image.min(), u8Image.max()))
|
|
||||||
cv2.imwrite(filePath, u8Image)
|
|
||||||
elif image.dtype == numpy.int32:
|
|
||||||
print('image range : %d-%d' % (image.min(), image.max()))
|
|
||||||
u8Image = cv2.normalize(image, numpy.array(image.shape, dtype=numpy.uint8), alpha=0.0, beta=255.0, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
|
|
||||||
print('u8Image range : %d-%d' % (u8Image.min(), u8Image.max()))
|
|
||||||
cv2.imwrite(filePath, u8Image)
|
|
||||||
else:
|
|
||||||
#assert( False )
|
|
||||||
cv2.imwrite(filePath, image)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MovieProcessDebugger(IMovieProcessListener):
|
|
||||||
def __init__(self):
|
|
||||||
IMovieProcessListener.__init__( self, ImageProcessDebugger() )
|
|
||||||
self.m_outputFolder='./debug'
|
|
||||||
self.m_scene = None
|
|
||||||
try:
|
|
||||||
os.mkdir(self.m_outputFolder)
|
|
||||||
except (OSError): # this exception is raised if the folder already exists
|
|
||||||
pass
|
|
||||||
def onImageProcessingStart(self):
|
|
||||||
"""
|
|
||||||
the processing of a new image starts
|
|
||||||
"""
|
|
||||||
IMovieProcessListener.onImageProcessingStart(self)
|
|
||||||
self.m_imageProcessListener.setOutputFolder( '%s/image%d' % (self.m_outputFolder, self.m_imageIndex) )
|
|
||||||
|
|
||||||
def onImageProcessingEnd(self):
|
|
||||||
IMovieProcessListener.onImageProcessingEnd(self)
|
|
||||||
self.m_imageProcessListener.setOutputFolder( None )
|
|
||||||
def onSignal(self, signal, signalName):
|
|
||||||
self.m_imageProcessListener.onSignal( signal, signalName )
|
|
||||||
def onSignals(self, signals, signalName):
|
|
||||||
self.m_imageProcessListener.onSignal( signals, signalName )
|
|
||||||
def onImage(self, image, imageName):
|
|
||||||
self.m_imageProcessListener.onImage( image, imageName )
|
|
||||||
def onBaseImage(self, image, imageName):
|
|
||||||
self.m_imageProcessListener.onBaseImage( image, imageName )
|
|
||||||
def onPoint(self, point, layerPath, label=None ):
|
|
||||||
self.m_imageProcessListener.onPoint( image, point, layerPath, label )
|
|
||||||
def onCircle(self, circle, layerPath, label=None ):
|
|
||||||
self.m_imageProcessListener.onPoint( image, circle, layerPath, label )
|
|
||||||
|
|
||||||
|
|
||||||
class IImageProcessor(object):
|
|
||||||
|
|
||||||
def __init__(self, movieProcessListener = NullMovieProcessListener()):
|
|
||||||
self.m_movieProcessListener = movieProcessListener
|
|
||||||
|
|
||||||
def processImage(self, image):
|
|
||||||
assert( False ) # this method is not supposed to be called
|
|
||||||
|
|
||||||
def get_image_process_listener(self):
|
|
||||||
return self.m_movieProcessListener
|
|
||||||
|
|
||||||
|
|
||||||
def findEdges(image):
|
|
||||||
sx = cv2.Sobel(image, cv2.CV_32F, dx=1, dy=0, ksize=3)
|
|
||||||
sy = cv2.Sobel(image, cv2.CV_32F, dx=0, dy=1, ksize=3)
|
|
||||||
return numpy.sqrt(sx*sx + sy*sy)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import cv2
|
|
||||||
|
|
||||||
class ISceneNodeVisitor(object):
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def visitPoint(self, point):
|
|
||||||
assert( False )
|
|
||||||
|
|
||||||
def visitImage(self, image):
|
|
||||||
assert( False )
|
|
||||||
|
|
||||||
def visitLayer(self, layer):
|
|
||||||
assert( False )
|
|
||||||
|
|
||||||
def visitScene(self, scene):
|
|
||||||
assert( False )
|
|
||||||
|
|
||||||
def visitLine(self, line):
|
|
||||||
assert( False )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ISceneNode(object):
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def onVisit(self, visitor ):
|
|
||||||
assert( False )
|
|
||||||
|
|
||||||
class Point(ISceneNode):
|
|
||||||
def __init__(self, coords, label = None):
|
|
||||||
self.m_coords = coords
|
|
||||||
self.m_label = label
|
|
||||||
|
|
||||||
def onVisit( self, visitor ):
|
|
||||||
visitor.visitPoint( self )
|
|
||||||
|
|
||||||
class Line(ISceneNode):
|
|
||||||
def __init__(self, line, label = None):
|
|
||||||
self.m_from = line[0]
|
|
||||||
self.m_to = line[1]
|
|
||||||
self.m_label = label
|
|
||||||
|
|
||||||
def onVisit( self, visitor ):
|
|
||||||
visitor.visitLine( self )
|
|
||||||
|
|
||||||
class Circle(ISceneNode):
|
|
||||||
def __init__(self, circle, label = None):
|
|
||||||
self.m_center = (circle[0], circle[1])
|
|
||||||
self.m_radius = circle[2]
|
|
||||||
self.m_label = label
|
|
||||||
|
|
||||||
def onVisit( self, visitor ):
|
|
||||||
visitor.visitCircle( self )
|
|
||||||
|
|
||||||
class Image(ISceneNode):
|
|
||||||
def __init__(self, imageFilePath):
|
|
||||||
self.m_imageFilePath = imageFilePath
|
|
||||||
|
|
||||||
def onVisit(self, visitor ):
|
|
||||||
visitor.visitImage( self )
|
|
||||||
|
|
||||||
def getFilePath(self):
|
|
||||||
return self.m_imageFilePath
|
|
||||||
|
|
||||||
def getSize(self):
|
|
||||||
cv_img = cv2.imread(self.m_imageFilePath, cv2.IMREAD_ANYDEPTH)
|
|
||||||
return cv_img.shape
|
|
||||||
|
|
||||||
class Layer(ISceneNode):
|
|
||||||
def __init__(self, layerName):
|
|
||||||
self.m_name = layerName
|
|
||||||
self.m_children = []
|
|
||||||
self.m_layers = {}
|
|
||||||
|
|
||||||
def getName(self):
|
|
||||||
return self.m_name
|
|
||||||
|
|
||||||
def addChild(self, childNode):
|
|
||||||
self.m_children.append( childNode )
|
|
||||||
|
|
||||||
def onVisit(self, visitor ):
|
|
||||||
visitor.visitLayer( self )
|
|
||||||
|
|
||||||
def addLayer(self, layer):
|
|
||||||
print('adding layer %s' % layer.getName())
|
|
||||||
self.m_layers[ layer.getName() ] = layer
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Scene(ISceneNode):
|
|
||||||
def __init__(self):
|
|
||||||
self.m_image = None
|
|
||||||
self.m_rootLayer = Layer('root')
|
|
||||||
|
|
||||||
def onVisit(self, visitor ):
|
|
||||||
visitor.visitScene( self )
|
|
||||||
|
|
||||||
def setBaseImage( self, image ):
|
|
||||||
self.m_image = image
|
|
||||||
|
|
||||||
def getLayer(self, layerPath):
|
|
||||||
pathParts = layerPath.split('/')
|
|
||||||
parentLayer = self.m_rootLayer
|
|
||||||
for layerName in pathParts:
|
|
||||||
if layerName not in parentLayer.m_layers:
|
|
||||||
parentLayer.addLayer( Layer(layerName) )
|
|
||||||
parentLayer = parentLayer.m_layers[layerName]
|
|
||||||
return parentLayer
|
|
||||||
|
|
||||||
def saveAsSvg(self, filePath):
|
|
||||||
visitor = SvgExporter( filePath )
|
|
||||||
self.onVisit(visitor)
|
|
||||||
|
|
||||||
class SvgExporter(ISceneNodeVisitor):
|
|
||||||
def __init__(self, svgFilePath):
|
|
||||||
self.m_svgFilePath = svgFilePath
|
|
||||||
|
|
||||||
def visitPoint(self, point):
|
|
||||||
radius = 1.0
|
|
||||||
self.m_f.write('<circle cx="%.3f" cy="%.3f" r="%.3f"/>\n' % (point.m_coords[0], point.m_coords[1], radius) )
|
|
||||||
if point.m_label is not None :
|
|
||||||
self.m_f.write('<text x="%.3f" y="%.3f">%s</text>\n' % (point.m_coords[0], point.m_coords[1], point.m_label) )
|
|
||||||
|
|
||||||
def visitLine(self, line):
|
|
||||||
radius = 1.0
|
|
||||||
self.m_f.write('<line x1="%.3f" x2="%.3f" y1="%.3f" y2="%.3f"/>\n' % (line.m_from[0], line.m_to[0], line.m_from[1], line.m_to[1]) )
|
|
||||||
if line.m_label is not None :
|
|
||||||
self.m_f.write('<text x="%.3f" y="%.3f">%s</text>\n' % (line.m_from[0], line.m_from[1], point.m_label) )
|
|
||||||
|
|
||||||
def visitCircle(self, circle):
|
|
||||||
radius = 1.0
|
|
||||||
self.m_f.write('<circle cx="%.3f" cy="%.3f" r="%.3f"/>\n' % (circle.m_center[0], circle.m_center[1], circle.m_radius) )
|
|
||||||
if circle.m_label is not None :
|
|
||||||
self.m_f.write('<text x="%.3f" y="%.3f">%s</text>\n' % (circle.m_center[0], circle.m_center[1], point.m_label) )
|
|
||||||
|
|
||||||
def visitImage(self, image):
|
|
||||||
imageSize = image.getSize()
|
|
||||||
self.m_f.write('<image xlink:href="%s" x="0" y="0" width="%d" height="%d"/>\n' % (image.getFilePath().split('/')[-1], imageSize[1], imageSize[0]) )
|
|
||||||
|
|
||||||
def visitLayer(self, layer):
|
|
||||||
self.m_f.write('<g id="%s" style="fill:red;stroke:cyan">\n' % layer.getName())
|
|
||||||
for child in layer.m_children:
|
|
||||||
child.onVisit( self )
|
|
||||||
for layer in layer.m_layers.itervalues():
|
|
||||||
layer.onVisit( self )
|
|
||||||
self.m_f.write('</g>\n')
|
|
||||||
|
|
||||||
def visitScene(self, scene):
|
|
||||||
with open(self.m_svgFilePath, 'wt') as self.m_f:
|
|
||||||
print('exporting scene2d as %s' % self.m_svgFilePath)
|
|
||||||
self.m_f.write('<?xml version="1.0"?>')
|
|
||||||
self.m_f.write('<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="3008" height="2280" onload="init()">')
|
|
||||||
self.m_f.write('<defs>')
|
|
||||||
self.m_f.write('<script type="text/ecmascript" xlink:href="MeniscusUI.js"/>')
|
|
||||||
self.m_f.write('</defs>')
|
|
||||||
if scene.m_image is not None:
|
|
||||||
scene.m_image.onVisit(self)
|
|
||||||
|
|
||||||
scene.m_rootLayer.onVisit(self)
|
|
||||||
#f.write('<image xlink:href="FullImage0235.png" x="0" y="0" width="3008" height="2280"/>')
|
|
||||||
self.m_f.write('</svg>')
|
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,6 @@ class EmptyFrameBackgroundEstimator(IBackgroundEstimator):
|
||||||
background_estimate = visible_traps_sequence.get_image(frame_index=self.empty_frame_index).clone()
|
background_estimate = visible_traps_sequence.get_image(frame_index=self.empty_frame_index).clone()
|
||||||
return background_estimate
|
return background_estimate
|
||||||
|
|
||||||
|
|
||||||
class GlobulesAreaEstimator(object):
|
class GlobulesAreaEstimator(object):
|
||||||
""" An image processing suite targetted to visible images of traps with moving particles (globules)
|
""" An image processing suite targetted to visible images of traps with moving particles (globules)
|
||||||
"""
|
"""
|
||||||
|
@ -186,7 +185,7 @@ class GlobulesAreaEstimator(object):
|
||||||
self.background_estimator = background_estimator
|
self.background_estimator = background_estimator
|
||||||
self.particle_threshold = particle_threshold
|
self.particle_threshold = particle_threshold
|
||||||
|
|
||||||
def detect_particles(self, visible_traps_sequence):
|
def detect_particles(self, visible_traps_sequence, image_proc_debugger=NullDebugger()):
|
||||||
"""
|
"""
|
||||||
:param IHyperStack visible_traps_sequence:
|
:param IHyperStack visible_traps_sequence:
|
||||||
:rtype: hdf5_data.Group
|
:rtype: hdf5_data.Group
|
||||||
|
@ -206,6 +205,7 @@ class GlobulesAreaEstimator(object):
|
||||||
particle_image = ie.subtract(visible_traps_sequence.get_image(frame_index=frame_index), background_image)
|
particle_image = ie.subtract(visible_traps_sequence.get_image(frame_index=frame_index), background_image)
|
||||||
abs_particle_image = ie.abs( particle_image )
|
abs_particle_image = ie.abs( particle_image )
|
||||||
is_particle = ie.threshold(abs_particle_image, self.particle_threshold)
|
is_particle = ie.threshold(abs_particle_image, self.particle_threshold)
|
||||||
|
image_proc_debugger.on_image(is_particle, 'is_particle')
|
||||||
measured_mean_value = is_particle.get_mean_value()
|
measured_mean_value = is_particle.get_mean_value()
|
||||||
particle_pixel_value = 255.0
|
particle_pixel_value = 255.0
|
||||||
num_pixels = is_particle.get_width() * is_particle.get_height()
|
num_pixels = is_particle.get_width() * is_particle.get_height()
|
||||||
|
|
Loading…
Reference in New Issue