now there is an image processing to compute the radial profile (needed for graffy/lipase#3).
This commit is contained in:
		
							parent
							
								
									e8b1e331fe
								
							
						
					
					
						commit
						4daf2bfe91
					
				|  | @ -0,0 +1,123 @@ | |||
| """ | ||||
|     an image processing technique to produce a 1D signal for each pixel : this 1D signal is obtained by projecting the neighborhood of this pixel on a set of bases (each base is used as a convilution kernel) | ||||
|     https://subversion.ipr.univ-rennes1.fr/repos/main/projects/antipode/src/python/antipode/texori.py | ||||
| """ | ||||
| from imageengine import IImageEngine, PixelType | ||||
| 
 | ||||
| class IProjectorBase(object): | ||||
|     """ | ||||
|         a set of projectors | ||||
| 
 | ||||
|         a projector is a grey level image, in which each pixel value is acting as a weight | ||||
|     """ | ||||
|     def __init__(self): | ||||
|         pass | ||||
| 
 | ||||
|     def get_num_projectors(self): | ||||
|         pass | ||||
|          | ||||
|     def get_projector_kernel(self, projector_index): | ||||
| 
 | ||||
|         pass | ||||
| 
 | ||||
| def create_circle_image(image_size, circle_radius, circle_pos, circle_thickness, background_value=0.0, circle_value=1.0): | ||||
|     """ | ||||
|     :param dict image_size: | ||||
|     """ | ||||
|     ie = IImageEngine.get_instance() | ||||
|     width = image_size['width'] | ||||
|     height = image_size['height'] | ||||
|     assert isinstance(width, int) | ||||
|     assert isinstance(height, int) | ||||
|     circle_pos_x = float(circle_pos['x']) | ||||
|     circle_pos_y = float(circle_pos['y']) | ||||
|     r_min = max(0.0, circle_radius - circle_thickness * 0.5) | ||||
|     r_max = circle_radius + circle_thickness * 0.5 | ||||
|     r_min_square = r_min * r_min | ||||
|     r_max_square = r_max * r_max | ||||
|     image = ie.create_image(width=width, height=height, pixel_type=PixelType.F32) | ||||
|     for y in range(height): | ||||
|         for x in range(width): | ||||
|             dx = x - circle_pos_x | ||||
|             dy = y - circle_pos_y | ||||
|             r_square = (dx * dx + dy * dy) | ||||
|             if r_min_square < r_square < r_max_square: | ||||
|                 pixel_value = circle_value | ||||
|             else: | ||||
|                 pixel_value = background_value | ||||
|             image.set_pixel(x, y, pixel_value) | ||||
|     return image | ||||
| 
 | ||||
| class CircularSymmetryProjectorBase(IProjectorBase): | ||||
|     """ | ||||
|         generates a base of circles  | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, max_radius, oversampling_scale=2): | ||||
|         """ | ||||
|         :param int max_radius: the biggest circle radius in the set of projectors | ||||
|         :param int oversampling_scale: oversampling is used to generate antialased circles. The higher this value, the better the quality of antialiasing is | ||||
|         """ | ||||
|         super(CircularSymmetryProjectorBase, self).__init__() | ||||
|         assert max_radius > 0 | ||||
|         assert oversampling_scale > 0 | ||||
|         self.max_radius = max_radius | ||||
|         self.oversampling_scale = oversampling_scale | ||||
|         self.num_projectors = int(max_radius) + 1 | ||||
| 
 | ||||
|     def get_num_projectors(self): | ||||
|         return self.num_projectors | ||||
|          | ||||
|     def get_projector_kernel(self, projector_index): | ||||
|         assert projector_index < self.get_num_projectors() | ||||
|         oversampling_is_handled = False  # TODO: handle oversampling to increase quality | ||||
|         if not oversampling_is_handled and self.oversampling_scale != 1  : | ||||
|             raise NotImplementedError("at the moment, oversampling is not yet implemented")   | ||||
|         radius = projector_index | ||||
|         image_size = int(self.max_radius) * 2 + 1 | ||||
|         circle_pos = {'x': self.max_radius, 'y': self.max_radius} | ||||
|         oversampled_circle = create_circle_image( | ||||
|             image_size={'width': image_size * self.oversampling_scale, 'height': image_size*self.oversampling_scale}, | ||||
|             circle_radius=radius * self.oversampling_scale, | ||||
|             circle_pos={'x': self.max_radius* self.oversampling_scale, 'y': self.max_radius* self.oversampling_scale}, | ||||
|             circle_thickness=1 * self.oversampling_scale) | ||||
|         if self.oversampling_scale == 1: | ||||
|             circle_image = oversampled_circle | ||||
|         else: | ||||
|             if oversampling_is_handled: | ||||
|                 circle_image = oversampled_circle.resample(width=image_size, height=image_size) | ||||
|         # mean_value = circle_image.get_mean_value() | ||||
|         # num_pixels = image_size * image_size | ||||
|         # sum_of_pixel_values = mean_value * num_pixels | ||||
|         # we want each circle to have a total weight of 1.0, regardless their radius | ||||
|         # circle_image.scale_values(1.0/sum_of_pixel_values) | ||||
|          | ||||
|         anchor_point = {'x': int(circle_pos['x']), 'y': int(circle_pos['y'])} | ||||
|         return circle_image, anchor_point | ||||
| 
 | ||||
| 
 | ||||
| class CircularSymmetryDetector: | ||||
|     def __init__(self, max_radius): | ||||
|         """ | ||||
|         :para float max_radius: | ||||
|         """ | ||||
|         self.max_radius = max_radius | ||||
| 
 | ||||
|     def compute_radial_profiles(self, src_image): | ||||
|         """ Computes for each pixel the radial profile (with this pixel as center) | ||||
| 
 | ||||
|         :param IImage src_image: | ||||
|         :rtype IHyperstack: each radial profile is stored in the channel coordinate of the hyperstack | ||||
|         """ | ||||
|         ie = IImageEngine.get_instance() | ||||
|         ie.debugger.on_image(src_image, 'src_image') | ||||
|         projector_base = CircularSymmetryProjectorBase(self.max_radius, oversampling_scale=1) | ||||
|         radial_profile_image = ie.create_hyperstack(width=src_image.get_width(), height=src_image.get_height(), num_channels=projector_base.get_num_projectors(), num_slices=1, num_frames=1, pixel_type=PixelType.F32) | ||||
|         for projector_index in range(projector_base.get_num_projectors()): | ||||
|             projector, center_of_filter = projector_base.get_projector_kernel(projector_index) | ||||
|             ie.debugger.on_image(projector, 'projector_%d' % (projector_index)) | ||||
|             print(type(center_of_filter)) | ||||
|             projection = ie.filter2D(src_image, dst_type=PixelType.F32, kernel=projector, anchor=(center_of_filter['x'], center_of_filter['y'])) | ||||
|             ie.debugger.on_image(projection, 'projection_%d' % (projector_index)) | ||||
|             radial_profile_image.set_image(self, projection, frame_index=0, slice_index=0, channel_index=projector_index) | ||||
|         return radial_profile_image | ||||
|  | @ -97,6 +97,14 @@ class IImage(ABC): | |||
|         """ | ||||
|         pass | ||||
| 
 | ||||
|     @abc.abstractmethod | ||||
|     def scale_values(self, src_image, scale): | ||||
|         """ | ||||
|         multiply the value of each pixel by a the given scalar | ||||
| 
 | ||||
|         :param float scale: | ||||
|         """ | ||||
| 
 | ||||
| class IHyperStack(ABC): | ||||
| 
 | ||||
|     @abc.abstractmethod | ||||
|  | @ -426,6 +434,17 @@ class IImageEngine(ABC): | |||
|         :param int radius: in pixels | ||||
|         """ | ||||
| 
 | ||||
|     @abc.abstractmethod | ||||
|     def filter2D(self, src_image, dst_type, kernel, anchor=(-1, -1)): | ||||
|         """ as cv2.filter2D | ||||
| 
 | ||||
|         :param IImage src_image: | ||||
|         :param PixelType or None dst_type: pixel type of the destination image (if None, the pixel type is the same as the source image type) | ||||
|         :param IImage kernel: convolution kernel (or rather a correlation kernel), a single-channel floating point matrix; if you want to apply different kernels to different channels, split the image into separate color planes using split() and process them individually. | ||||
|         :param tuple(int, int) angor: anchor of the kernel that indicates the relative position of a filtered point within the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor is at the kernel center.  | ||||
|         :rtype IImage: | ||||
|         """ | ||||
| 
 | ||||
|     @abc.abstractmethod | ||||
|     def perform_gray_morphology(self, image, operator, structuring_element_shape, structuring_element_radius): | ||||
|         """ | ||||
|  | @ -515,3 +534,4 @@ class IImageEngine(ABC): | |||
|         :param IImage src_binary_image: | ||||
|         :rtype IImage: binary image | ||||
|         """ | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,6 +24,12 @@ IJ_PIXELTYPE_TO_PIXEL_TYPE = { | |||
|     ImagePlus.GRAY32: PixelType.F32 | ||||
|     } | ||||
| 
 | ||||
| PIXEL_TYPE_TO_CV_PIXEL_TYPE = { | ||||
|     PixelType.U8: opencv_core.CV_8U, | ||||
|     PixelType.U16: opencv_core.CV_16U, | ||||
|     PixelType.F32: opencv_core.CV_32F, | ||||
| } | ||||
| 
 | ||||
| class IJImage(IImage): | ||||
| 
 | ||||
|     def __init__(self, image_engine, ij_image=None, width=None, height=None, pixel_type=None): | ||||
|  | @ -101,6 +107,10 @@ class IJImage(IImage): | |||
|         image_stats = processor.getStats()  # :type ImageStatistics image_stats: | ||||
|         return image_stats.mean | ||||
| 
 | ||||
|     def scale_values(self, scale): | ||||
|         raise NotImplementedError() | ||||
| 
 | ||||
| 
 | ||||
| class IJHyperStack(IHyperStack): | ||||
| 
 | ||||
|     def __init__(self, image_engine, width, height, num_channels, num_slices, num_frames, pixel_type): | ||||
|  | @ -231,6 +241,7 @@ def perform_gray_morphology_with_ijopencv(image, operator, structuring_element_s | |||
|     mat2imp = MatImagePlusConverter() | ||||
|     image.ij_image.setProcessor(mat2imp.toImageProcessor(cv_dst_image)) | ||||
| 
 | ||||
| 
 | ||||
| class ImageLogger(IImageProcessingDebugger): | ||||
| 
 | ||||
|     def __init__(self): | ||||
|  | @ -327,6 +338,39 @@ class IJImageEngine(IImageEngine): | |||
|         """Implement interface method.""" | ||||
|         IJ.run(image.ij_image, "Mean...", "radius=%d" % radius) | ||||
| 
 | ||||
|     def filter2D(self, src_image, dst_type, kernel, anchor=(-1, -1)): | ||||
|         print(type(anchor), anchor) | ||||
|         if anchor == (-1, -1): | ||||
|             assert kernel.get_width() % 2 == 1 and kernel.get_height() % 2 == 1, "kernel sizes are expected to be odd if you want the anchor to be at the center of the kernel" | ||||
| 
 | ||||
|             anchor = ((kernel.get_width() - 1) / 2, (kernel.get_height() - 1) / 2) | ||||
| 
 | ||||
|         imp2mat = ImagePlusMatConverter() | ||||
|         cv_src_image = imp2mat.toMat(src_image.ij_image.getProcessor()) | ||||
|         cv_kernel = imp2mat.toMat(kernel.ij_image.getProcessor()) | ||||
| 
 | ||||
|         cv_anchor = opencv_core.Point(anchor[0], anchor[1]) | ||||
|         ie = IImageEngine.get_instance() | ||||
|         dst_image = ie.create_image(width=src_image.get_width(), height=src_image.get_height(), pixel_type=PixelType.F32) | ||||
|         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 filter2D are in https://github.com/bytedeco/javacpp-presets/blob/master/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.filter2D') | ||||
|         delta = 0 | ||||
|         border_type = opencv_core.BORDER_DEFAULT | ||||
|         if dst_type is None: | ||||
|             ddepth = -1 | ||||
|         else: | ||||
|             ddepth = PIXEL_TYPE_TO_CV_PIXEL_TYPE[dst_type] | ||||
|         opencv_imgproc.filter2D(cv_src_image, cv_dst_image, ddepth, cv_kernel, cv_anchor, delta, border_type) | ||||
|         print('after opencv_imgproc.filter2D') | ||||
| 
 | ||||
|         mat2imp = MatImagePlusConverter() | ||||
|         dst_image.ij_image.setProcessor(mat2imp.toImageProcessor(cv_dst_image)) | ||||
|         return dst_image | ||||
| 
 | ||||
|     def perform_gray_morphology(self, image, operator, structuring_element_shape, structuring_element_radius): | ||||
|         """ | ||||
|         :param IJImage image: | ||||
|  |  | |||
|  | @ -1,143 +0,0 @@ | |||
| """ | ||||
|     an image processing technique to produce a 1D signal for each pixel : this 1D signal is obtained by projecting the neighborhood of this pixel on a set of bases (each base is used as a convilution kernel) | ||||
|     https://subversion.ipr.univ-rennes1.fr/repos/main/projects/antipode/src/python/antipode/texori.py | ||||
| """ | ||||
| from imageengine import IImageEngine, PixelType | ||||
| 
 | ||||
| class IProjectorBase(object): | ||||
|     """ | ||||
|         a set of projectors | ||||
| 
 | ||||
|         a projector is a grey level image, in which each pixel value is acting as a weight | ||||
|     """ | ||||
|     def __init__(self): | ||||
|         pass | ||||
| 
 | ||||
|     def get_num_projectors(self): | ||||
|         pass | ||||
|          | ||||
|     def get_projector_kernel(self, projector_index): | ||||
| 
 | ||||
|         pass | ||||
| 
 | ||||
| def create_circle_image(image_size, circle_radius, circle_pos, circle_thickness, background_value=0.0, circle_value=1.0): | ||||
|     """ | ||||
|     :param dict image_size: | ||||
|     """ | ||||
|     ie = IImageEngine.get_instance() | ||||
|     width = image_size['width'] | ||||
|     height = image_size['height'] | ||||
|     circle_pos_x = float(circle_pos['x']) | ||||
|     circle_pos_y = float(circle_pos['y']) | ||||
|     r_min = circle_radius - circle_thickness * 0.5 | ||||
|     assert r_min >= 0.0 | ||||
|     r_max = circle_radius + circle_thickness * 0.5 | ||||
|     r_min_square = r_min * r_min | ||||
|     r_max_square = r_max * r_max | ||||
|     image = ie.create_image(width=width, height=height, pixel_type=PixelType.F32) | ||||
|     for y in range(height): | ||||
|         for x in range(width): | ||||
|             dx = x - circle_pos_x | ||||
|             dy = y - circle_pos_y | ||||
|             r_square = (dx * dx + dy * dy) | ||||
|             if r_min_square < r_square < r_max_square: | ||||
|                 pixel_value = circle_value | ||||
|             else: | ||||
|                 pixel_value = background_value | ||||
|             image.set_pixel(x, y, pixel_value) | ||||
|     return image | ||||
| 
 | ||||
| class CircularSymetryProjectorBase(IProjectorBase): | ||||
|     """ | ||||
|         generates a base of circles  | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, max_radius, oversampling_scale=2): | ||||
|         """ | ||||
|         :param int max_radius: the biggest circle radius in the set of projectors | ||||
|         :param int oversampling_scale: oversampling is used to generate antialased circles. The higher this value, the better the quality of antialiasing is | ||||
|         """ | ||||
|         super().__init__() | ||||
|         assert max_radius > 0 | ||||
|         assert oversampling_scale > 0 | ||||
|         self.max_radius = max_radius | ||||
|         self.oversampling_scale = oversampling_scale | ||||
|         self.num_projectors = max_radius + 1 | ||||
| 
 | ||||
|     def get_num_projectors(self): | ||||
|         return self.num_projectors | ||||
|          | ||||
|     def get_projector_kernel(self, projector_index): | ||||
|         assert projector_index < self.get_num_projectors() | ||||
|         radius = projector_index | ||||
|         image_size = self.max_radius * 2 + 1 | ||||
|         circle_pos = {'x': self.max_radius, 'y': self.max_radius} | ||||
|         oversampled_circle = create_circle_image( | ||||
|             image_size={'width':image_size * self.oversampling_scale, 'height':image_size*self.oversampling_scale}, | ||||
|             circle_radius=radius * self.oversampling_scale, | ||||
|             circle_pos={'x': self.max_radius* self.oversampling_scale, 'y': self.max_radius* self.oversampling_scale}, | ||||
|             circle_thickness=1 * self.oversampling_scale) | ||||
|         circle_image = oversampled_circle.resample(width=image_size, height=image_size) | ||||
|         anchor_point = circle_pos | ||||
|         return circle_image, anchor_point | ||||
| 
 | ||||
| 
 | ||||
| # class LocalProjector: | ||||
| #     """ This image processor computes the probability for each pixel to have a material oriented in the given direction | ||||
|      | ||||
| #     The technique is based on the notion of a projector. The role of the projector is to project (or cumulate) the 2D neighborhood of each pixel on a projection axis that passes through the pixel and that has an orientation chosen by the user. | ||||
| 
 | ||||
| #     """ | ||||
| 
 | ||||
| 
 | ||||
| #     def __init__(self, searched_orientation, image_process_listener=imageprocessing.NullImageProcessListener()): | ||||
| #         imageprocessing.IImageProcessor.__init__(self, image_process_listener) | ||||
| #         self.searched_orientation = searched_orientation | ||||
| #         self.orientation_amount_image = None | ||||
| 
 | ||||
| #     @staticmethod | ||||
| #     def compute_noise_in_perpendicular_orientation(src_image, orientation, half_window_width=5, image_process_listener=imageprocessing.NullImageProcessListener()): | ||||
| #         """ Computes an image that gives for each pixel, the amount of noise in a direction perpendicular to the given orientation | ||||
| 
 | ||||
| #         Because the projection has to be performed for each pixel, we encode the projector operator in the form of a set of num_projectors 2D kernels that are used as a filter. Each kernel cumulates the image signal (therefore computes the sum of the image signal) along a line perpendicular to the projection axis, but each at a different position (offset) on this projection axis. | ||||
|    | ||||
| #           :param src_image: the input image, the one we want to process | ||||
| #           :type src_image: numpy.array | ||||
|            | ||||
| #           :param orientation: the orientation along which the noise needs to be computed | ||||
| #           :type orientation: float (in radians) | ||||
|            | ||||
| #           :param half_window_width: half size of the neighborhood window, in pixels (the heighborood window is a window of size (2*half_window_width+1, 2*half_window_width+1) centered on each pixel). The bigger, the more precise the measurement but with less locality. | ||||
| #         """ | ||||
| #         projector_base = OrientationProbabilityEstimator.ProjectorBase2(orientation, searched_segment_size=10.0, cut_blur_stddev=3.0, image_process_listener=image_process_listener) | ||||
| #         projections = numpy.empty((src_image.shape[0], src_image.shape[1], projector_base.get_num_projectors()), dtype=numpy.float32) | ||||
| #         # print('projections.shape=%s' % str(projections.shape)) | ||||
| #         for projector_index in range(projector_base.get_num_projectors()): | ||||
| #             projector, center_of_filter = projector_base.get_projector_kernel(projector_index) | ||||
| 
 | ||||
| #             projection = cv2.filter2D(src_image.astype(numpy.float32), ddepth=-1, kernel=projector, anchor=tuple(center_of_filter)) | ||||
| #             image_process_listener.onImage(projection, 'projection_%f_%d' % (orientation, projector_index)) | ||||
| #             projections[:, :, projector_index] = projection | ||||
| #         # for each pixel, compute the gradient along its projection axis | ||||
| #         # swap axes because I don't think the filter2D only works along fist 2 axes | ||||
| #         projections = numpy.swapaxes(projections, 1, 2) | ||||
| #         grad_kernel = numpy.array((-0.5, 0.5), dtype=numpy.float32) | ||||
| #         gradients = cv2.filter2D(projections, ddepth=-1, kernel=grad_kernel, anchor=(0, 0)) | ||||
| 
 | ||||
| #         if image_process_listener is not None: | ||||
| #             # grab a slice of the gradient image for debugging purpose | ||||
| #             cut = gradients[:, :, gradients.shape[2] / 2] | ||||
| #             image_process_listener.onImage(cut, 'cut_%f' % (orientation)) | ||||
| 
 | ||||
| #         gradients = numpy.swapaxes(gradients, 1, 2) | ||||
| #         gradients *= gradients | ||||
| #         texture_amount = numpy.sum(gradients, axis=2) | ||||
| #         image_process_listener.onImage(texture_amount, 'texture_amount_%f' % (orientation)) | ||||
| #         return texture_amount | ||||
| 
 | ||||
| #     def processImage(self, image): | ||||
| #         self.orientation_amount_image = OrientationProbabilityEstimator.compute_noise_in_perpendicular_orientation(image, self.searched_orientation, self.get_image_process_listener()) | ||||
| 
 | ||||
| #     def get_result(self): | ||||
| #         return self.orientation_amount_image | ||||
|      | ||||
|  | @ -8,7 +8,7 @@ import unittest  # unittest2 doesn't exist in fiji | |||
| import sys | ||||
| from lipase.imageengine import IImageEngine, PixelType, Aabb, NullDebugger, FileBasedDebugger | ||||
| from lipase.imagej.ijimageengine import IJImageEngine, IJImage | ||||
| from lipase.localprojector import create_circle_image | ||||
| from lipase.circsymdetector import create_circle_image | ||||
| 
 | ||||
| class ImProcTester(unittest.TestCase): | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ from lipase.traps_detector import TrapsDetector | |||
| from lipase.catalog import ImageCatalog, Sequence | ||||
| from lipase.lipase import Lipase, ImageLogger | ||||
| from lipase.lipase import GlobulesAreaEstimator, EmptyFrameBackgroundEstimator | ||||
| from lipase.circsymdetector import CircularSymmetryDetector | ||||
| from lipase.imagej.hdf5serializer import save_hdf5_file | ||||
| 
 | ||||
| 
 | ||||
|  | @ -35,78 +36,86 @@ class TestLipase(unittest.TestCase): | |||
|         print("uninitializing TestLipase instance") | ||||
|         self.catalog = None | ||||
| 
 | ||||
|     def test_estimate_white(self): | ||||
|         sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos2'] | ||||
|         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) | ||||
|         IImageEngine.get_instance().debugger.on_image(white_estimate, 'white_estimate') | ||||
|         # assert False, "hellooooo" | ||||
|         print('end of test_estimate_white') | ||||
|     # def test_estimate_white(self): | ||||
|     #     sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos2'] | ||||
|     #     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) | ||||
|     #     IImageEngine.get_instance().debugger.on_image(white_estimate, 'white_estimate') | ||||
|     #     # assert False, "hellooooo" | ||||
|     #     print('end of test_estimate_white') | ||||
| 
 | ||||
