def _test(): """Tests for the Resampling Module""" import ClearMap.Alignment.Resampling as self reload(self) from ClearMap.Settings import ClearMapPath as basedir import iDISCO.IO.IO as io import os, numpy fn = os.path.join( basedir, 'Test/Data/OME/16-17-27_0_8X-s3-20HF_UltraII_C00_xyz-Table Z\d{4}.ome.tif' ) outfn = os.path.join(basedir, "Test/Data/Resampling/test.mhd") print "Making resampled stack " + outfn print "source datasize %s" % str(io.dataSize(fn)) data = self.resampleData(fn, sink=None, resolutionSource=(1, 1, 1), orientation=(1, 2, 3), resolutionSink=(10, 10, 2)) print data.shape io.writeData(outfn, data) data = self.resampleData(fn, sink=None, dataSizeSink=(50, 70, 10), orientation=(1, 2, 3)) print data.shape io.writeData(outfn, data) dataSizeSource, dataSizeSink, resolutionSource, resolutionSink = self.resampleDataSize( dataSizeSource=(100, 200, 303), dataSizeSink=None, resolutionSource=(1, 1, 1), resolutionSink=(5, 5, 5), orientation=(1, 2, 3)) print dataSizeSource, dataSizeSink, resolutionSource, resolutionSink points = numpy.array([[0, 0, 0], [1, 1, 1], io.dataSize(fn)]) points = points.astype('float') pr = self.resamplePoints(points, dataSizeSource=fn, dataSizeSink=(50, 70, 10), orientation=(1, 2, 3)) print pr pri = self.resamplePointsInverse(pr, dataSizeSource=fn, dataSizeSink=(50, 70, 10), orientation=(-1, 2, 3)) print pri result = self.resampleDataInverse( outfn, os.path.join(basedir, 'Test/Data/OME/resample_\d{4}.ome.tif'), dataSizeSource=fn) print result
def voxelizeOrientations(points, orientations, dataSize=None, sink=None, size=(5, 5, 5), weights=None): """Converts a list of points into an volumetric image array Arguments: points (array): point data array orientations (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 Returns: (array): volumetric data of orientation statistics """ if dataSize is None: dataSize = tuple( int(math.ceil(points[:, i].max())) for i in range(points.shape[1])) elif isinstance(dataSize, str): dataSize = io.dataSize(dataSize) if weights is not None: orts = (orientations.T * weights).T else: orts = orientations data = orc.voxelizeOrientations(points, orts, dataSize[0], dataSize[1], dataSize[2], size[0], size[1], size[2]) return data
def _test(): """Tests for the Resampling Module""" import ClearMap.Alignment.Resampling as self reload(self) from ClearMap.Settings import ClearMapPath as basedir import iDISCO.IO.IO as io import os, numpy fn = os.path.join(basedir, 'Test/Data/OME/16-17-27_0_8X-s3-20HF_UltraII_C00_xyz-Table Z\d{4}.ome.tif'); outfn = os.path.join(basedir, "Test/Data/Resampling/test.mhd") print "Making resampled stack " + outfn print "source datasize %s" % str(io.dataSize(fn)); data = self.resampleData(fn, sink = None, resolutionSource = (1,1,1), orientation = (1,2,3), resolutionSink = (10,10,2)); print data.shape io.writeData(outfn, data) data = self.resampleData(fn, sink = None, dataSizeSink = (50,70,10), orientation = (1,2,3)); print data.shape io.writeData(outfn, data) dataSizeSource, dataSizeSink, resolutionSource, resolutionSink = self.resampleDataSize(dataSizeSource = (100,200, 303), dataSizeSink = None, resolutionSource = (1,1,1), resolutionSink = (5,5,5), orientation = (1,2,3)); print dataSizeSource, dataSizeSink, resolutionSource, resolutionSink points = numpy.array([[0,0,0], [1,1,1], io.dataSize(fn)]); points = points.astype('float') pr = self.resamplePoints(points, dataSizeSource = fn, dataSizeSink = (50,70,10), orientation = (1,2,3)) print pr pri = self.resamplePointsInverse(pr, dataSizeSource = fn, dataSizeSink = (50,70,10), orientation = (-1,2,3)) print pri result = self.resampleDataInverse(outfn, os.path.join(basedir, 'Test/Data/OME/resample_\d{4}.ome.tif'), dataSizeSource = fn); print result
def resamplePointsInverse(pointSource, pointSink=None, dataSizeSource=None, dataSizeSink=None, orientation=None, resolutionSource=(4.0625, 4.0625, 3), resolutionSink=(25, 25, 25), **args): """Resample points from the coordinates of the resampled image to the original data The resampling of points here corresponds to he resampling of an image in :func:`resampleDataInverse` Arguments: pointSource (str or array): image to be resampled pointSink (str or None): destination of resampled image orientation (tuple): orientation specified by permuation and change in sign of (1,2,3) dataSizeSource (str, tuple or None): size of the data source dataSizeSink (str, tuple or None): target size of the resampled image resolutionSource (tuple): resolution of the source image (in length per pixel) resolutionSink (tuple): resolution of the resampled image (in length per pixel) Returns: (array or str): data or file name of inversely resampled points Notes: * resolutions are assumed to be given for the axes of the intrinsic orientation of the data and reference as when viewed by matplotlib or ImageJ * orientation: permuation of 1,2,3 with potential sign, indicating which axes map onto the reference axes, a negative sign indicates reversal of that particular axes * only a minimal set of information to detremine the resampling parameter has to be given, e.g. dataSizeSource and dataSizeSink """ orientation = fixOrientation(orientation) #datasize of data source if isinstance(dataSizeSource, basestring): dataSizeSource = io.dataSize(dataSizeSource) dataSizeSource, dataSizeSink, resolutionSource, resolutionSink = resampleDataSize( dataSizeSource=dataSizeSource, dataSizeSink=dataSizeSink, resolutionSource=resolutionSource, resolutionSink=resolutionSink, orientation=orientation) points = io.readPoints(pointSource) dataSizeSinkI = orientDataSizeInverse(dataSizeSink, orientation) #resolutionSinkI = orientResolutionInverse(resolutionSink, orientation); #scaling factors scale = [ float(dataSizeSource[i]) / float(dataSizeSinkI[i]) for i in range(3) ] #print scale rpoints = points.copy() #invert axis inversion and permutations if not orientation is None: #invert permuation iorientation = inverseOrientation(orientation) per = orientationToPermuation(iorientation) rpoints = rpoints[:, per] for i in range(3): if iorientation[i] < 0: rpoints[:, i] = dataSizeSinkI[i] - rpoints[:, i] #scale points for i in range(3): rpoints[:, i] = rpoints[:, i] * scale[i] return io.writePoints(pointSink, rpoints)
def resampleDataInverse(sink, source=None, dataSizeSource=None, orientation=None, resolutionSource=(4.0625, 4.0625, 3), resolutionSink=(25, 25, 25), processingDirectory=None, processes=1, cleanup=True, verbose=True, interpolation='linear', **args): """Resample data inversely to :func:`resampleData` routine Arguments: sink (str or None): image to be inversly resampled (=sink in :func:`resampleData`) source (str or array): destination for inversly resmapled image (=source in :func:`resampleData`) dataSizeSource (tuple or None): target size of the resampled image orientation (tuple): orientation specified by permuation and change in sign of (1,2,3) resolutionSource (tuple): resolution of the source image (in length per pixel) resolutionSink (tuple): resolution of the resampled image (in length per pixel) processingDirectory (str or None): directory in which to perform resmapling in parallel, None a temporary directry will be created processes (int): number of processes to use for parallel resampling cleanup (bool): remove temporary files verbose (bool): display progress information interpolation (str): method to use for interpolating to the resmapled image Returns: (array or str): data or file name of resampled image Notes: * resolutions are assumed to be given for the axes of the intrinsic orientation of the data and reference as when viewed by matplotlib or ImageJ * orientation: permuation of 1,2,3 with potential sign, indicating which axes map onto the reference axes, a negative sign indicates reversal of that particular axes * only a minimal set of information to detremine the resampling parameter has to be given, e.g. dataSizeSource and dataSizeSink """ #orientation orientation = fixOrientation(orientation) #assume we can read data fully into memory resampledData = io.readData(sink) dataSizeSink = resampledData.shape if isinstance(dataSizeSource, basestring): dataSizeSource = io.dataSize(dataSizeSource) dataSizeSource, dataSizeSink, resolutionSource, resolutionSink = resampleDataSize( dataSizeSource=dataSizeSource, dataSizeSink=dataSizeSink, resolutionSource=resolutionSource, resolutionSink=resolutionSink, orientation=orientation) #print (dataSizeSource, dataSizeSink, resolutionSource, resolutionSink ) dataSizeSinkI = orientDataSizeInverse(dataSizeSink, orientation) #flip axes back and permute inversely if not orientation is None: if orientation[0] < 0: resampledData = resampledData[::-1, :, :] if orientation[1] < 0: resampledData = resampledData[:, ::-1, :] if orientation[2] < 0: resampledData = resampledData[:, :, ::-1] #reorient peri = inverseOrientation(orientation) peri = orientationToPermuation(peri) resampledData = resampledData.transpose(peri) # upscale in z interpolation = fixInterpolation(interpolation) resampledDataXY = numpy.zeros( (dataSizeSinkI[0], dataSizeSinkI[1], dataSizeSource[2]), dtype=resampledData.dtype) for i in range(dataSizeSinkI[0]): if verbose and i % 25 == 0: print "resampleDataInverse: processing %d/%d" % (i, dataSizeSinkI[0]) #cv2.resize takes reverse order of sizes ! resampledDataXY[i, :, :] = cv2.resize( resampledData[i, :, :], (dataSizeSource[2], dataSizeSinkI[1]), interpolation=interpolation) # upscale x, y in parallel if io.isFileExpression(source): files = source else: if processingDirectory == None: processingDirectory = tempfile.mkdtemp() files = os.path.join(sink[0], 'resample_\d{4}.tif') io.writeData(files, resampledDataXY) nZ = dataSizeSource[2] pool = multiprocessing.Pool(processes=processes) argdata = [] for i in range(nZ): argdata.append((source, fl.fileExpressionToFileName(files, i), dataSizeSource, interpolation, i, nZ)) pool.map(_resampleXYParallel, argdata) if io.isFileExpression(source): return source else: data = io.convertData(files, source) if cleanup: shutil.rmtree(processingDirectory) return data
def resampleData(source, sink=None, orientation=None, dataSizeSink=None, resolutionSource=(4.0625, 4.0625, 3), resolutionSink=(25, 25, 25), processingDirectory=None, processes=1, cleanup=True, verbose=True, interpolation='linear', **args): """Resample data of source in resolution and orientation Arguments: source (str or array): image to be resampled sink (str or None): destination of resampled image orientation (tuple): orientation specified by permuation and change in sign of (1,2,3) dataSizeSink (tuple or None): target size of the resampled image resolutionSource (tuple): resolution of the source image (in length per pixel) resolutionSink (tuple): resolution of the resampled image (in length per pixel) processingDirectory (str or None): directory in which to perform resmapling in parallel, None a temporary directry will be created processes (int): number of processes to use for parallel resampling cleanup (bool): remove temporary files verbose (bool): display progress information interpolation (str): method to use for interpolating to the resmapled image Returns: (array or str): data or file name of resampled image Notes: * resolutions are assumed to be given for the axes of the intrinsic orientation of the data and reference as when viewed by matplotlib or ImageJ * orientation: permuation of 1,2,3 with potential sign, indicating which axes map onto the reference axes, a negative sign indicates reversal of that particular axes * only a minimal set of information to detremine the resampling parameter has to be given, e.g. dataSizeSource and dataSizeSink """ orientation = fixOrientation(orientation) if isinstance(dataSizeSink, basestring): dataSizeSink = io.dataSize(dataSizeSink) #orient actual resolutions onto reference resolution dataSizeSource = io.dataSize(source) dataSizeSource, dataSizeSink, resolutionSource, resolutionSink = resampleDataSize( dataSizeSource=dataSizeSource, dataSizeSink=dataSizeSink, resolutionSource=resolutionSource, resolutionSink=resolutionSink, orientation=orientation) dataSizeSinkI = orientDataSizeInverse(dataSizeSink, orientation) #print dataSizeSource, dataSizeSink, resolutionSource, resolutionSink, dataSizeSinkI #rescale in x y in parallel if processingDirectory == None: processingDirectory = tempfile.mkdtemp() interpolation = fixInterpolation(interpolation) nZ = dataSizeSource[2] pool = multiprocessing.Pool(processes=processes) argdata = [] for i in range(nZ): argdata.append( (source, os.path.join(processingDirectory, 'resample_%04d.tif' % i), dataSizeSinkI, interpolation, i, nZ, verbose)) #print argdata[i] pool.map(_resampleXYParallel, argdata) #rescale in z fn = os.path.join(processingDirectory, 'resample_%04d.tif' % 0) data = io.readData(fn) zImage = numpy.zeros((dataSizeSinkI[0], dataSizeSinkI[1], nZ), dtype=data.dtype) for i in range(nZ): if verbose and i % 10 == 0: print "resampleData; reading %d/%d" % (i, nZ) fn = os.path.join(processingDirectory, 'resample_%04d.tif' % i) zImage[:, :, i] = io.readData(fn) resampledData = numpy.zeros(dataSizeSinkI, dtype=zImage.dtype) for i in range(dataSizeSinkI[0]): if verbose and i % 25 == 0: print "resampleData: processing %d/%d" % (i, dataSizeSinkI[0]) #resampledImage[:, iImage ,:] = scipy.misc.imresize(zImage[:,iImage,:], [resizedZAxisSize, sagittalImageSize[1]] , interp = 'bilinear'); #cv2.resize takes reverse order of sizes ! resampledData[i, :, :] = cv2.resize( zImage[i, :, :], (dataSizeSinkI[2], dataSizeSinkI[1]), interpolation=interpolation) #resampledData[i ,:, :] = cv2.resize(zImage[i,:, :], (dataSize[1], resizedZSize)); #account for using (z,y,x) array representation -> (y,x,z) #resampledData = resampledData.transpose([1,2,0]); #resampledData = resampledData.transpose([2,1,0]); if cleanup: shutil.rmtree(processingDirectory) if not orientation is None: #reorient per = orientationToPermuation(orientation) resampledData = resampledData.transpose(per) #reverse orientation after permuting e.g. (-2,1) brings axis 2 to first axis and we can reorder there if orientation[0] < 0: resampledData = resampledData[::-1, :, :] if orientation[1] < 0: resampledData = resampledData[:, ::-1, :] if orientation[2] < 0: resampledData = resampledData[:, :, ::-1] #bring back from y,x,z to z,y,x #resampledImage = resampledImage.transpose([2,0,1]); if verbose: print "resampleData: resampled data size: " + str(resampledData.shape) if sink == []: if io.isFileExpression(source): sink = os.path.split(source) sink = os.path.join(sink[0], 'resample_\d{4}.tif') elif isinstance(source, basestring): sink = source + '_resample.tif' else: raise RuntimeError( 'resampleData: automatic sink naming not supported for non string source!' ) return io.writeData(sink, resampledData)
def xmlImportFile(regularExpression, size = None, overlap = None, addOverlap = 0, origin = None, resolution = None, tiling = None, tileExpression = None, zRange = None, xmlImportFile = None, asString = False): """Creates the xml import file for TeraStitcher from a directory of image files and optional additional information Arguments: regularExpression (string): base directory or regular expression to infer the tiled image data, in the latter case use group names names 'col' and 'row' for the tile indices and 'z' for the z-plane indices size (tuple or None): volume size in pixel if None inferred from meta data overlap (tuple or None): the (x,y) overlap of the tiles in pixel, if None try to find info from metadata addOverlapp (tuple): additional overlap in pixel to increase posssible search radius origin (tuple or None): the origin of the image, if None then the tpypical value (0.0,0.0,0.0). resolution (tupl0 or None): the (x,y,z) resolution of the image in microns per pixel, if None try to find info from metadata tiling (tuple or None): the (row,col) tiling dimensions, if None infer from 'row' and 'col' groups in regularExpression tileExpression (function or None): a function of (col,row) that returns a regular expression for the images in the (col,row) tile or None if that tile is missing, if None use the regular expression row and col group info zRange (function or None. all): a function of (col,row) that returns a the z range specifications for the (col,row) tile if None use the regular expression z group to infer this from first tile, if all infer this in detail for all tiles xmlImportFile (string or None): filename for the xml import file, if None return the xml tree, if all create 'TreaStitcher_import.xml' file in base directory asString (bool): if True return xml code as string, otherwise return as a xml tree Returns: string: filename of the xml import file Note: Example for a regular expression: r'/path/to/image/image_(?P<row>\d{2})_(?P<col>\d{2})_(?P<z>\d{4}).tif' See also: :func:`importData` """ ## origin if origin is None: origin = (0,0,0); #infer size, resolution and overlap if size is None or resolution is None or overlap is None: firstFile = findFirstFile(regularExpression); finfo = findFileInfo(firstFile); if size is None: size = finfo['size']; if resolution is None: resolution = finfo['resolution']; if overlap is None: overlap = finfo['overlap']; for val, name in zip([size, overlap, resolution],['size', 'overlap', 'resolution']) : if val is None: raise RuntimeError('cannot determine %s from file or input!' % name); if tiling is None or zRange is None or zRange is all: #infer tiling from regular expression #find file: fns, ids = findFileList(regularExpression, groups = ('row', 'col', 'z')); fsize = io.dataSize(fns[0]); dim = len(fsize); #print fns #print ids ids = np.array(ids); # get rid of invalid labels b = np.zeros(ids.shape[0], dtype = bool); for i in range(5 - dim): b = np.logical_or(b, np.equal(ids[:,i], None)) b = np.logical_not(b); fns = fns[b]; ids = ids[b]; if len(fns) == 0: raise RuntimeError('no files found that match the expression %s with row, col and z groups' % regularExpression); # calculate tile dimensions rows = np.unique(ids[:,0]); nrows = len(rows); cols = np.unique(ids[:,1]); ncols = len(cols); if tiling is not None and tiling != (nrows, ncols): raise RuntimeWarning('specified tiling is different from inferred tiling, min tile number will be used !'); tiling = (min(nrows, tiling[0]), min(ncols, tiling[1])); rows = rows[:tiling[0]]; cols = cols[:tiling[1]]; else: tiling = (nrows, ncols); # zRanges if dim == 2: zs = np.unique(ids[:,2]); nzs = len(zs); if zRange is None: zRange = (0, nzs); elif zRange is all: zRange = lambda row,col: (0, np.sum(np.logical_and(ids[:,0] == row, ids[:,1] == col))); else: nzs = fsize[2]; zRange = (0, nzs); else: rows = None; cols = None; fns = None; nzs = 0; for row in range(tiling[0]): for col in range(tiling[1]): nzs = max(nzs, zRange(row,col)[1]); size = tuple(size) + (nzs,); #base directory and tile directories if fns is None: if firstFile is None: fn = findFirstFile(regularExpression, sort = False); else: fn = firstFile; else: fn = fns[0]; fdim = len(io.dataSize(fn)); fnsep = fn.split(os.path.sep); fesep = regularExpression.split(os.path.sep); if len(fnsep) != len(fesep): raise RuntimeError('inconsistent file names and file expression!'); for i in range(len(fnsep)): if fnsep[i] != fesep[i]: baseDirectory = os.path.sep.join(fesep[:i]); regularExpression = os.path.sep.join(fesep[i:]); break; #tileExpression if tileExpression is None: def makeTileExpression(row,col): te = re.sub(r'\(\?\P\<row\>.*?\)', str(row), regularExpression, count = 1); return re.sub(r'\(\?\P\<col\>.*?\)', str(col), te, count = 1); tileExpression = makeTileExpression; elif isinstance(tileExpression, str): tileExpressionString = tileExpression; def makeTileExpression(row,col): te = re.sub(r'\(\?\P\<row\>.*?\)', str(row), tileExpressionString, count = 1); return re.sub(r'\(\?\P\<col\>.*?\)', str(col), te, count = 1); tileExpression = makeTileExpression; # create xml import return xmlImport(baseDirectory, size = size, resolution = resolution, origin = origin, overlap = overlap, addOverlap = addOverlap, tiling = tiling, tileExpression = tileExpression, zRange = zRange, rows = rows, cols = cols, dim = fdim, xmlImportFile = xmlImportFile, asString = asString);
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) Dict = {} for m,n in zip(i.tag.keys(),i.tag.values()) : Dict[m] = n #info = i.tag.as_dict(); for tag, value in Dict.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]; try: imgxml = etree.fromstring(str(imgxml)); except: imgxml = _cleanXML(imgxml); # for large images the TileConfiguration entry is huge and can cause a AttValue error in the xml parser 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 dataViewer(source, axis = None, scale = None): source = io.readData(source); size = io.dataSize(source); size2 = np.array(np.array(size) / 2, dtype = int); order = [0,1,2]; #ImageView expexts z,x,y ordering #order = np.roll(order, -2) source = np.transpose(source, order); dim = len(size); if scale is None: scale = np.ones(dim); else: scale = np.array(scale); assert(len(scale) == dim); #scale = np.roll(scale,-2); if axis is None: axis = 2; orderR = np.roll(order, -axis); sourceR = np.transpose(source, orderR); sizeR = np.roll(size, -axis); scaleR = np.roll(scale,-axis); print sizeR; print scaleR; #axes = ('t', 'x', 'y'); axes = None; percentiles = ([0,5,10,50],[50,90, 95, 100]); precent_id = [1, 2]; # create the gui pg.mkQApp() widget = pg.QtGui.QWidget(); widget.setWindowTitle('Data Viewer'); widget.resize(1000,800) layout = pg.QtGui.QVBoxLayout(); layout.setContentsMargins(0,0,0,0) splitter = pg.QtGui.QSplitter(); splitter.setOrientation(pg.QtCore.Qt.Vertical) splitter.setSizes([int(widget.height()*0.99), int(widget.height()*0.01)]); layout.addWidget(splitter); # Image plot img = pg.ImageView(); img.setImage(sourceR, axes = axes); img.imageItem.setRect(pg.QtCore.QRect(0, 0, sizeR[1] * scaleR[1], sizeR[2] * scaleR[2])) img.view.setXRange(0, sizeR[1] * scaleR[1]); img.view.setYRange(0, sizeR[2] * scaleR[2]); img.setCurrentIndex(size2[axis]); img.ui.histogram.region.setRegion(np.percentile(sourceR[size2[axis]], [percentiles[0][precent_id[0]], percentiles[1][precent_id[1]]])); splitter.addWidget(img); # Tools tools_layout = pg.QtGui.QGridLayout() axis_buttons = []; for d in range(dim): b = pg.QtGui.QPushButton('%d' % (d)); b.setMaximumWidth(100); tools_layout.addWidget(b,0,d); axis_buttons.append(b); adjust_buttons = []; pre = ['Min %d', 'Max %d']; iitem = dim; for r in range(2): adjust_buttons_mm = []; for p in percentiles[r]: b = pg.QtGui.QPushButton(pre[r] % (p)); b.setMaximumWidth(120); tools_layout.addWidget(b,0,iitem); iitem +=1; adjust_buttons_mm.append(b); adjust_buttons.append(adjust_buttons_mm); tools_widget = pg.QtGui.QWidget(); tools_widget.setLayout(tools_layout); splitter.addWidget(tools_widget); widget.setLayout(layout) widget.show(); # Callbacks for handling user interaction def updateAxis(a): axis = a; orderR = np.roll(order, -axis); sourceR = np.transpose(source, orderR); sizeR = np.roll(size, -axis); scaleR = np.roll(scale,-axis); img.setImage(sourceR, axes = axes); img.imageItem.setRect(pg.QtCore.QRect(0, 0, sizeR[1] * scaleR[1], sizeR[2] * scaleR[2])) img.view.setXRange(0, sizeR[1] * scaleR[1]); img.view.setYRange(0, sizeR[2] * scaleR[2]); img.setCurrentIndex(size2[axis]); img.ui.histogram.region.setRegion(np.percentile(sourceR[size2[axis]], [percentiles[0][precent_id[0]], percentiles[1][precent_id[1]]])); for i,ab in enumerate(axis_buttons): ab.clicked.connect(partial(updateAxis, i)); def updateRegion(m,p): precent_id[m] = p; img.ui.histogram.region.setRegion(np.percentile(sourceR[size2[axis]], [percentiles[0][precent_id[0]], percentiles[1][precent_id[1]]])); for m,ab in enumerate(adjust_buttons): for p, abm in enumerate(ab): abm.clicked.connect(partial(updateRegion, m, p)); return widget;
def resamplePointsInverse(pointSource, pointSink = None, dataSizeSource = None, dataSizeSink = None, orientation = None, resolutionSource = (4.0625, 4.0625, 3), resolutionSink = (25, 25, 25), **args): """Resample points from the coordinates of the resampled image to the original data The resampling of points here corresponds to he resampling of an image in :func:`resampleDataInverse` Arguments: pointSource (str or array): image to be resampled pointSink (str or None): destination of resampled image orientation (tuple): orientation specified by permuation and change in sign of (1,2,3) dataSizeSource (str, tuple or None): size of the data source dataSizeSink (str, tuple or None): target size of the resampled image resolutionSource (tuple): resolution of the source image (in length per pixel) resolutionSink (tuple): resolution of the resampled image (in length per pixel) Returns: (array or str): data or file name of inversely resampled points Notes: * resolutions are assumed to be given for the axes of the intrinsic orientation of the data and reference as when viewed by matplotlib or ImageJ * orientation: permuation of 1,2,3 with potential sign, indicating which axes map onto the reference axes, a negative sign indicates reversal of that particular axes * only a minimal set of information to detremine the resampling parameter has to be given, e.g. dataSizeSource and dataSizeSink """ orientation = fixOrientation(orientation); #datasize of data source if isinstance(dataSizeSource, basestring): dataSizeSource = io.dataSize(dataSizeSource); dataSizeSource, dataSizeSink, resolutionSource, resolutionSink = resampleDataSize(dataSizeSource = dataSizeSource, dataSizeSink = dataSizeSink, resolutionSource = resolutionSource, resolutionSink = resolutionSink, orientation = orientation); points = io.readPoints(pointSource); dataSizeSinkI = orientDataSizeInverse(dataSizeSink, orientation); #resolutionSinkI = orientResolutionInverse(resolutionSink, orientation); #scaling factors scale = [float(dataSizeSource[i]) / float(dataSizeSinkI[i]) for i in range(3)]; #print scale rpoints = points.copy(); #invert axis inversion and permutations if not orientation is None: #invert permuation iorientation = inverseOrientation(orientation); per = orientationToPermuation(iorientation); rpoints = rpoints[:,per]; for i in range(3): if iorientation[i] < 0: rpoints[:,i] = dataSizeSinkI[i] - rpoints[:,i]; #scale points for i in range(3): rpoints[:,i] = rpoints[:,i] * scale[i]; return io.writePoints(pointSink, rpoints);
def resampleDataInverse(sink, source = None, dataSizeSource = None, orientation = None, resolutionSource = (4.0625, 4.0625, 3), resolutionSink = (25, 25, 25), processingDirectory = None, processes = 1, cleanup = True, verbose = True, interpolation = 'linear', **args): """Resample data inversely to :func:`resampleData` routine Arguments: sink (str or None): image to be inversly resampled (=sink in :func:`resampleData`) source (str or array): destination for inversly resmapled image (=source in :func:`resampleData`) dataSizeSource (tuple or None): target size of the resampled image orientation (tuple): orientation specified by permuation and change in sign of (1,2,3) resolutionSource (tuple): resolution of the source image (in length per pixel) resolutionSink (tuple): resolution of the resampled image (in length per pixel) processingDirectory (str or None): directory in which to perform resmapling in parallel, None a temporary directry will be created processes (int): number of processes to use for parallel resampling cleanup (bool): remove temporary files verbose (bool): display progress information interpolation (str): method to use for interpolating to the resmapled image Returns: (array or str): data or file name of resampled image Notes: * resolutions are assumed to be given for the axes of the intrinsic orientation of the data and reference as when viewed by matplotlib or ImageJ * orientation: permuation of 1,2,3 with potential sign, indicating which axes map onto the reference axes, a negative sign indicates reversal of that particular axes * only a minimal set of information to detremine the resampling parameter has to be given, e.g. dataSizeSource and dataSizeSink """ #orientation orientation = fixOrientation(orientation); #assume we can read data fully into memory resampledData = io.readData(sink); dataSizeSink = resampledData.shape; if isinstance(dataSizeSource, basestring): dataSizeSource = io.dataSize(dataSizeSource); dataSizeSource, dataSizeSink, resolutionSource, resolutionSink = resampleDataSize(dataSizeSource = dataSizeSource, dataSizeSink = dataSizeSink, resolutionSource = resolutionSource, resolutionSink = resolutionSink, orientation = orientation); #print (dataSizeSource, dataSizeSink, resolutionSource, resolutionSink ) dataSizeSinkI = orientDataSizeInverse(dataSizeSink, orientation); #flip axes back and permute inversely if not orientation is None: if orientation[0] < 0: resampledData = resampledData[::-1, :, :]; if orientation[1] < 0: resampledData = resampledData[:, ::-1, :]; if orientation[2] < 0: resampledData = resampledData[:, :, ::-1]; #reorient peri = inverseOrientation(orientation); peri = orientationToPermuation(peri); resampledData = resampledData.transpose(peri); # upscale in z interpolation = fixInterpolation(interpolation); resampledDataXY = numpy.zeros((dataSizeSinkI[0], dataSizeSinkI[1], dataSizeSource[2]), dtype = resampledData.dtype); for i in range(dataSizeSinkI[0]): if verbose and i % 25 == 0: print "resampleDataInverse: processing %d/%d" % (i, dataSizeSinkI[0]) #cv2.resize takes reverse order of sizes ! resampledDataXY[i ,:, :] = cv2.resize(resampledData[i,:,:], (dataSizeSource[2], dataSizeSinkI[1]), interpolation = interpolation); # upscale x, y in parallel if io.isFileExpression(source): files = source; else: if processingDirectory == None: processingDirectory = tempfile.mkdtemp(); files = os.path.join(sink[0], 'resample_\d{4}.tif'); io.writeData(files, resampledDataXY); nZ = dataSizeSource[2]; pool = multiprocessing.Pool(processes=processes); argdata = []; for i in range(nZ): argdata.append( (source, fl.fileExpressionToFileName(files, i), dataSizeSource, interpolation, i, nZ) ); pool.map(_resampleXYParallel, argdata); if io.isFileExpression(source): return source; else: data = io.convertData(files, source); if cleanup: shutil.rmtree(processingDirectory); return data;
def resampleData(source, sink = None, orientation = None, dataSizeSink = None, resolutionSource = (4.0625, 4.0625, 3), resolutionSink = (25, 25, 25), processingDirectory = None, processes = 1, cleanup = True, verbose = True, interpolation = 'linear', **args): """Resample data of source in resolution and orientation Arguments: source (str or array): image to be resampled sink (str or None): destination of resampled image orientation (tuple): orientation specified by permuation and change in sign of (1,2,3) dataSizeSink (tuple or None): target size of the resampled image resolutionSource (tuple): resolution of the source image (in length per pixel) resolutionSink (tuple): resolution of the resampled image (in length per pixel) processingDirectory (str or None): directory in which to perform resmapling in parallel, None a temporary directry will be created processes (int): number of processes to use for parallel resampling cleanup (bool): remove temporary files verbose (bool): display progress information interpolation (str): method to use for interpolating to the resmapled image Returns: (array or str): data or file name of resampled image Notes: * resolutions are assumed to be given for the axes of the intrinsic orientation of the data and reference as when viewed by matplotlib or ImageJ * orientation: permuation of 1,2,3 with potential sign, indicating which axes map onto the reference axes, a negative sign indicates reversal of that particular axes * only a minimal set of information to detremine the resampling parameter has to be given, e.g. dataSizeSource and dataSizeSink """ orientation = fixOrientation(orientation); if isinstance(dataSizeSink, basestring): dataSizeSink = io.dataSize(dataSizeSink); #orient actual resolutions onto reference resolution dataSizeSource = io.dataSize(source); dataSizeSource, dataSizeSink, resolutionSource, resolutionSink = resampleDataSize(dataSizeSource = dataSizeSource, dataSizeSink = dataSizeSink, resolutionSource = resolutionSource, resolutionSink = resolutionSink, orientation = orientation); dataSizeSinkI = orientDataSizeInverse(dataSizeSink, orientation); #print dataSizeSource, dataSizeSink, resolutionSource, resolutionSink, dataSizeSinkI #rescale in x y in parallel if processingDirectory == None: processingDirectory = tempfile.mkdtemp(); interpolation = fixInterpolation(interpolation); nZ = dataSizeSource[2]; pool = multiprocessing.Pool(processes=processes); argdata = []; for i in range(nZ): argdata.append( (source, os.path.join(processingDirectory, 'resample_%04d.tif' % i), dataSizeSinkI, interpolation, i, nZ, verbose) ); #print argdata[i] pool.map(_resampleXYParallel, argdata); #rescale in z fn = os.path.join(processingDirectory, 'resample_%04d.tif' % 0); data = io.readData(fn); zImage = numpy.zeros((dataSizeSinkI[0], dataSizeSinkI[1], nZ), dtype = data.dtype); for i in range(nZ): if verbose and i % 10 == 0: print "resampleData; reading %d/%d" % (i, nZ); fn = os.path.join(processingDirectory, 'resample_%04d.tif' % i); zImage[:,:, i] = io.readData(fn); resampledData = numpy.zeros(dataSizeSinkI, dtype = zImage.dtype); for i in range(dataSizeSinkI[0]): if verbose and i % 25 == 0: print "resampleData: processing %d/%d" % (i, dataSizeSinkI[0]) #resampledImage[:, iImage ,:] = scipy.misc.imresize(zImage[:,iImage,:], [resizedZAxisSize, sagittalImageSize[1]] , interp = 'bilinear'); #cv2.resize takes reverse order of sizes ! resampledData[i ,:, :] = cv2.resize(zImage[i,:,:], (dataSizeSinkI[2], dataSizeSinkI[1]), interpolation = interpolation); #resampledData[i ,:, :] = cv2.resize(zImage[i,:, :], (dataSize[1], resizedZSize)); #account for using (z,y,x) array representation -> (y,x,z) #resampledData = resampledData.transpose([1,2,0]); #resampledData = resampledData.transpose([2,1,0]); if cleanup: shutil.rmtree(processingDirectory); if not orientation is None: #reorient per = orientationToPermuation(orientation); resampledData = resampledData.transpose(per); #reverse orientation after permuting e.g. (-2,1) brings axis 2 to first axis and we can reorder there if orientation[0] < 0: resampledData = resampledData[::-1, :, :]; if orientation[1] < 0: resampledData = resampledData[:, ::-1, :]; if orientation[2] < 0: resampledData = resampledData[:, :, ::-1]; #bring back from y,x,z to z,y,x #resampledImage = resampledImage.transpose([2,0,1]); if verbose: print "resampleData: resampled data size: " + str(resampledData.shape) if sink == []: if io.isFileExpression(source): sink = os.path.split(source); sink = os.path.join(sink[0], 'resample_\d{4}.tif'); elif isinstance(source, basestring): sink = source + '_resample.tif'; else: raise RuntimeError('resampleData: automatic sink naming not supported for non string source!'); return io.writeData(sink, resampledData);