def runTest(self): numThreadsInTest = 100 CreateFile(self.TestOutputPath, 0) ExpectedPath = os.path.join(self.TestOutputPath, TestThreadPool.FilenameTemplate % 0) self.assertTrue( os.path.exists(ExpectedPath), "Function we are testing threads with does not seem to work") os.remove(ExpectedPath) # Create a 100 threads and have them create files TPool = pools.GetGlobalThreadPool() self.assertIsNotNone(TPool) VerifyExceptionBehaviour(self, TPool) runFunctionOnPool(self, TPool) runFileIOOnPool(self, TPool) #No need to test even distribution of work because the threads are all in the same process #runEvenDistributionOfWorkTestOnThePool(self,TPool) TPool = pools.GetThreadPool("Test local thread pool") self.assertIsNotNone(TPool) runFileIOOnPool(self, TPool)
def _ShowMosaic(self, mosaic, mosaic_path=None, openwindow=True, usecluster=True, title=None, target_space_scale=None, source_space_scale=None): (assembledImage, mask) = mosaic.AssembleImage(tilesPath=None, usecluster=usecluster, target_space_scale=target_space_scale, source_space_scale=source_space_scale) if not mosaic_path is None: pool = nornir_pools.GetGlobalThreadPool() pool.add_task("Save %s" % mosaic_path, core.SaveImage, mosaic_path, assembledImage) #core.SaveImage(mosaic_path, assembledImage) if openwindow: if title is None: title = "A mosaic with no tiles out of place" self.assertTrue( nornir_imageregistration.ShowGrayscale(assembledImage, title=title, PassFail=True))
def runTest(self): TPool = pools.GetGlobalThreadPool() self.assertIsNotNone(TPool) runFunctionOnPool(self, TPool, Func=SquareTheNumberWithDelay) runFileIOOnPool(self, TPool, CreateFunc=CreateFileWithDelay, ReadFunc=ReadFileWithDelay)
def LoadMosaic(self, mosaicFullPath, tiles_dir=None): '''Return a list of image transform views for the mosaic file''' mosaic = Mosaic.LoadFromMosaicFile(mosaicFullPath) if len(mosaic.ImageToTransform) == 0: return None mosaic.TranslateToZeroOrigin() tiles_dir = MosaicState.GetMosaicTilePath( list(mosaic.ImageToTransform.keys())[0], mosaicFullPath, tiles_dir) if tiles_dir is None: return None tilesPathList = mosaic.CreateTilesPathList(tiles_dir) transform_scale = nornir_imageregistration.tileset.MostCommonScalar( list(mosaic.ImageToTransform.values()), tilesPathList) ImageTransformViewList = [] z_step = 1.0 / float(len(mosaic.ImageToTransform)) z = z_step - (z_step / 2.0) output_len = 0 pools = nornir_pools.GetGlobalThreadPool() tasks = [] for image_filename, transform in list(mosaic.ImageToTransform.items()): tile_full_path = os.path.join(tiles_dir, image_filename) task = pools.add_task(str(z), self.AllocateMosaicTile, transform, tile_full_path, transform_scale) task.z = z tasks.append(task) # image_transform_view = self.AllocateMosaicTile(transform, tile_full_path, transform_scale) # image_transform_view.z = z z += z_step # ImageTransformViewList.append(image_transform_view) wx.Yield() for t in tasks: image_transform_view = t.wait_return() image_transform_view.z = t.z ImageTransformViewList.append(image_transform_view) output = '%g' % (z * 100.0) sys.stdout.write('\b' * output_len) sys.stdout.write(output) output_len = len(output) self.ImageTransformViewList = ImageTransformViewList return ImageTransformViewList
def GetFixedAndWarpedImageStats(imFixed, imWarped): tpool = nornir_pools.GetGlobalThreadPool() fixedStatsTask = tpool.add_task( 'FixedStats', nornir_imageregistration.ImageStats.CalcStats, imFixed) warpedStats = nornir_imageregistration.ImageStats.CalcStats(imWarped) fixedStats = fixedStatsTask.wait_return() return (fixedStats, warpedStats)
def ClearTempDirectories(level_paths): '''Deletes temporary directories used to generate levels''' if level_paths is None: return if len(level_paths) == 0: return temp_dir = tempfile.gettempdir() pool = nornir_pools.GetGlobalThreadPool() for level_path in level_paths: LevelDir = os.path.join(temp_dir, os.path.basename(level_path)) pool.add_task("Remove temp directory {0}".format(LevelDir), shutil.rmtree, LevelDir, ignore_errors=True) pool.wait_completion()
def __ScaleImage(ImageNode, HtmlPaths, MaxImageWidth=None, MaxImageHeight=None): '''Scale an image to be smaller than the maximum dimensions. Vector based images such as SVG will not be scaled :return: (Image_source_path, Width, Height) Image source path may refer to a copy or the original. ''' Height = MaxImageHeight Width = MaxImageWidth try: (Height, Width) = ImageNode.Dimensions #[Height, Width] = nornir_imageregistration.GetImageSize(ImageNode.FullPath) except IOError: return (HtmlPaths.GetSubNodeFullPath(ImageNode), Height, Width) # Create a thumbnail if needed if Width > MaxImageWidth or Height > MaxImageHeight: Scale = max( float(Width) / MaxImageWidth, float(Height) / MaxImageHeight) Scale = 1.0 / Scale os.makedirs(HtmlPaths.ThumbnailDir, exist_ok=True) ThumbnailFilename = GetTempFileSaltString() + ImageNode.Path ImgSrcPath = os.path.join(HtmlPaths.ThumbnailRelative, ThumbnailFilename) ThumbnailOutputFullPath = os.path.join(HtmlPaths.ThumbnailDir, ThumbnailFilename) # nfiles.RemoveOutdatedFile(ImageNode.FullPath, ThumbnailOutputFullPath) # if not os.path.exists(ThumbnailOutputFullPath): Pool = nornir_pools.GetGlobalThreadPool() Pool.add_task(ImageNode.FullPath, nornir_imageregistration.Shrink, ImageNode.FullPath, ThumbnailOutputFullPath, Scale) #cmd = "magick convert " + ImageNode.FullPath + " -resize " + str(Scale * 100) + "% " + ThumbnailOutputFullPath #Pool.add_process(cmd, cmd + " && exit", shell=True) Width = int(Width * Scale) Height = int(Height * Scale) else: ImgSrcPath = HtmlPaths.GetSubNodeFullPath(ImageNode) return (ImgSrcPath, Height, Width)
def CalculateRBFWeights(self, WarpedPoints, ControlPoints, BasisFunction=None): BetaMatrix = RBFWithLinearCorrection.CreateBetaMatrix( WarpedPoints, BasisFunction) (SolutionMatrix_X, SolutionMatrix_Y ) = RBFWithLinearCorrection.CreateSolutionMatricies(ControlPoints) thread_pool = nornir_pools.GetGlobalThreadPool() Y_Task = thread_pool.add_task("WeightsY", scipy.linalg.solve, BetaMatrix, SolutionMatrix_Y) WeightsX = scipy.linalg.solve(BetaMatrix, SolutionMatrix_X) WeightsY = Y_Task.wait_return() return numpy.hstack([WeightsX, WeightsY])
def OnTransformChanged(self): '''Calls every function registered to be notified when the transform changes.''' # Calls every listener when the transform has changed in a way that a point may be mapped to a new position in the fixed space if len(self.OnChangeEventListeners) > 1: Pool = nornir_pools.GetGlobalThreadPool() tlist = list() for func in self.OnChangeEventListeners: tlist.append( Pool.add_task("OnTransformChanged calling " + str(func), func)) #Call wait on all tasks so we see exceptions while len(tlist) > 0: t = tlist.pop(0) t.wait() else: for func in self.OnChangeEventListeners: func()
def OnSaveWarpedImage(self, e): # Set the path for the output directory. if not (pyre.state.currentStosConfig.FixedImageViewModel is None or pyre.state.currentStosConfig.WarpedImageViewModel is None): dlg = wx.FileDialog(self, "Choose a Directory", StosWindow.imagedirname, "", "*.png", wx.FD_SAVE) if dlg.ShowModal() == wx.ID_OK: StosWindow.imagedirname = dlg.GetDirectory() self.filename = dlg.GetFilename() state.currentStosConfig.OutputImageFullPath = os.path.join( StosWindow.imagedirname, self.filename) # common.SaveRegisteredWarpedImage(pyre.state.currentStosConfig.OutputImageFullPath, # pyre.state.currentStosConfig.Transform, # pyre.state.currentStosConfig.WarpedImageViewModel.Image) pool = pools.GetGlobalThreadPool() pool.add_task( "Save " + pyre.state.currentStosConfig.OutputImageFullPath, common.SaveRegisteredWarpedImage, state.currentStosConfig.OutputImageFullPath, state.currentStosConfig.Transform, state.currentStosConfig.WarpedImageViewModel.Image)
def ParseSections(InputVolumeNode, OutputVolumeNode): # Find all of the section tags Pool = nornir_pools.GetGlobalThreadPool() SectionTasks = [] print("Adding Sections\n") for BlockNode in InputVolumeNode.findall('Block'): for SectionNode in BlockNode.Sections: OutputSectionNode = OutputVolumeNode.find("Section[@Number='%d']" % SectionNode.Number) assert (OutputSectionNode is None) #if not ECLIPSE: #print('\b' * 3) print('Queue %g' % SectionNode.Number) task = Pool.add_task(str(SectionNode.Number), ParseSection, BlockNode.Path, SectionNode) SectionTasks.append(task) for t in SectionTasks: if not ECLIPSE: print('\b' * 8) print('%s' % t.name) OutputSectionNode = t.wait_return() OutputVolumeNode.append(OutputSectionNode) AllSectionNodes = OutputVolumeNode.findall('Section') OutputVolumeNode.attrib['num_sections'] = str(len(AllSectionNodes))
def LoadStos(self, stosFullPath): if stosFullPath is None: return False success = True dirname = os.path.dirname(stosFullPath) filename = os.path.basename(stosFullPath) obj = StosFile.Load(os.path.join(dirname, filename)) self.LoadTransform(stosFullPath) pool = nornir_pools.GetGlobalThreadPool() ControlImageTask = None WarpedImageTask = None ControlImageMaskTask = None WarpedImageMaskTask = None # First check the absolute path in the .stos file for images, then # check relative to the .stos file's directory ControlImagePath = self._try_locate_file(obj.ControlImageFullPath, [dirname]) if ControlImagePath is not None: ControlImageTask = pool.add_task( 'load fixed %s' % ControlImagePath, self.LoadImage, ControlImagePath) else: print("Could not find fixed image: " + obj.ControlImageFullPath) success = False WarpedImagePath = self._try_locate_file(obj.MappedImageFullPath, [dirname]) if WarpedImagePath is not None: WarpedImageTask = pool.add_task('load warped %s' % WarpedImagePath, self.LoadImage, WarpedImagePath) else: print("Could not find warped image: " + obj.MappedImageFullPath) success = False if obj.HasMasks and success: ControlMaskImagePath = self._try_locate_file( obj.ControlMaskFullPath, [dirname]) if ControlMaskImagePath: ControlImageMaskTask = pool.add_task( 'load fixed mask %s' % ControlMaskImagePath, self.LoadImage, ControlMaskImagePath) WarpedMaskImagePath = self._try_locate_file( obj.MappedMaskFullPath, [dirname]) if WarpedMaskImagePath: WarpedImageMaskTask = pool.add_task( 'load warped mask %s' % WarpedMaskImagePath, self.LoadImage, WarpedMaskImagePath) if ControlImageTask is not None: self.FixedImageViewModel = ControlImageTask.wait_return() if WarpedImageTask is not None: self.WarpedImageViewModel = WarpedImageTask.wait_return() if ControlImageMaskTask is not None: self.FixedImageMaskViewModel = ControlImageMaskTask.wait_return() if WarpedImageMaskTask is not None: self.WarpedImageMaskViewModel = WarpedImageMaskTask.wait_return() return success
def RunStosRefinement(self, stosFilePath, ImageDir=None, SaveImages=False, SavePlots=True): ''' This is a test for the refine mosaic feature which is not fully implemented ''' #stosFile = self.GetStosFile("0164-0162_brute_32") #stosFile = self.GetStosFile("0617-0618_brute_64") stosObj = nornir_imageregistration.files.StosFile.Load(stosFilePath) #stosObj.Downsample = 64.0 #stosObj.Scale(2.0) #stosObj.Save(os.path.join(self.TestOutputPath, "0617-0618_brute_32.stos")) fixedImage = stosObj.ControlImageFullPath warpedImage = stosObj.MappedImageFullPath if ImageDir is not None: fixedImage = os.path.join(ImageDir, stosObj.ControlImageFullPath) warpedImage = os.path.join(ImageDir, stosObj.MappedImageFullPath) fixedImageData = nornir_imageregistration.ImageParamToImageArray( fixedImage, dtype=np.float16) warpedImageData = nornir_imageregistration.ImageParamToImageArray( warpedImage, dtype=np.float16) stosTransform = nornir_imageregistration.transforms.factory.LoadTransform( stosObj.Transform, 1) unrefined_image_path = os.path.join(self.TestOutputPath, 'unrefined_transform.png') # if not os.path.exists(unrefined_image_path): # unrefined_warped_image = nornir_imageregistration.assemble.TransformStos(stosTransform, # fixedImage=fixedImage, # warpedImage=warpedImage) # nornir_imageregistration.SaveImage(unrefined_image_path, unrefined_warped_image, bpp=8) # else: # unrefined_warped_image = nornir_imageregistration.LoadImage(unrefined_image_path) num_iterations = 10 cell_size = np.asarray((128, 128), dtype=np.int32) * 2.0 grid_spacing = (256, 256) i = 1 finalized_points = {} min_percentile_included = 5.0 final_pass = False final_pass_angles = np.linspace(-7.5, 7.5, 11) CutoffPercentilePerIteration = 10.0 angles_to_search = None pool = nornir_pools.GetGlobalThreadPool() while i <= num_iterations: cachedFileName = '{5}_pass{0}_alignment_Cell_{2}x{1}_Grid_{4}x{3}'.format( i, cell_size[0], cell_size[1], grid_spacing[0], grid_spacing[1], self.TestName) alignment_points = self.ReadOrCreateVariable(cachedFileName) if alignment_points is None: alignment_points = _RunRefineTwoImagesIteration( stosTransform, fixedImageData, warpedImageData, os.path.join(ImageDir, stosObj.ControlMaskFullPath), os.path.join(ImageDir, stosObj.MappedMaskFullPath), cell_size=cell_size, grid_spacing=grid_spacing, finalized=finalized_points, angles_to_search=angles_to_search, min_alignment_overlap=None) self.SaveVariable(alignment_points, cachedFileName) print("Pass {0} aligned {1} points".format(i, len(alignment_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( self.TestOutputPath, '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( self.TestOutputPath, 'Vector_field_pass{0}.png'.format(i)) nornir_imageregistration.views.PlotPeakList( alignment_points, list(finalized_points.values()), vector_field_filename, ylim=(0, fixedImageData.shape[1]), xlim=(0, fixedImageData.shape[0])) updatedTransform = local_distortion_correction._PeakListToTransform( combined_alignment_points, percentile) new_finalized_points = local_distortion_correction.CalculateFinalizedAlignmentPointsMask( combined_alignment_points, percentile=percentile, min_travel_distance=0.333) 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=0.25, SingleThread=True, Cluster=False, TestFlip=False) if refined_align_record.weight > record.weight: record = nornir_imageregistration.alignment_record.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) #Create a record that is unmoving finalized_points[key] = 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) 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))) stosObj.Transform = updatedTransform stosObj.Save( os.path.join(self.TestOutputPath, "UpdatedTransform_pass{0}.stos".format(i))) if SaveImages: warpedToFixedImage = nornir_imageregistration.assemble.TransformStos( updatedTransform, fixedImage=fixedImageData, warpedImage=warpedImageData) Delta = warpedToFixedImage - fixedImageData ComparisonImage = np.abs(Delta) ComparisonImage = ComparisonImage / ComparisonImage.max() #nornir_imageregistration.SaveImage(os.path.join(self.TestOutputPath, 'delta_pass{0}.png'.format(i)), ComparisonImage, bpp=8) #nornir_imageregistration.SaveImage(os.path.join(self.TestOutputPath, 'image_pass{0}.png'.format(i)), warpedToFixedImage, bpp=8) pool.add_task('delta_pass{0}.png'.format(i), nornir_imageregistration.SaveImage, os.path.join(self.TestOutputPath, 'delta_pass{0}.png'.format(i)), np.copy(ComparisonImage), bpp=8) pool.add_task('image_pass{0}.png'.format(i), nornir_imageregistration.SaveImage, os.path.join(self.TestOutputPath, 'image_pass{0}.png'.format(i)), np.copy(warpedToFixedImage), bpp=8) #nornir_imageregistration.core.ShowGrayscale([fixedImageData, unrefined_warped_image, warpedToFixedImage, ComparisonImage]) i = i + 1 stosTransform = updatedTransform 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 stosObj.Transform = local_distortion_correction.ConvertTransformToGridTransform( stosObj.Transform, source_image_shape=warpedImageData.shape, cell_size=cell_size, grid_spacing=grid_spacing) stosObj.Save(os.path.join(self.TestOutputPath, "Final_Transform.stos")) return
def AttemptAlignPoint(transform, fixedImage, warpedImage, controlpoint, alignmentArea, anglesToSearch=None): '''Try to use the Composite view to render the two tiles we need for alignment''' if anglesToSearch is None: anglesToSearch = np.linspace(-7.5, 7.5, 11) FixedRectangle = nornir_imageregistration.Rectangle.CreateFromPointAndArea( point=[ controlpoint[0] - (alignmentArea[0] / 2.0), controlpoint[1] - (alignmentArea[1] / 2.0) ], area=alignmentArea) FixedRectangle = nornir_imageregistration.Rectangle.SafeRound( FixedRectangle) FixedRectangle = nornir_imageregistration.Rectangle.change_area( FixedRectangle, alignmentArea) rigid_transforms = nornir_imageregistration.local_distortion_correction.ApproximateRigidTransform( input_transform=transform, target_points=controlpoint) # Pull image subregions rigid_warpedImageROI = nornir_imageregistration.assemble.WarpedImageToFixedSpace( rigid_transforms[0], fixedImage.shape, warpedImage, botleft=FixedRectangle.BottomLeft, area=FixedRectangle.Size, extrapolate=True) warpedImageROI = nornir_imageregistration.assemble.WarpedImageToFixedSpace( transform, fixedImage.shape, warpedImage, botleft=FixedRectangle.BottomLeft, area=FixedRectangle.Size, extrapolate=True) fixedImageROI = nornir_imageregistration.CropImage( fixedImage.copy(), FixedRectangle.BottomLeft[1], FixedRectangle.BottomLeft[0], int(FixedRectangle.Size[1]), int(FixedRectangle.Size[0]), cval="random") fixedImageROI.setflags(write=False) #nornir_imageregistration.ShowGrayscale(([fixedImageROI, warpedImageROI],[rigid_warpedImageROI, fixedImageROI - warpedImageROI,])) pool = nornir_pools.GetGlobalThreadPool() # task = pool.add_task("AttemptAlignPoint", nornir_imageregistration.FindOffset, fixedImageROI, warpedImageROI, MinOverlap = 0.2) # apoint = task.wait_return() # apoint = nornir_imageregistration.FindOffset(fixedImageROI, warpedImageROI, MinOverlap=0.2) # nornir_imageregistration.ShowGrayscale([fixedImageROI, warpedImageROI], "Fixed <---> Warped") # nornir_imageregistration.ShowGrayscale([fixedImageROI, warpedImageROI]) t = pool.add_task( "Rigid align point {0},{1}".format(controlpoint[1], controlpoint[0]), nornir_imageregistration.stos_brute.SliceToSliceBruteForce, fixedImageROI, rigid_warpedImageROI, AngleSearchRange=anglesToSearch, MinOverlap=0.25, SingleThread=True, Cluster=False, TestFlip=False) # rigid_apoint = nornir_imageregistration.stos_brute.SliceToSliceBruteForce(fixedImageROI, rigid_warpedImageROI, # AngleSearchRange=anglesToSearch, # MinOverlap=0.25, SingleThread=True, # Cluster=False, TestFlip=False) apoint = nornir_imageregistration.stos_brute.SliceToSliceBruteForce( fixedImageROI, warpedImageROI, AngleSearchRange=anglesToSearch, MinOverlap=0.25, SingleThread=True, Cluster=False, TestFlip=False) rigid_apoint = t.wait_return() if rigid_apoint.weight > apoint.weight: return rigid_apoint else: # print("Auto-translate result: " + str(apoint)) return apoint
def ToMosaic(cls, VolumeObj, idocFileFullPath, ContrastCutoffs, OutputImageExt=None, TargetBpp=None, FlipList=None, ContrastMap=None, CameraBpp=None, debug=None): ''' This function will convert an idoc file in the given path to a .mosaic file. It will also rename image files to the requested extension and subdirectory. TargetBpp is calculated based on the number of bits required to encode the values between the median min and max values :param list FlipList: List of section numbers which should have images flipped :param dict ContrastMap: Dictionary mapping section number to (Min, Max, Gamma) tuples ''' if(OutputImageExt is None): OutputImageExt = 'png' if TargetBpp is None: TargetBpp = 8 if FlipList is None: FlipList = [] if ContrastMap is None: ContrastMap = {} SaveChannel = False idocFilePath = serialem_utils.GetPathWithoutSpaces(idocFileFullPath) OutputPath = VolumeObj.FullPath os.makedirs(OutputPath, exist_ok=True) logger = logging.getLogger(__name__ + '.' + str(cls.__name__) + "ToMosaic") # Report the current stage to the user prettyoutput.CurseString('Stage', "SerialEM to Mosaic " + str(idocFileFullPath)) SectionNumber = 0 sectionDir = os.path.dirname(idocFileFullPath) #serialem_utils.GetDirectories(idocFileFullPath) BlockObj = BlockNode.Create('TEM') [saveBlock, BlockObj] = VolumeObj.UpdateOrAddChild(BlockObj) # If the parent directory doesn't have the section number in the name, change it ExistingSectionInfo = shared.GetSectionInfo(sectionDir) if(ExistingSectionInfo[0] < 0): i = 5 # SectionNumber = SectionNumber + 1 # newPathName = ('%' + nornir_buildmanager.templates.Current.SectionFormat) % SectionNumber + '_' + sectionDir # newPath = os.path.join(ParentDir, newPathName) # prettyoutput.Log('Moving: ' + InputPath + ' -> ' + newPath) # shutil.move(InputPath, newPath) # # InputPath = newPath # # #Run glob again because the dir changes # idocFiles = glob.glob(os.path.join(InputPath,'*.idoc')) else: SectionNumber = ExistingSectionInfo.number prettyoutput.CurseString('Section', str(SectionNumber)) # Check for underscores. If there is an underscore and the first part is the sectionNumber, then use everything after as the section name SectionName = ('%' + nornir_buildmanager.templates.Current.SectionFormat) % ExistingSectionInfo.number SectionPath = ('%' + nornir_buildmanager.templates.Current.SectionFormat) % ExistingSectionInfo.number try: parts = sectionDir.partition("_") if not parts is None: if len(parts[2]) > 0: SectionName = parts[2] except: pass sectionObj = SectionNode.Create(SectionNumber, SectionName, SectionPath) [saveSection, sectionObj] = BlockObj.UpdateOrAddChildByAttrib(sectionObj, 'Number') sectionObj.Name = SectionName # Create a channel group [saveChannel, channelObj] = sectionObj.UpdateOrAddChildByAttrib(ChannelNode.Create('TEM'), 'Name') # Create a channel group for the section # I started ignoring existing supertile.mosaic files so I could rebuild sections where # a handful of tiles were corrupt # if(os.path.exists(SupertilePath)): # continue Flip = SectionNumber in FlipList; if(Flip): prettyoutput.Log("Found in FlipList.txt, flopping images") IDocData = IDoc.Load(idocFilePath, CameraBpp=CameraBpp) assert(hasattr(IDocData, 'PixelSpacing')) assert(hasattr(IDocData, 'DataMode')) assert(hasattr(IDocData, 'ImageSize')) # If there are no tiles... return if IDocData.NumTiles == 0: prettyoutput.Log("No tiles found in IDoc: " + idocFilePath) return # See if we can find a notes file... shared.TryAddNotes(channelObj, sectionDir, logger) serialem_utils.TryAddLogs(channelObj, sectionDir, logger) AddIdocNode(channelObj, idocFilePath, IDocData, logger) # Set the scale [added, ScaleObj] = cls.CreateScaleNode(IDocData, channelObj) # Parse the images ImageBpp = IDocData.GetImageBpp() if ImageBpp is None: ImageBpp = cls.GetImageBpp(IDocData, sectionDir) FilterName = 'Raw' + str(TargetBpp) if(TargetBpp is None): FilterName = 'Raw' histogramFullPath = os.path.join(sectionDir, 'Histogram.xml') IDocData.RemoveMissingTiles(sectionDir) source_tile_list = [os.path.join(sectionDir, t.Image) for t in IDocData.tiles ] (ActualMosaicMin, ActualMosaicMax, Gamma) = cls.GetSectionContrastSettings(SectionNumber, ContrastMap, ContrastCutoffs, source_tile_list, IDocData, histogramFullPath) ActualMosaicMax = numpy.around(ActualMosaicMax) ActualMosaicMin = numpy.around(ActualMosaicMin) contrast_mismatch = channelObj.RemoveFilterOnContrastMismatch(FilterName, ActualMosaicMin, ActualMosaicMax, Gamma) Pool = nornir_pools.GetGlobalThreadPool() #_PlotHistogram(histogramFullPath, SectionNumber, ActualMosaicMin, ActualMosaicMax) Pool.add_task(histogramFullPath, _PlotHistogram, histogramFullPath, SectionNumber, ActualMosaicMin, ActualMosaicMax, force_recreate=contrast_mismatch) ImageConversionRequired = contrast_mismatch # Create a channel for the Raw data [added_filter, filterObj] = channelObj.UpdateOrAddChildByAttrib(FilterNode.Create(Name=FilterName), 'Name') if added_filter: ImageConversionRequired = True filterObj.SetContrastValues(ActualMosaicMin, ActualMosaicMax, Gamma) filterObj.BitsPerPixel = TargetBpp SupertileName = 'Stage' SupertileTransform = SupertileName + '.mosaic' SupertilePath = os.path.join(channelObj.FullPath, SupertileTransform) # Check to make sure our supertile mosaic file is valid RemoveOutdatedFile(idocFilePath, SupertilePath) [added_transform, transformObj] = channelObj.UpdateOrAddChildByAttrib(TransformNode.Create(Name=SupertileName, Path=SupertileTransform, Type='Stage'), 'Path') [added_tilepyramid, PyramidNodeObj] = filterObj.UpdateOrAddChildByAttrib(TilePyramidNode.Create(Type='stage', NumberOfTiles=IDocData.NumTiles), 'Path') [added_level, LevelObj] = PyramidNodeObj.GetOrCreateLevel(1, GenerateData=False) Tileset = NornirTileset.CreateTilesFromIDocTileData(IDocData.tiles, InputTileDir=sectionDir, OutputTileDir=LevelObj.FullPath, OutputImageExt=OutputImageExt) # Make sure the target LevelObj is verified if not os.path.exists(LevelObj.FullPath): os.makedirs(LevelObj.FullPath, exist_ok=True) else: Tileset.RemoveStaleTilesFromOutputDir(SupertilePath=SupertilePath) VerifyTiles(filterObj.TilePyramid.GetLevel(1)) SourceToMissingTargetMap = Tileset.GetSourceToMissingTargetMap() # Figure out if we have to move or convert images if len(SourceToMissingTargetMap) == 0: ImageConversionRequired = False else: ImageConversionRequired = (not ImageBpp == TargetBpp) or (ImageConversionRequired or Tileset.ImageConversionRequired) if(ImageConversionRequired): Invert = False filterObj.SetContrastValues(ActualMosaicMin, ActualMosaicMax, Gamma) filterObj.TilePyramid.NumberOfTiles = IDocData.NumTiles # andValue = cls.GetBitmask(ActualMosaicMin, ActualMosaicMax, TargetBpp) #nornir_shared.images.ConvertImagesInDict(SourceToMissingTargetMap, Flip=Flip, Bpp=TargetBpp, Invert=Invert, bDeleteOriginal=False, MinMax=[ActualMosaicMin, ActualMosaicMax]) nornir_imageregistration.ConvertImagesInDict(SourceToMissingTargetMap, Flip=Flip, InputBpp=ImageBpp, OutputBpp=TargetBpp, Invert=Invert, bDeleteOriginal=False, MinMax=[ActualMosaicMin, ActualMosaicMax], Gamma=Gamma) elif(Tileset.ImageMoveRequired): for f in SourceToMissingTargetMap: shutil.copy(f, SourceToMissingTargetMap[f]) # If we wrote new images replace the .mosaic file if len(SourceToMissingTargetMap) > 0 or not os.path.exists(SupertilePath): # Writing this file indicates import succeeded and we don't need to repeat these steps, writing it will possibly invalidate a lot of downstream data # We need to flip the images. This may be a Utah scope issue, our Y coordinates are inverted relative to the images. To fix this # we flop instead of flip and reverse when writing the coordinates mosaicfile.MosaicFile.Write(SupertilePath, Entries=Tileset.GetPositionsForTargets(), Flip=not Flip, ImageSize=IDocData.ImageSize, Downsample=1); MFile = mosaicfile.MosaicFile.Load(SupertilePath) # Sometimes files fail to convert, when this occurs remove them from the .mosaic if MFile.RemoveInvalidMosaicImages(LevelObj.FullPath): MFile.Save(SupertilePath) Mosaic.TranslateMosaicFileToZeroOrigin(SupertilePath) transformObj.ResetChecksum() SaveChannel = True # transformObj.Checksum = MFile.Checksum if saveBlock: return VolumeObj elif saveSection: return BlockObj elif saveChannel: return sectionObj elif added_transform or added_tilepyramid or added_level or ImageConversionRequired or SaveChannel or contrast_mismatch: return channelObj return None