|     def test_uniform_lighting_correction(self): | ||||
|         non_uniform_sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0'] | ||||
|         uniform_sequence = correct_non_uniform_lighting(non_uniform_sequence, 'DM300_nofilter_vis', white_estimator=WhiteEstimator(open_size=75, close_size=75, average_size=75))  # pylint: disable=unused-variable | ||||
|     # def test_uniform_lighting_correction(self): | ||||
|     #     non_uniform_sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0'] | ||||
|     #     uniform_sequence = correct_non_uniform_lighting(non_uniform_sequence, 'DM300_nofilter_vis', white_estimator=WhiteEstimator(open_size=75, close_size=75, average_size=75))  # pylint: disable=unused-variable | ||||
| 
 | ||||
|     def test_template_matcher(self): | ||||
|         sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0'] | ||||
|         stack = sequence.as_hyperstack(['DM300_nofilter_vis'], selected_frames=[0]) | ||||
|         first_image = stack.get_image(frame_index=0) | ||||
|         x_min = 423 | ||||
|         x_max = 553 | ||||
|         y_min = 419 | ||||
|         y_max = 533 | ||||
|         template_trap_aabb = Aabb(x_min, y_min, x_max, y_max) | ||||
|         template_trap_image = first_image.get_subimage(template_trap_aabb) | ||||
|         for image in [first_image, template_trap_image]: | ||||
|             print(image.get_pixel_type(), image.get_width(), image.get_height()) | ||||
|         # the typical value of peaks is -2.e10 and the value between peaks is below -8.0e10 | ||||
|         threshold = -3.0e10 | ||||
|         tolerance = 1.0e10 | ||||
|         maxima_finder = MaximaFinder(threshold, tolerance) | ||||
|         template_matcher = TemplateMatcher(maxima_finder) | ||||
|         matches = template_matcher.match_template(first_image, template_trap_image) | ||||
|         num_traps = len(matches) | ||||
|         print("number of traps found : %d" % num_traps) | ||||
|         num_expected_traps = 13  # 13 traps are completely visible in the first image | ||||
|         self.assertAlmostEqual(len(matches), num_expected_traps, delta=1.0) | ||||
|     # def test_template_matcher(self): | ||||
|     #     sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0'] | ||||
|     #     stack = sequence.as_hyperstack(['DM300_nofilter_vis'], selected_frames=[0]) | ||||
|     #     first_image = stack.get_image(frame_index=0) | ||||
|     #     x_min = 423 | ||||
|     #     x_max = 553 | ||||
|     #     y_min = 419 | ||||
|     #     y_max = 533 | ||||
|     #     template_trap_aabb = Aabb(x_min, y_min, x_max, y_max) | ||||
|     #     template_trap_image = first_image.get_subimage(template_trap_aabb) | ||||
|     #     for image in [first_image, template_trap_image]: | ||||
|     #         print(image.get_pixel_type(), image.get_width(), image.get_height()) | ||||
|     #     # the typical value of peaks is -2.e10 and the value between peaks is below -8.0e10 | ||||
|     #     threshold = -3.0e10 | ||||
|     #     tolerance = 1.0e10 | ||||
|     #     maxima_finder = MaximaFinder(threshold, tolerance) | ||||
|     #     template_matcher = TemplateMatcher(maxima_finder) | ||||
|     #     matches = template_matcher.match_template(first_image, template_trap_image) | ||||
|     #     num_traps = len(matches) | ||||
|     #     print("number of traps found : %d" % num_traps) | ||||
|     #     num_expected_traps = 13  # 13 traps are completely visible in the first image | ||||
|     #     self.assertAlmostEqual(len(matches), num_expected_traps, delta=1.0) | ||||
| 
 | ||||
