def testBrightfieldShading(self): ReferenceImagePath = self.GetImagePath("400.png") ShadedImagePath = self.GetImagePath("400_Shaded.png") ShadingReferencePath = self.GetImagePath("BrightfieldShading.png") self.assertTrue(os.path.exists(ReferenceImagePath)) self.assertTrue(os.path.exists(ShadedImagePath)) self.assertTrue(os.path.exists(ShadingReferencePath)) originalImage = nir.LoadImage(ReferenceImagePath) shadedImage = nir.LoadImage(ShadedImagePath) shadingMask = nir.LoadImage(ShadingReferencePath) shadedImageV2 = originalImage * shadingMask shadedImageV2Path = os.path.join(self.TestOutputPath, "TestGeneratedShadedImage.png") nir.SaveImage(shadedImageV2Path, shadedImageV2) OutputPaths = tiles.ShadeCorrect( [ShadedImagePath, shadedImageV2Path], shadingMask, self.TestOutputPath, correction_type=tiles.ShadeCorrectionTypes.BRIGHTFIELD) shownImages = [originalImage, shadedImage, shadingMask] for path in OutputPaths: correctedImage = nir.LoadImage(path) shownImages.append(correctedImage) # nir.ShowGrayscale(shownImages) pass
def test_16Bit_to_8Bit_ConvertImage(self): filename = '10001_RPC2_590.tif' self.FixedImagePath = os.path.join(self.ImportedDataPath, '16-bit', filename) basename = os.path.basename(filename) output_path = os.path.join(self.TestOutputPath, basename + '_converted.tif') self.assertTrue(os.path.exists(self.FixedImagePath), "Missing test input: {0}".format(self.FixedImagePath)) output = self.RunConvertImageTest(self.FixedImagePath) nornir_imageregistration.SaveImage(output_path, output)
def RunSaveLoadImageTest_BppOnly(self, input_image, output_fullpath, expected_bpp): wrong_input_bpp_error_msg = "Expected {0}-bit image".format( expected_bpp) wrong_output_bpp_error_msg = "Expected {0}-bit image".format( expected_bpp) bpp = nornir_imageregistration.ImageBpp(input_image) self.assertEqual(bpp, expected_bpp, wrong_input_bpp_error_msg) nornir_imageregistration.SaveImage(output_fullpath, input_image, bpp=expected_bpp) reloaded_image = nornir_imageregistration.ImageParamToImageArray( output_fullpath) MagickBpp = nornir_shared.images.GetImageBpp(output_fullpath) self.assertEqual(MagickBpp, expected_bpp, wrong_output_bpp_error_msg) reloaded_bpp = nornir_imageregistration.ImageBpp(reloaded_image) self.assertEqual(reloaded_bpp, expected_bpp, wrong_output_bpp_error_msg)
def RunSaveLoadImageTest(self, input_image_fullpath, expected_input_properties, expected_output_properties): self.assertTrue(isinstance(expected_input_properties, ImageProperties)) self.assertTrue(isinstance(expected_output_properties, ImageProperties)) self.assertTrue(os.path.exists(input_image_fullpath), "Missing test input: {0}".format(input_image_fullpath)) input_image = nornir_imageregistration.ImageParamToImageArray( input_image_fullpath) output_path = os.path.join( self.TestOutputPath, expected_output_properties.GenFilename(input_image_fullpath)) wrong_input_bpp_error_msg = "Expected {0}-bit image".format( expected_input_properties.bpp) wrong_output_bpp_error_msg = "Expected {0}-bit image".format( expected_output_properties.bpp) bpp = nornir_imageregistration.ImageBpp(input_image) self.assertEqual(bpp, expected_input_properties.bpp, wrong_input_bpp_error_msg) nornir_imageregistration.SaveImage(output_path, input_image, bpp=expected_output_properties.bpp) reloaded_image = nornir_imageregistration.ImageParamToImageArray( output_path) MagickBpp = nornir_shared.images.GetImageBpp(output_path) self.assertEqual(MagickBpp, expected_output_properties.bpp, wrong_output_bpp_error_msg) reloaded_bpp = nornir_imageregistration.ImageBpp(reloaded_image) self.assertEqual(reloaded_bpp, expected_output_properties.bpp, wrong_output_bpp_error_msg)
def RefineTransform(stosTransform, target_image, source_image, target_mask=None, source_mask=None, num_iterations=None, cell_size=None, grid_spacing=None, angles_to_search=None, min_travel_for_finalization=None, min_alignment_overlap=None, SaveImages=False, SavePlots=False, outputDir=None): ''' Refines a transform and returns a grid transform produced by the refinement algorithm. Places a regular grid of control points across the target image. These corresponding points on the source image are then adjusted to create a mapping from Source To Fixed Space for the source image. :param stosTransform: The transform to refine :param target_image: ndarray or path to file, fixed space image :param source_image: ndarray or path to file, source space image :param target_mask: ndarray or path to file, fixed space image mask :param source_mask: ndarray or path to file, source space image mask :param int num_iterations: The maximum number of iterations to perform :param tuple cell_size: (width, height) area of image around control points to use for registration :param tuple grid_spacing: (width, height) of separation between control points on the grid :param array angles_to_search: An array of floats or None. Images are rotated by the degrees indicated in the array. The single best alignment across all angles is selected. :param float min_alighment_overlap: Limits how far control points can be translated. The cells from fixed and target space must overlap by this minimum amount. :param bool SaveImages: Saves registered images of each iteration in the output path for debugging purposes :param bool SavePlots: Saves histograms and vector plots of each iteration in the output path for debugging purposes :param str outputDir: Directory to save images and plots if requested. Must not be null if SaveImages or SavePlots are true ''' if cell_size is None: cell_size = (256, 256) if grid_spacing is None: grid_spacing = (256, 256) if angles_to_search is None: angles_to_search = [0] if num_iterations is None: num_iterations = 10 if min_travel_for_finalization is None: min_travel_for_finalization = 0.333 if min_alignment_overlap is None: min_alignment_overlap = 0.5 if SavePlots or SaveImages: assert (outputDir is not None) # Convert inputs to numpy arrays cell_size = np.asarray( cell_size, dtype=np.int32) * 2.0 # Double size of cell area for first pass only grid_spacing = np.asarray(grid_spacing, dtype=np.int32) target_image = nornir_imageregistration.ImageParamToImageArray( target_image, dtype=np.float32) source_image = nornir_imageregistration.ImageParamToImageArray( source_image, dtype=np.float32) if target_mask is not None: target_mask = nornir_imageregistration.ImageParamToImageArray( target_mask, dtype=np.bool) if source_mask is not None: source_mask = nornir_imageregistration.ImageParamToImageArray( source_mask, dtype=np.bool) final_pass = False # True if this is the last iteration the loop will perform final_pass_angles = np.linspace( -7.5, 7.5, 11 ) # The last registration we perform on a cell is a bit more thorough finalized_points = {} CutoffPercentilePerIteration = 10.0 i = 1 while i <= num_iterations: alignment_points = _RunRefineTwoImagesIteration( stosTransform, target_image, source_image, target_mask, source_mask, cell_size=cell_size, grid_spacing=grid_spacing, finalized=finalized_points, angles_to_search=angles_to_search, min_alignment_overlap=min_alignment_overlap) print("Pass {0} aligned {1} points".format(i, len(alignment_points))) # For the first pass we use a larger cell to help get some initial registration points if i == 1: cell_size = cell_size / 2.0 combined_alignment_points = alignment_points + list( finalized_points.values()) percentile = 100.0 - (CutoffPercentilePerIteration * i) if percentile < 10.0: percentile = 10.0 elif percentile > 100: percentile = 100 # if final_pass: # percentile = 0 if SavePlots: histogram_filename = os.path.join( outputDir, 'weight_histogram_pass{0}.png'.format(i)) nornir_imageregistration.views.PlotWeightHistogram( alignment_points, histogram_filename, cutoff=percentile / 100.0) vector_field_filename = os.path.join( outputDir, 'Vector_field_pass{0}.png'.format(i)) nornir_imageregistration.views.PlotPeakList( alignment_points, list(finalized_points.values()), vector_field_filename, ylim=(0, target_image.shape[1]), xlim=(0, target_image.shape[0])) vector_field_filename = os.path.join( outputDir, 'Vector_field_pass_delta{0}.png'.format(i)) nornir_imageregistration.views.PlotPeakList( alignment_points, list(finalized_points.values()), vector_field_filename, ylim=(0, target_image.shape[1]), xlim=(0, target_image.shape[0]), attrib='PSDDelta') updatedTransform = _PeakListToTransform(combined_alignment_points, percentile) new_finalized_points = CalculateFinalizedAlignmentPointsMask( combined_alignment_points, percentile=percentile, min_travel_distance=min_travel_for_finalization) new_finalizations = 0 for (ir, record) in enumerate(alignment_points): if not new_finalized_points[ir]: continue key = tuple(record.SourcePoint) if key in finalized_points: continue # See if we can improve the final alignment refined_align_record = nornir_imageregistration.stos_brute.SliceToSliceBruteForce( record.TargetROI, record.SourceROI, AngleSearchRange=final_pass_angles, MinOverlap=min_alignment_overlap, SingleThread=True, Cluster=False, TestFlip=False) if refined_align_record.weight > record.weight: oldPSDDelta = record.PSDDelta record = nornir_imageregistration.EnhancedAlignmentRecord( ID=record.ID, TargetPoint=record.TargetPoint, SourcePoint=record.SourcePoint, peak=refined_align_record.peak, weight=refined_align_record.weight, angle=refined_align_record.angle, flipped_ud=refined_align_record.flippedud) record.PSDDelta = oldPSDDelta # Create a record that is unmoving finalized_points[ key] = nornir_imageregistration.EnhancedAlignmentRecord( record.ID, TargetPoint=record.AdjustedTargetPoint, SourcePoint=record.SourcePoint, peak=np.asarray((0, 0), dtype=np.float32), weight=record.weight, angle=0, flipped_ud=record.flippedud) finalized_points[key].PSDDelta = record.PSDDelta new_finalizations += 1 print( "Pass {0} has locked {1} new points, {2} of {3} are locked".format( i, new_finalizations, len(finalized_points), len(combined_alignment_points))) stosTransform = updatedTransform if SaveImages: #InputStos.Save(os.path.join(outputDir, "UpdatedTransform_pass{0}.stos".format(i))) warpedToFixedImage = nornir_imageregistration.assemble.TransformStos( updatedTransform, fixedImage=target_image, warpedImage=source_image) Delta = warpedToFixedImage - target_image ComparisonImage = np.abs(Delta) ComparisonImage = ComparisonImage / ComparisonImage.max() nornir_imageregistration.SaveImage(os.path.join( outputDir, 'delta_pass{0}.png'.format(i)), ComparisonImage, bpp=8) nornir_imageregistration.SaveImage(os.path.join( outputDir, 'image_pass{0}.png'.format(i)), warpedToFixedImage, bpp=8) i = i + 1 if final_pass: break if i == num_iterations: final_pass = True angles_to_search = final_pass_angles # If we've locked 10% of the points and have not locked any new ones we are done if len(finalized_points) > len( combined_alignment_points) * 0.1 and new_finalizations == 0: final_pass = True angles_to_search = final_pass_angles # If we've locked 90% of the points we are done if len(finalized_points) > len(combined_alignment_points) * 0.9: final_pass = True angles_to_search = final_pass_angles # Convert the transform to a grid transform and persist to disk return stosTransform