def create_tiling(s, size=40, shift=0): imtile = s.oshape.translate(-s.pad) region = util.Tile(size, dim=s.dim) trange = np.ceil(imtile.shape.astype('float') / region.shape) translations = util.Tile(trange).coords(form='vector') translations = translations.reshape(-1, translations.shape[-1]) return [ region.copy().translate(region.shape * v - s.pad + shift) for v in translations ]
def separate_particles_into_groups(s, region_size=40, bounds=None): """ Given a state, returns a list of groups of particles. Each group of particles are located near each other in the image. Every particle located in the desired region is contained in exactly 1 group. Parameters: ----------- s : state The PERI state to find particles in. region_size: int or list of ints The size of the box. Groups particles into boxes of shape region_size. If region_size is a scalar, the box is a cube of length region_size. Default is 40. bounds: 2-element list-like of 3-element lists. The sub-region of the image over which to look for particles. bounds[0]: The lower-left corner of the image region. bounds[1]: The upper-right corner of the image region. Default (None -> ([0,0,0], s.oshape.shape)) is a box of the entire image size, i.e. the default places every particle in the image somewhere in the groups. Returns: ----------- particle_groups: list Each element of particle_groups is an int numpy.ndarray of the group of nearby particles. Only contains groups with a nonzero number of particles, so the elements don't necessarily correspond to a given image region. """ imtile = (s.oshape.translate(-s.pad) if bounds is None else util.Tile( bounds[0], bounds[1])) # does all particle including out of image, is that correct? region = util.Tile(region_size, dim=s.dim) trange = np.ceil(imtile.shape.astype('float') / region.shape) translations = util.Tile(trange).coords(form='vector') translations = translations.reshape(-1, translations.shape[-1]) groups = [] positions = s.obj_get_positions() for v in translations: tmptile = region.copy().translate(region.shape * v - s.pad) groups.append(find_particles_in_tile(positions, tmptile)) return [g for g in groups if len(g) > 0]
def set_image(self, image): """ Update the current comparison (real) image """ if isinstance(image, np.ndarray): image = util.Image(image) if isinstance(image, util.NullImage): self.model_as_data = True else: self.model_as_data = False self.image = image self._data = self.image.get_padded_image(self.pad) # set up various slicers and Tiles associated with the image and pad self.oshape = util.Tile(self._data.shape) self.ishape = self.oshape.pad(-self.pad) self.inner = self.ishape.slicer for c in self.comps: c.set_shape(self.oshape, self.ishape) self._model = np.zeros(self._data.shape, dtype=np.float64) self._residuals = np.zeros(self._data.shape, dtype=np.float64) self.calculate_model()
def get_update_io_tiles(self, params, values): """ Get the tiles corresponding to a particular section of image needed to be updated. Inputs are the parameters and values. Returned is the padded tile, inner tile, and slicer to go between, but accounting for wrap with the edge of the image as necessary. """ # get the affected area of the model image otile = self.get_update_tile(params, values) if otile is None: return [None] * 3 ptile = self.get_padding_size(otile) or util.Tile(0, dim=otile.dim) otile = util.Tile.intersection(otile, self.oshape) if (otile.shape <= 0).any(): raise UpdateError("update triggered invalid tile size") if (ptile.shape < 0).any() or (ptile.shape > self.oshape.shape).any(): raise UpdateError("update triggered invalid padding tile size") # now remove the part of the tile that is outside the image and pad the # interior part with that overhang. reflect the necessary padding back # into the image itself for the outer slice which we will call outer outer = otile.pad((ptile.shape + 1) / 2) inner, outer = outer.reflect_overhang(self.oshape) iotile = inner.translate(-outer.l) outer = util.Tile.intersection(outer, self.oshape) inner = util.Tile.intersection(inner, self.oshape) return outer, inner, iotile
def initialize_particles(N=None, tile=None, phi=None, radius=5., polydispersity=0.): """ Creates an initial (overlapping) particle configuration by 3 different ways: (N, phi) : creates an appropriate box (N, tile) : uses a box and determines phi (tile, phi): uses both to determine N """ vparticle = 4./3*np.pi*radius**3 if phi and tile is not None: vbox = np.prod(tile.shape) N = int(phi * vbox / vparticle) elif N and phi: vbox = N * vparticle / phi side = vbox**(1./3) tile = util.Tile(side) elif N and tile is not None: pass else: raise AttributeError("Any pair of (phi, tile, N) must be specified") pos = np.random.rand(N, 3)*tile.shape + tile.l rad = np.abs(np.random.normal( loc=radius, scale=np.abs(polydispersity*radius)+1e-20, size=N )) return pos, rad, tile
def create_image(N=128, size=64, radius=6.0, pad=16, identity=False, polydispersity=0.0): blank = np.zeros((size, ) * 3) pos, rad, tile = nbody.initialize_particles(N, radius=radius, tile=util.Tile(blank.shape), polydispersity=polydispersity) sim = nbody.BrownianHardSphereSimulation(pos, rad, tile) sim.relax(2000) sim.step(5000) sim.relax(2000) slab_zpos = -radius if not identity: s = runner.create_state(blank, pos, rad, slab=slab_zpos, sigma=0.00001, stateargs={ 'pad': pad, 'offset': 0.18 }, psftype='cheb-linescan-fixedss', psfargs={ 'zslab': 10., 'cheb_degree': 6, 'cheb_evals': 8, 'support_size': FIXEDSS, }, ilmtype='barnesleg2p1dx', ilmargs={ 'order': (1, 1, 3), 'npts': (30, 10, 5) }) s.ilm.randomize_parameters(ptp=0.4, vmax=1.0, fourier=False) else: s = runner.create_state( blank, pos, rad, slab=slab_zpos, sigma=0.00001, stateargs={ 'pad': pad, 'offset': 0.18 }, psftype='identity', ilmtype='leg2p1d', ) s.reset() s.model_to_true_image() return s
def closest_uniform_tile(s, shift, size, other): """ Given a tiling of space (by state, shift, and size), find the closest tile to another external tile """ region = util.Tile(size, dim=s.dim, dtype='float').translate(shift - s.pad) vec = np.round((other.center - region.center) / region.shape) return region.translate(region.shape * vec)
def create_many_particle_state(imsize=None, N=None, phi=None, radius=5.0, polydispersity=0.0, seed=None, **kwargs): """ Creates a random packing of spheres and generates the state. In order to specify the state, either (phi, imsize) or (N, phi) or (N, imsize) must be given. Any more than that and it would be over-specified. Parameters: ----------- imsize : tuple, array_like, or integer the unpadded image size to fill with particles N : integer number of particles phi : float packing fraction radius : float radius of particles to add N : integer Number of particles seed : integer set the seed if desired *args, **kwargs : see create_state """ _seed_or_not(seed) if imsize is not None: imsize = _toarr(imsize) tile = util.Tile(imsize) else: tile = None pos, rad, tile = nbody.create_configuration(N, tile, radius=radius, phi=phi, polydispersity=polydispersity) s = create_state(util.NullImage(shape=tile.shape), pos, rad, **kwargs) if isinstance(s.get('ilm'), ilms.BarnesStreakLegPoly2P1D): ilm = s.get('ilm') ilm.randomize_parameters() s.reset() s.model_to_data(s.sigma) return s
def get_update_tile(self, params, values): if not self.local_updates: return self.shape.copy() params = util.listify(params) values = util.listify(values) c = self.category # check for global update requiring parameters: for p in params: if p in self.poly_params or p == c + '-scale' or p == c + '-off': return self.shape.copy() # now look for the local update sizes orig_values = self.get_values(params) tiles = [] for p, v in zip(params, values): # figure out the barnes local update size for n, grp in enumerate(self.barnes_params): if not p in grp: continue val0 = self._barnes(self.b_out, n=n) self.set_values(p, v) val1 = self._barnes(self.b_out, n=n) inds = np.arange(self.b_out.shape[0]) inds = inds[np.abs(val1 - val0) > 1e-12] if len(inds) < 2: continue l, r = inds.min(), inds.max() tile = self.shape.copy() tile.l[2] = l tile.r[2] = r tiles.append(util.Tile(tile.l, tile.r)) self.set_values(params, orig_values) if len(tiles) == 0: return None return util.Tile.boundingtile(tiles)
def get_update_tile(self, params, values): #a lot of this is duplicated from parent to here if not self.local_updates: return self.shape.copy() params = util.listify(params) values = util.listify(values) c = self.category # check for global update requiring parameters: for p in params: if p in self.poly_params or p == c + '-scale' or p == c + '-off': return self.shape.copy() # now look for the local update sizes orig_values = self.get_values(params) #see for loop... tiles = [] for p, v in zip(params, values): # figure out the barnes local update size # looks like matt does this by changing each param, then seeing # manually which points have changed.... if not p in self.barnes_params: raise RuntimeError('Im confused...') val0 = self._barnes(self.b_out) self.set_values(p, v) val1 = self._barnes(self.b_out) inds = np.arange(self.b_out.shape[0]) inds = inds[np.abs(val1 - val0) > 1e-12] if len(inds) < 2: continue l, r = inds.min(), inds.max() tile = self.shape.copy() tile.l[2] = l tile.r[2] = r tiles.append(util.Tile(tile.l, tile.r)) # raise NotImplementedError('Local updates not implemented yet') if len(tiles) == 0: return None return util.Tile.boundingtile(tiles)
def generative_model(s, x, y, z, r, factor=1.1): """ Samples x,y,z,r are created by: b = s.blocks_particle(#) h = runner.sample_state(s, b, stepout=0.05, N=2000, doprint=True) z,y,x,r = h.get_histogram().T """ pl.close('all') slicez = int(round(z.mean())) slicex = s.image.shape[2] // 2 slicer1 = np.s_[slicez, s.pad:-s.pad, s.pad:-s.pad] slicer2 = np.s_[s.pad:-s.pad, s.pad:-s.pad, slicex] center = (slicez, s.image.shape[1] // 2, slicex) fig = pl.figure(figsize=(factor * 13, factor * 10)) #========================================================================= #========================================================================= gs1 = ImageGrid(fig, rect=[0.0, 0.6, 1.0, 0.35], nrows_ncols=(1, 3), axes_pad=0.1) ax_real = gs1[0] ax_fake = gs1[1] ax_diff = gs1[2] diff = s.get_model_image() - s.image ax_real.imshow(s.image[slicer1], cmap=pl.cm.bone_r) ax_real.set_xticks([]) ax_real.set_yticks([]) ax_real.set_title("Confocal image", fontsize=24) ax_fake.imshow(s.get_model_image()[slicer1], cmap=pl.cm.bone_r) ax_fake.set_xticks([]) ax_fake.set_yticks([]) ax_fake.set_title("Model image", fontsize=24) ax_diff.imshow(diff[slicer1], cmap=pl.cm.RdBu, vmin=-0.1, vmax=0.1) ax_diff.set_xticks([]) ax_diff.set_yticks([]) ax_diff.set_title("Difference", fontsize=24) #========================================================================= #========================================================================= gs2 = ImageGrid(fig, rect=[0.1, 0.0, 0.4, 0.55], nrows_ncols=(3, 2), axes_pad=0.1) ax_plt1 = fig.add_subplot(gs2[0]) ax_plt2 = fig.add_subplot(gs2[1]) ax_ilm1 = fig.add_subplot(gs2[2]) ax_ilm2 = fig.add_subplot(gs2[3]) ax_psf1 = fig.add_subplot(gs2[4]) ax_psf2 = fig.add_subplot(gs2[5]) c = int(z.mean()), int(y.mean()) + s.pad, int(x.mean()) + s.pad if s.image.shape[0] > 2 * s.image.shape[1] // 3: w = s.image.shape[2] - 2 * s.pad h = 2 * w // 3 else: h = s.image.shape[0] - 2 * s.pad w = 3 * h // 2 w, h = w // 2, h // 2 xyslice = np.s_[slicez, c[1] - h:c[1] + h, c[2] - w:c[2] + w] yzslice = np.s_[c[0] - h:c[0] + h, c[1] - w:c[1] + w, slicex] #h = s.image.shape[2]/2 - s.image.shape[0]/2 #slicer2 = np.s_[s.pad:-s.pad, s.pad:-s.pad, slicex] #slicer3 = np.s_[slicez, s.pad+h:-s.pad-h, s.pad:-s.pad] ax_plt1.imshow(1 - s.obj.get_field()[xyslice], cmap=pl.cm.bone_r, vmin=0, vmax=1) ax_plt1.set_xticks([]) ax_plt1.set_yticks([]) ax_plt1.set_ylabel("Platonic", fontsize=22) ax_plt1.set_title("x-y", fontsize=24) ax_plt2.imshow(1 - s._platonic_image()[yzslice], cmap=pl.cm.bone_r, vmin=0, vmax=1) ax_plt2.set_xticks([]) ax_plt2.set_yticks([]) ax_plt2.set_title("y-z", fontsize=24) ax_ilm1.imshow(s.ilm.get_field()[xyslice], cmap=pl.cm.bone_r) ax_ilm1.set_xticks([]) ax_ilm1.set_yticks([]) ax_ilm1.set_ylabel("ILM", fontsize=22) ax_ilm2.imshow(s.ilm.get_field()[yzslice], cmap=pl.cm.bone_r) ax_ilm2.set_xticks([]) ax_ilm2.set_yticks([]) t = s.ilm.get_field().copy() t *= 0 t[c] = 1 s.psf.set_tile(util.Tile(t.shape)) psf = (s.psf.execute(t) + 5e-5)**0.1 ax_psf1.imshow(psf[xyslice], cmap=pl.cm.bone) ax_psf1.set_xticks([]) ax_psf1.set_yticks([]) ax_psf1.set_ylabel("PSF", fontsize=22) ax_psf2.imshow(psf[yzslice], cmap=pl.cm.bone) ax_psf2.set_xticks([]) ax_psf2.set_yticks([]) #========================================================================= #========================================================================= ax_zoom = fig.add_axes([0.48, 0.018, 0.45, 0.52]) #s.model_to_true_image() im = s.image[slicer1] sh = np.array(im.shape) cx = x.mean() cy = y.mean() extent = [0, sh[0], 0, sh[1]] ax_zoom.set_xticks([]) ax_zoom.set_yticks([]) ax_zoom.imshow(im, extent=extent, cmap=pl.cm.bone_r) ax_zoom.set_xlim(cx - 12, cx + 12) ax_zoom.set_ylim(cy - 12, cy + 12) ax_zoom.set_title("Sampled positions", fontsize=24) ax_zoom.hexbin(x, y, gridsize=32, mincnt=0, cmap=pl.cm.hot) zoom1 = zoomed_inset_axes(ax_zoom, 30, loc=3) zoom1.imshow(im, extent=extent, cmap=pl.cm.bone_r) zoom1.set_xlim(cx - 1.0 / 6, cx + 1.0 / 6) zoom1.set_ylim(cy - 1.0 / 6, cy + 1.0 / 6) zoom1.hexbin(x, y, gridsize=32, mincnt=5, cmap=pl.cm.hot) zoom1.set_xticks([]) zoom1.set_yticks([]) zoom1.hlines(cy - 1.0 / 6 + 1.0 / 32, cx - 1.0 / 6 + 5e-2, cx - 1.0 / 6 + 5e-2 + 1e-1, lw=3) zoom1.text(cx - 1.0 / 6 + 1.0 / 24, cy - 1.0 / 6 + 5e-2, '0.1px') mark_inset(ax_zoom, zoom1, loc1=2, loc2=4, fc="none", ec="0.0")
def get_padding_size(self, tile, z=None): return util.Tile(self.support)
bkg_vry = ilms.LegendrePoly3D(order=(1,3,5)) st.set('ilm', bkg_vry) opt.do_levmarq(st, st.params) # Looking at the plot of the residuals again shows a significant improvement # in the residuals: plot_averaged_residuals(st) # Next, let's check the illumination field. For this, we load a different # image, one that I've taken of just dyed fluid. This image also has a # coverslip in it, at the bottom. For now, we'll ignore this coverlip by # setting the tile to be a specific region of z in the image. Moreover, # since I know that our confocal has some scan issues at the edges of the # image, I'll also crop out the image edges with the tile: im_ilm = util.RawImage('./ilm_test.tif', tile=util.Tile([48,0,0], [49,100,100])) # also located in the scripts folder # Looking at the image, the illlumination is very stripey, due to the line-scan # nature of our confocal. To account for this, we use a stripe-based ilm: ilm = ilms.BarnesStreakLegPoly2P1D(npts=(50, 30, 20, 13, 7, 7, 7), zorder=1) # (we only use a zorder of 1 since we've truncated to 1 pixel in z). # Our real model will use a point-spread function that will blur out the ilm # field slightly more. So we check the fit with a model that includes the # type of point-spread function that we will use. A model that blur with a # point-spread function takes considerably more time to evaluate than a # SmoothFieldModel, so if you're not sure if your ilm is high enough order # you should first check with a faster SmoothFieldModel. psf = exactpsf.FixedSSChebLinePSF() st = states.ImageState(im_ilm, [ilm, psf], mdl=models.BlurredFieldModel())
st.set('ilm', bkg_vry) opt.do_levmarq(st, st.params) # Looking at the plot of the residuals again shows a significant improvement # in the residuals: plot_averaged_residuals(st) # Next, let's check the illumination field. For this, we load a different # image, one that I've taken of just dyed fluid. This image also has a # coverslip in it, at the bottom. For now, we'll ignore this coverlip by # setting the tile to be a specific region of z in the image. Moreover, # since I know that our confocal has some scan issues at the edges of the # image, I'll also crop out the image edges with the tile: im_ilm = util.RawImage('./ilm_test.tif', tile=util.Tile([48, 0, 0], [49, 100, 100])) # also located in the scripts folder # Looking at the image, the illlumination is very stripey, due to the line-scan # nature of our confocal. To account for this, we use a stripe-based ilm: ilm = ilms.BarnesStreakLegPoly2P1D(npts=(50, 30, 20, 13, 7, 7, 7), zorder=1) # (we only use a zorder of 1 since we've truncated to 1 pixel in z). # Our real model will use a point-spread function that will blur out the ilm # field slightly more. So we check the fit with a model that includes the # type of point-spread function that we will use. A model that blur with a # point-spread function takes considerably more time to evaluate than a # SmoothFieldModel, so if you're not sure if your ilm is high enough order # you should first check with a faster SmoothFieldModel. psf = exactpsf.FixedSSChebLinePSF() st = states.ImageState(im_ilm, [ilm, psf], mdl=models.BlurredFieldModel())
from peri.viz.interaction import OrthoPrefeature from peri import models from peri import states from peri import comp from peri import runner from peri.viz import plots from datetime import datetime imFile = '/Volumes/PhD/expDesign/test/balls.tif' blank_im = util.RawImage(imFile) particle_positions=np.load('part_loc_davidImage.npy') # particle_positions n=100 # random_particles = np.c_[np.random.random(n), np.random.random(n),np.zeros(n)]*200.0 tile = util.Tile(200) small_im = util.RawImage(imFile, tile=tile) zpixel=1 xpixel=1 zscale=zpixel/xpixel particle_radii = 8.0 particles = objs.PlatonicSpheresCollection(particle_positions, particle_radii, zscale=zscale) objects = comp.comp.ComponentCollection([particles], category='obj') background = comp.ilms.LegendrePoly2P1D(order=(4,2,2), category='bkg') illumination = comp.ilms.BarnesStreakLegPoly2P1D(npts=(4, 2, 2)) offset = comp.GlobalScalar(name='offset', value=0.)
def psf_slice(self, zint, size=11, zoffset=0., getextent=False): """ Calculates the 3D psf at a particular z pixel height Parameters ---------- zint : float z pixel height in image coordinates , converted to 1/k by the function using the slab position as well size : int, list, tuple The size over which to calculate the psf, can be 1 or 3 elements for the different axes in image pixel coordinates zoffset : float Offset in pixel units to use in the calculation of the psf cutval : float If not None, the psf will be cut along a curve corresponding to p(r) == 0 with exponential damping exp(-d^4) getextent : boolean If True, also return the extent of the psf in pixels for example to get the support size. Can only be used with cutval. """ # calculate the current pixel value in 1/k, making sure we are above the slab zint = max(self._p2k(self._tz(zint)), 0) offset = np.array([zoffset * (zint > 0), 0, 0]) scale = [self.param_dict[self.zscale], 1.0, 1.0] # create the coordinate vectors for where to actually calculate the tile = util.Tile(left=0, size=size, centered=True) vecs = tile.coords(form='flat') vecs = [self._p2k(s * i + o) for i, s, o in zip(vecs, scale, offset)] psf = self.psffunc(*vecs[::-1], zint=zint, **self.pack_args()).T vec = tile.coords(form='meshed') # create a smoothly varying point spread function by cutting off the psf # at a certain value and smoothly taking it to zero if self.cutoffval is not None and not self.cutbyval: # find the edges of the PSF edge = psf > psf.max() * self.cutoffval dd = nd.morphology.distance_transform_edt(~edge) # calculate the new PSF and normalize it to the new support psf = psf * np.exp(-dd**4) psf /= psf.sum() if getextent: # the size is determined by the edge plus a 2 pad for the # exponential damping to zero at the edge size = np.array([ (vec * edge).min(axis=(1, 2, 3)) - 2, (vec * edge).max(axis=(1, 2, 3)) + 2, ]).T return psf, vec, size return psf, vec # perform a cut by value instead if self.cutoffval is not None and self.cutbyval: cutval = self.cutoffval * psf.max() dd = (psf - cutval) / cutval dd[dd > 0] = 0. # calculate the new PSF and normalize it to the new support psf = psf * np.exp(-(dd / self.cutfallrate)**4) psf /= psf.sum() # let the small values determine the edges edge = psf > cutval * self.cutedgeval if getextent: # the size is determined by the edge plus a 2 pad for the # exponential damping to zero at the edge size = np.array([ (vec * edge).min(axis=(1, 2, 3)) - 2, (vec * edge).max(axis=(1, 2, 3)) + 2, ]).T return psf, vec, size return psf, vec return psf, vec
import numpy as np from peri.comp import objs from peri.viz.interaction import OrthoPrefeature from peri import models from peri import states from peri import comp from peri import runner from peri.viz import plots from datetime import datetime im = util.RawImage( '/Volumes/PhD/expDesign/Data/2011_DAS_SoftMatter_Data/jtLLF090701_BR090729_NBD_xyz007_x100_z35_K4.tif' ) tile = util.Tile([5, 312, 0], right=[12, 512, 200]) small_im = util.RawImage( '/Volumes/PhD/expDesign/Data/2011_DAS_SoftMatter_Data/jtLLF090701_BR090729_NBD_xyz007_x100_z35_K4.tif', tile=tile) zpixel = 0.82 xpixel = 35.2 / 512 zscale = zpixel / xpixel particle_positions = np.load('part_loc_smallSlice.npy') particle_radii = 8.0 particles = objs.PlatonicSpheresCollection(particle_positions, particle_radii, zscale=zscale) # imaginary_slide = objs.Slab(zpos=6) print(particles) objects = comp.comp.ComponentCollection([particles], category='obj')