| 
 | ||||
|     def test_traps_detector(self): | ||||
|         # the typical value of peaks is -500 and the value between peaks is below -2500 | ||||
|         threshold = -1500.0 | ||||
|         tolerance = 1500 | ||||
|         maxima_finder = MaximaFinder(threshold, tolerance) | ||||
|         template_matcher = TemplateMatcher(maxima_finder) | ||||
|         traps_detector = TrapsDetector(template_matcher) | ||||
|         sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0'] | ||||
|         x_min = 423 | ||||
|         x_max = 553 | ||||
|         y_min = 419 | ||||
|         y_max = 533 | ||||
|         trap_aabb = Aabb(x_min, y_min, x_max, y_max) | ||||
|         traps_mask = traps_detector.compute_traps_mask(sequence, 'DM300_nofilter_vis', trap_aabb) | ||||
|         measured_mean_value = traps_mask.get_mean_value() | ||||
|         expected_traps_coverage = 0.07909 | ||||
|         traps_pixel_value = 255.0 | ||||
|         expected_mean_value = expected_traps_coverage * traps_pixel_value | ||||
|         print("expected_mean_value: %f" % expected_mean_value) | ||||
|         print("measured_mean_value: %f" % measured_mean_value) | ||||
|         self.assertAlmostEqual(measured_mean_value, expected_mean_value, delta=0.01) | ||||
|     # def test_traps_detector(self): | ||||
|     #     # the typical value of peaks is -500 and the value between peaks is below -2500 | ||||
|     #     threshold = -1500.0 | ||||
|     #     tolerance = 1500 | ||||
|     #     maxima_finder = MaximaFinder(threshold, tolerance) | ||||
|     #     template_matcher = TemplateMatcher(maxima_finder) | ||||
|     #     traps_detector = TrapsDetector(template_matcher) | ||||
|     #     sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0'] | ||||
|     #     x_min = 423 | ||||
|     #     x_max = 553 | ||||
|     #     y_min = 419 | ||||
|     #     y_max = 533 | ||||
|     #     trap_aabb = Aabb(x_min, y_min, x_max, y_max) | ||||
|     #     traps_mask = traps_detector.compute_traps_mask(sequence, 'DM300_nofilter_vis', trap_aabb) | ||||
|     #     measured_mean_value = traps_mask.get_mean_value() | ||||
|     #     expected_traps_coverage = 0.07909 | ||||
|     #     traps_pixel_value = 255.0 | ||||
|     #     expected_mean_value = expected_traps_coverage * traps_pixel_value | ||||
|     #     print("expected_mean_value: %f" % expected_mean_value) | ||||
|     #     print("measured_mean_value: %f" % measured_mean_value) | ||||
|     #     self.assertAlmostEqual(measured_mean_value, expected_mean_value, delta=0.01) | ||||
| 
 | ||||
