def joinPoints(results, subStacks=None, shiftPoints=True, **args): """Joins a list of points obtained from processing a stack in chunks Arguments: results (list): list of point results from the individual sub-processes subStacks (list or None): list of all sub-stack information, see :ref:`SubStack` shiftPoints (bool): if True shift points to refer to origin of the image stack considered when range specification is given. If False, absolute position in entire image stack. Returns: tuple: joined points, joined intensities """ nchunks = len(results) pointlist = [results[i][0] for i in range(nchunks)] intensities = [results[i][1] for i in range(nchunks)] results = [] resultsi = [] for i in range(nchunks): cts = pointlist[i] cti = intensities[i] if cts.size > 0: cts[:, 2] += subStacks[i]["z"][0] iid = numpy.logical_and(subStacks[i]["zCenters"][0] <= cts[:, 2], cts[:, 2] < subStacks[i]["zCenters"][1]) cts = cts[iid, :] results.append(cts) if not cti is None: cti = cti[iid] resultsi.append(cti) if results == []: if not intensities is None: return (numpy.zeros((0, 3)), numpy.zeros((0))) else: return numpy.zeros((0, 3)) else: points = numpy.concatenate(results) if shiftPoints: points = points + io.pointShiftFromRange(io.dataSize( subStacks[0]["source"]), x=subStacks[0]["x"], y=subStacks[0]["y"], z=0) else: points = points - io.pointShiftFromRange(io.dataSize( subStacks[0]["source"]), x=0, y=0, z=subStacks[0]["z"]) #absolute offset is added initially via zranges ! if intensities is None: return points else: return (points, numpy.concatenate(resultsi))
def joinPoints(results, subStacks = None, shiftPoints = True, **args): """Joins a list of points obtained from processing a stack in chunks Arguments: results (list): list of point results from the individual sub-processes subStacks (list or None): list of all sub-stack information, see :ref:`SubStack` shiftPoints (bool): if True shift points to refer to origin of the image stack considered when range specification is given. If False, absolute position in entire image stack. Returns: tuple: joined points, joined intensities """ nchunks = len(results); pointlist = [results[i][0] for i in range(nchunks)]; intensities = [results[i][1] for i in range(nchunks)]; results = []; resultsi = []; for i in range(nchunks): cts = pointlist[i]; cti = intensities[i]; if cts.size > 0: cts[:,2] += subStacks[i]["z"][0]; iid = numpy.logical_and(subStacks[i]["zCenters"][0] <= cts[:,2] , cts[:,2] < subStacks[i]["zCenters"][1]); cts = cts[iid,:]; results.append(cts); if not cti is None: cti = cti[iid]; resultsi.append(cti); if results == []: if not intensities is None: return (numpy.zeros((0,3)), numpy.zeros((0))); else: return numpy.zeros((0,3)) else: points = numpy.concatenate(results); if shiftPoints: points = points + io.pointShiftFromRange(io.dataSize(subStacks[0]["source"]), x = subStacks[0]["x"], y = subStacks[0]["y"], z = 0); else: points = points - io.pointShiftFromRange(io.dataSize(subStacks[0]["source"]), x = 0, y = 0, z = subStacks[0]["z"]); #absolute offset is added initially via zranges ! if intensities is None: return points; else: return (points, numpy.concatenate(resultsi));
def voxelizePixel(points, dataSize = None, weights = None): """Mark pixels/voxels of each point in an image array Arguments: points (array): point data array dataSize (tuple or None): size of the final output data, if None size is determined by maximal point coordinates weights (array or None): weights for each points, if None weights are all 1s. Returns: (array): volumetric data with with points marked in voxels """ if dataSize is None: dataSize = tuple(int(math.ceil(points[:,i].max())) for i in range(points.shape[1])); elif isinstance(dataSize, basestring): dataSize = io.dataSize(dataSize); if weights is None: vox = numpy.zeros(dataSize, dtype=numpy.int16); for i in range(points.shape[0]): if points[i,0] > 0 and points[i,0] < dataSize[0] and points[i,1] > 0 and points[i,1] < dataSize[1] and points[i,2] > 0 and points[i,2] < dataSize[2]: vox[points[i,0], points[i,1], points[i,2]] += 1; else: vox = numpy.zeros(dataSize, dtype=weights.dtype); for i in range(points.shape[0]): if points[i,0] > 0 and points[i,0] < dataSize[0] and points[i,1] > 0 and points[i,1] < dataSize[1] and points[i,2] > 0 and points[i,2] < dataSize[2]: vox[points[i,0], points[i,1], points[i,2]] += weights[i]; return vox;
def voxelizePixel(points, dataSize=None, weights=None): """Mark pixels/voxels of each point in an image array Arguments: points (array): point data array dataSize (tuple or None): size of the final output data, if None size is determined by maximal point coordinates weights (array or None): weights for each points, if None weights are all 1s. Returns: (array): volumetric data with with points marked in voxels """ if dataSize is None: dataSize = tuple( int(math.ceil(points[:, i].max())) for i in range(points.shape[1])) elif isinstance(dataSize, basestring): dataSize = io.dataSize(dataSize) if weights is None: vox = numpy.zeros(dataSize, dtype=numpy.int16) for i in range(points.shape[0]): if points[i, 0] > 0 and points[i, 0] < dataSize[0] and points[ i, 1] > 0 and points[i, 1] < dataSize[1] and points[ i, 2] > 0 and points[i, 2] < dataSize[2]: vox[points[i, 0], points[i, 1], points[i, 2]] += 1 else: vox = numpy.zeros(dataSize, dtype=weights.dtype) for i in range(points.shape[0]): if points[i, 0] > 0 and points[i, 0] < dataSize[0] and points[ i, 1] > 0 and points[i, 1] < dataSize[1] and points[ i, 2] > 0 and points[i, 2] < dataSize[2]: vox[points[i, 0], points[i, 1], points[i, 2]] += weights[i] return vox
def test(): import os; import ClearMap.IO as io import ClearMap.Settings as settings import ClearMap.ImageProcessing.Ilastik as il; reload(il); ilp = os.path.join(settings.ClearMapPath, 'Test/Ilastik/Test.ilp') src = os.path.join(settings.ClearMapPath, 'Test/Data/ImageAnalysis/cfos-substack.tif'); #out = os.path.join(settings.ClearMapPath, 'Test/Data/Ilastik/image.npy'); out = None; #out = os.path.join(settings.ClearMapPath, 'Test/Data/Ilastik/result\d*.tif'); cls = il.classifyPixel(ilp, src, out); print io.dataSize(src) print cls.shape io.writeData('/home/ckirst/result.raw', cls);
def test(): import os import ClearMap.IO as io import ClearMap.Settings as settings import ClearMap.ImageProcessing.Ilastik as il reload(il) ilp = os.path.join(settings.ClearMapPath, 'Test/Ilastik/Test.ilp') src = os.path.join(settings.ClearMapPath, 'Test/Data/ImageAnalysis/cfos-substack.tif') #out = os.path.join(settings.ClearMapPath, 'Test/Data/Ilastik/image.npy'); out = None #out = os.path.join(settings.ClearMapPath, 'Test/Data/Ilastik/result\d*.tif'); cls = il.classifyPixel(ilp, src, out) print io.dataSize(src) print cls.shape io.writeData('/home/ckirst/result.raw', cls)
def calculateSubStacks(source, z = all, x = all, y = all, **args): """Calculates the chunksize and other info for parallel processing and returns a list of sub-stack objects The sub-stack information is described in :ref:`SubStack` Arguments: source (str): image source x,y,z (tuple or all): range specifications processes (int): number of parallel processes chunkSizeMax (int): maximal size of a sub-stack chunkSizeMin (int): minial size of a sub-stack chunkOverlap (int): minimal sub-stack overlap chunkOptimization (bool): optimize chunck sizes to best fit number of processes chunkOptimizationSize (bool or all): if True only decrease the chunk size when optimizing verbose (bool): print information on sub-stack generation Returns: list: list of sub-stack objects """ #determine z ranges fs = io.dataSize(source); zs = fs[2]; zr = io.toDataRange(zs, r = z); nz = zr[1] - zr[0]; #calculate optimal chunk sizes nchunks, zranges, zcenters = calculateChunkSize(nz, **args); #adjust for the zrange zcenters = [c + zr[0] for c in zcenters]; zranges = [(zc[0] + zr[0], zc[1] + zr[0]) for zc in zranges]; #create substacks subStacks = []; indexlo = zr[0]; for i in range(nchunks): indexhi = int(round(zcenters[i+1])); if indexhi > zr[1] or i == nchunks - 1: indexhi = zr[1]; zs = zranges[i][1] - zranges[i][0]; subStacks.append({"stackId" : i, "nStacks" : nchunks, "source" : source, "x" : x, "y" : y, "z" : zranges[i], "zCenters" : (zcenters[i], zcenters[i+1]), "zCenterIndices" : (indexlo, indexhi), "zSubStackCenterIndices" : (indexlo - zranges[i][0], zs - (zranges[i][1] - indexhi))}); indexlo = indexhi; # + 1; return subStacks;
def openData(dataSource, x = all, y = all, z = all, inverse = False, cleanUp = True): """Open image in ImageJ Arguments: dataSouce (str or array): volumetric image data x, y, z (all or tuple): sub-range specification inverse (bool):invert image Returns: (object): figure handle """ checkImageJInitialized(); if isinstance(dataSource, numpy.ndarray): filename = tempfile.mktemp(suffix = '.mhd', prefix = 'CM_ImageJ'); io.writeData(filename, dataSource, x = x, y = y, z = z); temp= True dSize = dataSource.shape; else: filename = dataSource; temp = False; dSize = io.dataSize(dataSource); colorImage = len(dSize) == 4; if colorImage: macro = ('open("%s"); ' % filename) + \ 'run("Stack to Hyperstack...", "order=xyzct channels=%d slices=%d frames=1 display=Color"); ' % (dSize[3], dSize[2]) + \ 'Stack.setDisplayMode("composite");'; else: macro = ('open("%s");' % filename); cmd = ImageJBinary + " -eval '%s'" % macro; print 'running: %s' % cmd res = os.system(cmd); if res != 0: raise RuntimeError('openData: failed executing: ' + cmd); if cleanUp and temp: os.remove(filename); filepath, imagename = os.path.split(filename); imagename = imagename[:-4] + '.raw'; os.remove(os.path.join(filepath, imagename)); return macro;
def testCompletedCumulativesInSpheres(points1, intensities1, points2, intensities2, dataSize = lbl.DefaultLabeledImageFile, radius = 100, method = 'AndresonDarling'): """Performs completed cumulative distribution tests for each pixel using points in a ball centered at that cooridnates, returns 4 arrays p value, statistic value, number in each group""" #TODO: sinple implementation -> slow -> speed up dataSize = io.dataSize(dataSize); if len(dataSize) != 3: raise RuntimeError('dataSize expected to be 3d'); # distances^2 to origin x1= points1[:,0]; y1 = points1[:,1]; z1 = points1[:,2]; i1 = intensities1; d1 = x1 * x1 + y1 * y1 + z1 * z1; x2 = points2[:,0]; y2 = points2[:,1]; z2 = points2[:,2]; i2 = intensities2; d2 = x2 * x2 + y2 * y2 + z2 * z2; r2 = radius * radius; # TODO: inhomogenous in 3d ! p = numpy.zeros(dataSize); s = numpy.zeros(dataSize); n1 = numpy.zeros(dataSize, dtype = 'int'); n2 = numpy.zeros(dataSize, dtype = 'int'); for x in range(dataSize[0]): #print x for y in range(dataSize[1]): #print y for z in range(dataSize[2]): #print z d11 = d1 - 2 * (x * x1 + y * y1 + z * z1) + (x*x + y*y + z*z); d22 = d2 - 2 * (x * x2 + y * y2 + z * z2) + (x*x + y*y + z*z); ii1 = d11 < r2; ii2 = d22 < r2; n1[x,y,z] = ii1.sum(); n2[x,y,z] = ii2.sum(); if n1[x,y,z] > 0 and n2[x,y,z] > 0: (pp, ss) = self.testCompletedCumulatives((i1[ii1], i2[ii2]), method = method); else: pp = 0; ss = 0; p[x,y,z] = pp; s[x,y,z] = ss; return (p,s,n1,n2);
def voxelize(points, dataSize = None, sink = None, voxelizeParameter = None, method = 'Spherical', size = (5,5,5), weights = None): """Converts a list of points into an volumetric image array Arguments: points (array): point data array dataSize (tuple): size of final image sink (str, array or None): the location to write or return the resulting voxelization image, if None return array voxelizeParameter (dict): ========== ==================== =========================================================== Name Type Descritption ========== ==================== =========================================================== *method* (str or None) method for voxelization: 'Spherical', 'Rectangular' or 'Pixel' *size* (tuple) size parameter for the voxelization *weights* (array or None) weights for each point, None is uniform weights ========== ==================== =========================================================== Returns: (array): volumetric data of smeared out points """ if dataSize is None: dataSize = tuple(int(math.ceil(points[:,i].max())) for i in range(points.shape[1])); elif isinstance(dataSize, basestring): dataSize = io.dataSize(dataSize); points = io.readPoints(points); if method.lower() == 'spherical': if weights is None: data = vox.voxelizeSphere(points.astype('float'), dataSize[0], dataSize[1], dataSize[2], size[0], size[1], size[2]); else: data = vox.voxelizeSphereWithWeights(points.astype('float'), dataSize[0], dataSize[1], dataSize[2], size[0], size[1], size[2], weights); elif method.lower() == 'rectangular': if weights is None: data = vox.voxelizeRectangle(points.astype('float'), dataSize[0], dataSize[1], dataSize[2], size[0], size[1], size[2]); else: data = vox.voxelizeRectangleWithWeights(points.astype('float'), dataSize[0], dataSize[1], dataSize[2], size[0], size[1], size[2], weights); elif method.lower() == 'pixel': data = voxelizePixel(points, dataSize, weights); else: raise RuntimeError('voxelize: mode: %s not supported!' % method); return io.writeData(sink, data);
def dataSize(filename, **args): """Returns size of data stored as a file list Arguments: filename (str): file name as regular expression x,y,z (tuple): data range specifications Returns: tuple: data size """ fp, fl = readFileList(filename) nz = len(fl) d2 = io.dataSize(os.path.join(fp, fl[0])) if not len(d2) == 2: raise RuntimeError("FileList: importing multiple files of dim %d not supported!" % len(d2)) dims = d2 + (nz,) return io.dataSizeFromDataRange(dims, **args)
def dataSize(filename, **args): """Returns size of data stored as a file list Arguments: filename (str): file name as regular expression x,y,z (tuple): data range specifications Returns: tuple: data size """ fp, fl = readFileList(filename) nz = len(fl) d2 = io.dataSize(os.path.join(fp, fl[0])) if not len(d2) == 2: raise RuntimeError( "FileList: importing multiple files of dim %d not supported!" % len(d2)) dims = d2 + (nz, ) return io.dataSizeFromDataRange(dims, **args)
datadir ='/home/mtllab/Documents/th/'; fn = os.path.join(datadir, r'160412_mosaic_15-20-19/15-20-19_mosaic_UltraII\[(?P<row>\d{2}) x (?P<col>\d{2})\]_C00_xyz-Table Z(?P<z>\d{4}).ome.tif') _, gr = st.findFileList(fn , sort = True, groups = ['row','col'], absolute = True) groups = []; for i in range(gr.shape[1]): groups.append(np.unique(gr[:,i])); print groups for i in groups[0]: for j in groups[1]: fileExpression = os.path.join(datadir, r'160412_mosaic_15-20-19/15-20-19_mosaic_UltraII\[%s x %s]_C00_xyz-Table Z\d{4}.ome.tif' % (i,j)) io.dataSize(fileExpression) io.readMetaData(fileExpression, info = ['size', 'overlap', 'resolution']) import ClearMap.IO.FileList as fl; reload(fl) fncrop = os.path.join(datadir, r'cropped/15-20-19_mosaic_UltraII_%s_x_%s_C00_xyz-Table Z\d{4}.ome.tif' % (i,j)) fc = fl.cropData(fileExpression, fncrop, x = (400, -400), y = (550, -550), adjustOverlap = True, processes = all) #fc1 = fl.firstFile(fc) #io.readMetaData(fc1, info = ['overlap', 'resolution', 'size']);
def findFileInfo(filename): """Tries to infer relevant information from filename for tiling / stitching Arguments: filename (str): filename to infer information from Returns: dict: dictionary with relavant information: resolution (microns per pixel), overlap (microns), size (pixel) Note: resolution is in microns per pixel, overlap is in microns and size is in pixel """ # TODO: move this to the individual file readers # this is for ome tif images from PIL import Image from PIL.ExifTags import TAGS def ome_info(fn): ret = {} i = Image.open(fn) info = i.tag.as_dict() for tag, value in info.iteritems(): decoded = TAGS.get(tag) ret[decoded] = value return ret imginfo = ome_info(filename) keys = imginfo.keys() finfo = {"resolution": None, "overlap": None, "size": None} # get image sizes if ("ImageHeight" in keys) and ("ImageWidth" in keys): finfo["size"] = (imginfo["ImageWidth"], imginfo["ImageHeight"]) else: finfo["size"] = io.dataSize(filename) if "ImageDescription" in keys: imgxml = imginfo["ImageDescription"] if isinstance(imgxml, tuple): imgxml = imgxml[0] imgxml = etree.fromstring(str(imgxml)) # get resolution pix = [x for x in imgxml.iter("{*}Pixels")] if len(pix) > 0: pix = pix[0].attrib keys = pix.keys() if "PhysicalSizeX" in keys and "PhysicalSizeY" in keys and "PhysicalSizeZ" in keys: finfo["resolution"] = ( float(pix["PhysicalSizeX"]), float(pix["PhysicalSizeY"]), float(pix["PhysicalSizeZ"]), ) # get overlap e1 = [x for x in imgxml.iter("{*}xyz-Table_X_Overlap")] e2 = [x for x in imgxml.iter("{*}xyz-Table_Y_Overlap")] if len(e1) > 0 and len(e2) > 0: finfo["overlap"] = (float(e1[0].attrib["Value"]), float(e2[0].attrib["Value"])) return finfo
def correctIllumination(img, correctIlluminationParameter = None, flatfield = None, background = None, scaling = None, save = None, verbose = False, subStack = None, out = sys.stdout, **parameter): """Correct illumination variations The intensity image :math:`I(x)` given a flat field :math:`F(x)` and a background :math:`B(x)` the image is corrected to :math:`C(x)` as: .. math: C(x) = \\frac{I(x) - B(x)}{F(x) - B(x)} If the background is not given :math:`B(x) = 0`. The correction is done slice by slice assuming the data was collected with a light sheet microscope. The image is finally optionally scaled. Arguments: img (array): image data findCenterOfMaximaParameter (dict): ============ ==================== =========================================================== Name Type Descritption ============ ==================== =========================================================== *flatfield* (str, None or array) flat field intensities, if None d onot correct image for illumination, if True the *background* (str, None or array) background image as file name or array if None background is assumed to be zero *scaling* (str or None) scale the corrected result by this factor if 'max'/'mean' scale to keep max/mean invariant *save* (str or None) save the corrected image to file *verbose* (bool or int) print / plot information about this step ============ ==================== =========================================================== subStack (dict or None): sub-stack information verbose (bool): print progress info out (object): object to write progress info to Returns: array: illumination corrected image References: Fundamentals of Light Microscopy and Electronic Imaging, p 421 See Also: :const:`DefaultFlatFieldLineFile` """ flatfield = getParameter(correctIlluminationParameter, "flatfield", flatfield); background = getParameter(correctIlluminationParameter, "background", background); scaling = getParameter(correctIlluminationParameter, "scaling", scaling); save = getParameter(correctIlluminationParameter, "save", save); verbose = getParameter(correctIlluminationParameter, "verbose", verbose); if verbose: if flatfield is None or isinstance(flatfield, str) or flatfield is True: fld = flatfield; else: fld = "image of size %s" % str(flatfield.shape); if background is None or isinstance(background, str): bkg = background; else: bkg = "image of size %s" % str(background.shape); writeParameter(out = out, head = 'Illumination correction:', flatfield = fld, background = bkg, scaling = scaling, save = save); print subStack; if not subStack is None: x = subStack["x"]; y = subStack["y"]; else: x = all; y = all; #print "sizes", x, y, img.shape #read data timer = Timer(); if flatfield is None: return img; elif flatfield is True: # default flatfield correction if subStack is None: flatfield = flatfieldFromLine(DefaultFlatFieldLineFile, img.shape[0]); else: dataSize = io.dataSize(subStack["source"]); flatfield = flatfieldFromLine(DefaultFlatFieldLineFile, dataSize[0]); elif isinstance(flatfield, str): # point or image file if io.isPointFile(flatfield): if subStack is None: flatfield = flatfieldFromLine(flatfield, img.shape[0]); else: dataSize = io.dataSize(subStack["source"]); flatfield = flatfieldFromLine(flatfield, dataSize[0]); else: flatfield = io.readData(flatfield); ffmean = flatfield.mean(); ffmax = flatfield.max(); #correct for subset flatfield = io.readData(flatfield, x = x, y = y); background = io.readData(background, x = x, y = y); if flatfield.shape != img[:,:,0].shape: raise RuntimeError("correctIllumination: flatfield does not match image size: %s vs %s" % (flatfield.shape, img[:,:,0].shape)); #convert to float for scaling dtype = img.dtype; img = img.astype('float32'); flatfield = flatfield.astype('float32'); # illumination correction in each slice if background is None: for z in range(img.shape[2]): img[:,:,z] = img[:,:,z] / flatfield; else: if background.shape != flatfield.shape: raise RuntimeError("correctIllumination: background does not match image size: %s vs %s" % (background.shape, img[:,:,0].shape)); background = background.astype('float32'); flatfield = (flatfield - background); for z in range(img.shape[2]): img[:,:,z] = (img[:,:,z] - background) / flatfield; # rescale if scaling is True: scaling = "mean"; if isinstance(scaling, str): if scaling.lower() == "mean": # scale back by average flat field correction: sf = ffmean; elif scaling.lower() == "max": sf = ffmax; else: raise RuntimeError('Scaling not "Max" or "Mean" but %s' % scaling); else: sf = scaling; if verbose: writeParameter(out = out, head = 'Illumination correction:', scaling = sf); if not sf is None: img = img * sf; img = img.astype(dtype); #write result for inspection if not save is None: writeSubStack(save, img, subStack = subStack); #plot result for inspection if verbose > 1: plotTiling(img); if verbose: out.write(timer.elapsedTime(head = 'Illumination correction') + '\n'); return img
def correctIllumination(img, correctIlluminationParameter=None, flatfield=None, background=None, scaling=None, save=None, verbose=False, subStack=None, out=sys.stdout, **parameter): """Correct illumination variations The intensity image :math:`I(x)` given a flat field :math:`F(x)` and a background :math:`B(x)` the image is corrected to :math:`C(x)` as: .. math: C(x) = \\frac{I(x) - B(x)}{F(x) - B(x)} If the background is not given :math:`B(x) = 0`. The correction is done slice by slice assuming the data was collected with a light sheet microscope. The image is finally optionally scaled. Arguments: img (array): image data findCenterOfMaximaParameter (dict): ============ ==================== =========================================================== Name Type Descritption ============ ==================== =========================================================== *flatfield* (str, None or array) flat field intensities, if None d onot correct image for illumination, if True the *background* (str, None or array) background image as file name or array if None background is assumed to be zero *scaling* (str or None) scale the corrected result by this factor if 'max'/'mean' scale to keep max/mean invariant *save* (str or None) save the corrected image to file *verbose* (bool or int) print / plot information about this step ============ ==================== =========================================================== subStack (dict or None): sub-stack information verbose (bool): print progress info out (object): object to write progress info to Returns: array: illumination corrected image References: Fundamentals of Light Microscopy and Electronic Imaging, p 421 See Also: :const:`DefaultFlatFieldLineFile` """ flatfield = getParameter(correctIlluminationParameter, "flatfield", flatfield) background = getParameter(correctIlluminationParameter, "background", background) scaling = getParameter(correctIlluminationParameter, "scaling", scaling) save = getParameter(correctIlluminationParameter, "save", save) verbose = getParameter(correctIlluminationParameter, "verbose", verbose) if verbose: if flatfield is None or isinstance(flatfield, str) or flatfield is True: fld = flatfield else: fld = "image of size %s" % str(flatfield.shape) if background is None or isinstance(background, str): bkg = background else: bkg = "image of size %s" % str(background.shape) writeParameter(out=out, head='Illumination correction:', flatfield=fld, background=bkg, scaling=scaling, save=save) print subStack if not subStack is None: x = subStack["x"] y = subStack["y"] else: x = all y = all #print "sizes", x, y, img.shape #read data timer = Timer() if flatfield is None: return img elif flatfield is True: # default flatfield correction if subStack is None: flatfield = flatfieldFromLine(DefaultFlatFieldLineFile, img.shape[0]) else: dataSize = io.dataSize(subStack["source"]) flatfield = flatfieldFromLine(DefaultFlatFieldLineFile, dataSize[0]) elif isinstance(flatfield, str): # point or image file if io.isPointFile(flatfield): if subStack is None: flatfield = flatfieldFromLine(flatfield, img.shape[0]) else: dataSize = io.dataSize(subStack["source"]) flatfield = flatfieldFromLine(flatfield, dataSize[0]) else: flatfield = io.readData(flatfield) ffmean = flatfield.mean() ffmax = flatfield.max() #correct for subset flatfield = io.readData(flatfield, x=x, y=y) background = io.readData(background, x=x, y=y) if flatfield.shape != img[:, :, 0].shape: raise RuntimeError( "correctIllumination: flatfield does not match image size: %s vs %s" % (flatfield.shape, img[:, :, 0].shape)) #convert to float for scaling dtype = img.dtype img = img.astype('float32') flatfield = flatfield.astype('float32') # illumination correction in each slice if background is None: for z in range(img.shape[2]): img[:, :, z] = img[:, :, z] / flatfield else: if background.shape != flatfield.shape: raise RuntimeError( "correctIllumination: background does not match image size: %s vs %s" % (background.shape, img[:, :, 0].shape)) background = background.astype('float32') flatfield = (flatfield - background) for z in range(img.shape[2]): img[:, :, z] = (img[:, :, z] - background) / flatfield # rescale if scaling is True: scaling = "mean" if isinstance(scaling, str): if scaling.lower() == "mean": # scale back by average flat field correction: sf = ffmean elif scaling.lower() == "max": sf = ffmax else: raise RuntimeError('Scaling not "Max" or "Mean" but %s' % scaling) else: sf = scaling if verbose: writeParameter(out=out, head='Illumination correction:', scaling=sf) if not sf is None: img = img * sf img = img.astype(dtype) #write result for inspection if not save is None: writeSubStack(save, img, subStack=subStack) #plot result for inspection if verbose > 1: plotTiling(img) if verbose: out.write(timer.elapsedTime(head='Illumination correction') + '\n') return img
def cropData(source, sink=None, x=all, y=all, z=all, adjustOverlap=False, verbose=True, processes=all): """Crop source from start to stop point Arguments: source (str or array): filename or data array of source sink (str or None): filename or sink x,y,z (tuple or all): the range to crop the data to adjustOverlap (bool): correct overlap meta data if exists Return: str or array: array or filename with cropped data """ if sink is None: return readDataFiles(source, x=x, y=y, z=z) else: # sink assumed to be file expression if not io.isFileExpression(sink): raise RuntimeError("cropping data to different format not supported!") fileheader, fileext, digitfrmt = splitFileExpression(sink) # read first image to get data size and type fp, fl = readFileList(source) nz = len(fl) rz = io.toDataRange(nz, r=z) if adjustOverlap: # change overlap in first file try: fn = os.path.join(fp, fl[0]) info = io.readMetaData(fn, info=["description", "overlap", "resolution"]) description = str(info["description"]) overlap = numpy.array(info["overlap"], dtype=float) resolution = numpy.array(info["resolution"], dtype=float) except: raise RuntimeWarning("could not modify overlap!") fullsize = io.dataSize(fn) data = io.readData(fn, x=x, y=y) # overlap in pixels poverlap = overlap[:2] / resolution[:2] print poverlap # cropped pixel xr = io.toDataRange(fullsize[0], r=x) yr = io.toDataRange(fullsize[1], r=y) print xr print yr print fullsize poverlap[0] = poverlap[0] - xr[0] - (fullsize[0] - xr[1]) poverlap[1] = poverlap[1] - yr[0] - (fullsize[1] - yr[1]) print poverlap # new overlap in microns overlap = poverlap * resolution[:2] # check for consistency if numpy.abs(fullsize[0] - xr[1] - xr[0]) > 1 or numpy.abs(fullsize[1] - yr[1] - yr[0]) > 1: raise RuntimeWarning("cropping is inconsistent with overlap )modification!") # change image description import ClearMap.IO.TIF as CMTIF description = CMTIF.changeOMEMetaDataString(description, {"overlap": overlap}) print len(description) # write first file fnout = fileheader + (digitfrmt % 0) + fileext io.writeData(fnout, data, info=description) zr = range(rz[0] + 1, rz[1]) else: zr = range(rz[0], rz[1]) print zr nZ = len(zr) if processes is None: processes = 1 if processes is all: processes = multiprocessing.cpu_count() if processes > 1: # parallel processing pool = multiprocessing.Pool(processes=processes) argdata = [] for i, z in enumerate(zr): if verbose: argdata.append( (os.path.join(fp, fl[z]), fileheader + (digitfrmt % (i + 1)) + fileext, x, y, (i + 1), (nZ + 1)) ) else: argdata.append( (os.path.join(fp, fl[z]), fileheader + (digitfrmt % (i + 1)) + fileext, x, y, None, None) ) pool.map(_cropParallel, argdata) else: # sequential processing for i, z in enumerate(zr): if verbose: print "cropData: corpping image %d / %d" % (i + 1, nZ + 1) fileSource = os.path.join(fp, fl[z]) data = io.readData(fileSource, x=x, y=y) fileSink = fileheader + (digitfrmt % (i + 1)) + fileext io.writeData(fileSink, data) return sink