Now the grayscale morphology in estimate_white is performed in a reasonable time.

The performance improvement is obtained by using opencv's gray morphology operators instad of imagej's
This commit is contained in:
Guillaume Raffy 2019-09-18 10:23:21 +02:00
parent 74d7f9e603
commit 1fd2fc4281
3 changed files with 123 additions and 16 deletions

View File

@ -79,6 +79,22 @@ from org.bytedeco.javacpp.opencv_imgcodecs import imread, imwrite # pylint: dis
# from org.bytedeco.javacpp.opencv_core import CvMat
def print_ijopencvmat(src_mat):
"""Print details about the given opencv Mat object
:param org.bytedeco.javacpp.opencv_core.Mat src_mat:
"""
# Mat members listed in javacpp-presets/opencv/src/gen/java/org/bytedeco/opencv/opencv_core/Mat.java
print("number of rows : %d" % src_mat.rows())
print("number of columns : %d" % src_mat.cols())
print("number of dimensions : %d" % src_mat.dims())
size = src_mat.size()
print("size : %d, %d" % (size.get(0), size.get(1)))
print("number of channels: %d" % src_mat.channels())
print("pixel type : %d" % src_mat.type())
def test_opencv_calc_hist1():
src_image = opencv_core.Mat([128, 128])
histogram = opencv_imgproc.cvCalcHist(src_image) # pylint: disable=unused-variable
@ -199,6 +215,28 @@ def test_ijopencv_converter():
# white_mat = imread(white_image_file_path)
print('mat', mat)
def test_ijopencv_morphology_ex():
print(opencv_core.CV_VERSION())
# src_image = opencv_core.Mat(128, 128)
src_image = opencv_core.Mat().zeros(96, 128, opencv_core.CV_8U).asMat()
print(src_image)
struct_el_size = opencv_core.Size(3, 3)
struct_el_anchor = opencv_core.Point(1, 1)
# print(struct_el_anchor)
struct_element = opencv_imgproc.getStructuringElement(opencv_imgproc.MORPH_RECT, struct_el_size, struct_el_anchor)
print(struct_element)
# dst_image = opencv_core.Mat().zeros(128, 128, opencv_core.CV_8U).asMat()
dst_image = opencv_core.Mat(src_image.size(), src_image.type())
# warning ! trying to guess the arguments from opencv's documentation is time consuming as the error messages are misleading (in the following call, javacpp complains that the 1st argument is not a org.bytedeco.javacpp.opencv_core$Mat, while it is ! The problem comes from the order of the arguments). So, instead of guessing, the found accepted signatures of morphologyEx are in javacpp-presets/opencv/src/gen/java/org/bytedeco/opencv/global/opencv_imgproc.java
# opencv_imgproc.morphologyEx(src_image, opencv_imgproc.MORPH_OPEN, struct_element, dst_image)
# TypeError: morphologyEx(): 1st arg can't be coerced to org.bytedeco.javacpp.opencv_core$GpuMat, org.bytedeco.javacpp.opencv_core$Mat, org.bytedeco.javacpp.opencv_core$UMat
opencv_imgproc.morphologyEx(src_image, dst_image, opencv_imgproc.MORPH_OPEN, struct_element)
print_ijopencvmat(dst_image)
def test_opencv():
@ -206,6 +244,9 @@ def test_opencv():
test_opencv_calc_hist()
test_ijopencv_morphology_ex()
# If a Jython script is run, the variable __name__ contains the string '__main__'.
# If a script is loaded as module, __name__ has a different value.

View File

@ -4,6 +4,12 @@
from imageengine import IImage, IImageEngine
from ij import IJ
from ij.plugin import ImageCalculator
from ijopencv.ij import ImagePlusMatConverter # pylint: disable=import-error
from ijopencv.opencv import MatImagePlusConverter # pylint: disable=import-error
import org.bytedeco.javacpp.opencv_core as opencv_core # pylint: disable=import-error
import org.bytedeco.javacpp.opencv_imgproc as opencv_imgproc # pylint: disable=import-error
# from org.bytedeco.javacpp.opencv_imgcodecs import imread, imwrite # pylint: disable=import-error
class IJImage(IImage):
@ -37,6 +43,79 @@ def imagej_run_image_command(image, command, options):
raise Exception('The command "%s" with options "%s" failed because of the following error : %s' % (command, options, error_message))
def perform_gray_morphology_with_imagej(image, operator, structuring_element_shape, structuring_element_radius):
"""
:param IJImage 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)"
processor = image.ij_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.ij_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.ij_image, "Gray Morphology", "radius=%d type=%s operator=%s" % (structuring_element_radius, structuring_element_shape, operator))
print("after gray morphology")
def perform_gray_morphology_with_ijopencv(image, operator, structuring_element_shape, structuring_element_radius):
"""Perform gray morphology on the given image using imagej's opencv api (this api is provided by javacpp-presets)
:param IJImage image:
:param str operator: eg 'open'
:param str structuring_element_shape: eg 'square'
:param int structuring_element_radius:
"""
shape_name_to_opencv_id = {
'square': opencv_imgproc.MORPH_RECT,
}
operator_name_to_opencv_id = {
'open': opencv_imgproc.MORPH_OPEN,
'close': opencv_imgproc.MORPH_CLOSE,
}
if structuring_element_shape not in shape_name_to_opencv_id.keys():
raise NotImplementedError('structuring element shape %s is not currently supported (supported operators : %s)' % (structuring_element_shape, str(operator_name_to_opencv_id.keys())))
if operator not in operator_name_to_opencv_id.keys():
raise NotImplementedError('operator %s is not currently supported (supported operators : %s)' % (operator, str(operator_name_to_opencv_id.keys())))
imp2mat = ImagePlusMatConverter()
cv_src_image = imp2mat.toMat(image.ij_image.getProcessor())
# cv_src_image = opencv_core.Mat().zeros(128, 128, opencv_core.CV_8U).asMat()
print(cv_src_image)
struct_el_size = structuring_element_radius * 2 + 1
struct_el_size = opencv_core.Size(struct_el_size, struct_el_size)
struct_el_anchor = opencv_core.Point(structuring_element_radius, structuring_element_radius)
# print(struct_el_anchor)
struct_element = opencv_imgproc.getStructuringElement(shape_name_to_opencv_id[structuring_element_shape], struct_el_size, struct_el_anchor)
print(struct_element)
# dst_image = opencv_core.Mat().zeros(128, 128, opencv_core.CV_8U).asMat()
cv_dst_image = opencv_core.Mat(cv_src_image.size(), cv_src_image.type())
# warning ! trying to guess the arguments from opencv's documentation is time consuming as the error messages are misleading (in the following call, javacpp complains that the 1st argument is not a org.bytedeco.javacpp.opencv_core$Mat, while it is ! The problem comes from the order of the arguments). So, instead of guessing, the found accepted signatures of morphologyEx are in javacpp-presets/opencv/src/gen/java/org/bytedeco/opencv/global/opencv_imgproc.java
# opencv_imgproc.morphologyEx(cv_src_image, opencv_imgproc.MORPH_OPEN, struct_element, dst_image)
# TypeError: morphologyEx(): 1st arg can't be coerced to org.bytedeco.javacpp.opencv_core$GpuMat, org.bytedeco.javacpp.opencv_core$Mat, org.bytedeco.javacpp.opencv_core$UMat
print('before opencv_imgproc.morphologyEx')
opencv_imgproc.morphologyEx(cv_src_image, cv_dst_image, operator_name_to_opencv_id[operator], struct_element)
print('after opencv_imgproc.morphologyEx')
mat2imp = MatImagePlusConverter()
image.ij_image.setProcessor(mat2imp.toImageProcessor(cv_dst_image))
class IJImageEngine(IImageEngine):
@ -72,21 +151,8 @@ class IJImageEngine(IImageEngine):
: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)"
processor = image.ij_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.ij_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.ij_image, "Gray Morphology", "radius=%d type=%s operator=%s" % (structuring_element_radius, structuring_element_shape, operator))
print("after gray morphology")
# we use opencv version because imagej's slow version is way too slow for big values of structuring_element_radius
perform_gray_morphology_with_ijopencv(image, operator, structuring_element_shape, structuring_element_radius)
def replace_border(self, image, band_width):

View File

@ -264,7 +264,7 @@ def test_preprocessing(raw_images_root_path):
IImageEngine.set_instance(IJImageEngine())
catalog = ImageCatalog(raw_images_root_path)
sequence = catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos2']
white_estimator = WhiteEstimator(open_size=3, close_size=3, average_size=3)
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())
print(white_estimate)