|     def test_visible_traps_sequence_processing(self): | ||||
|     # def test_visible_traps_sequence_processing(self): | ||||
|     #     traps_sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0'] | ||||
|     #     visible_traps_sequence = traps_sequence.as_hyperstack(['DM300_nofilter_vis']) | ||||
|     #     background_estimator = EmptyFrameBackgroundEstimator(empty_frame_index=39) | ||||
|     #     processor = GlobulesAreaEstimator(background_estimator=background_estimator, particle_threshold=2000.0) | ||||
|     #     results = processor.detect_particles(visible_traps_sequence) | ||||
|     #     save_hdf5_file('results.h5', results) | ||||
|     #     # results file could be checked with "h5dump --xml ./lipase.git/results.h5" | ||||
|     #     first_frame_measured_ratio = results['globules_area_ratio'][(0,)] | ||||
|     #     first_frame_expected_ratio = 0.008 | ||||
|     #     self.assertAlmostEqual(first_frame_measured_ratio, first_frame_expected_ratio, delta=0.01) | ||||
| 
 | ||||
|     def test_circle_detector(self): | ||||
|         traps_sequence = self.catalog.sequences['res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0'] | ||||
|         visible_traps_sequence = traps_sequence.as_hyperstack(['DM300_nofilter_vis']) | ||||
|         background_estimator = EmptyFrameBackgroundEstimator(empty_frame_index=39) | ||||
|         processor = GlobulesAreaEstimator(background_estimator=background_estimator, particle_threshold=2000.0) | ||||
|         results = processor.detect_particles(visible_traps_sequence) | ||||
|         save_hdf5_file('results.h5', results) | ||||
|         # results file could be checked with "h5dump --xml ./lipase.git/results.h5" | ||||
|         first_frame_measured_ratio = results['globules_area_ratio'][(0,)] | ||||
|         first_frame_expected_ratio = 0.008 | ||||
|         self.assertAlmostEqual(first_frame_measured_ratio, first_frame_expected_ratio, delta=0.01) | ||||
| 
 | ||||
|         src_image = visible_traps_sequence.get_image(frame_index=0) | ||||
|         ie = IImageEngine.get_instance() | ||||
|         detector = CircularSymmetryDetector(max_radius=10.0) | ||||
|         radial_profiles = detector.compute_radial_profiles(src_image) | ||||
|          | ||||
|     # def test_lipase_process(self): | ||||
|     #     lipase = Lipase(self.catalog, debugger=NullDebugger()) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue