def _adv_superbee(vel, var, mask, dx, axis, cost, cosu, dt_tracer): velfac = 1 if axis == 0: sm1, s, sp1, sp2 = ((slice(1 + n, -2 + n or None), slice(2, -2), slice(None)) for n in range(-1, 3)) dx = cost[bh.newaxis, 2:-2, bh.newaxis] * \ dx[1:-2, bh.newaxis, bh.newaxis] elif axis == 1: sm1, s, sp1, sp2 = ((slice(2, -2), slice(1 + n, -2 + n or None), slice(None)) for n in range(-1, 3)) dx = (cost * dx)[bh.newaxis, 1:-2, bh.newaxis] velfac = cosu[bh.newaxis, 1:-2, bh.newaxis] elif axis == 2: vel, var, mask = (pad_z_edges(a) for a in (vel, var, mask)) sm1, s, sp1, sp2 = ((slice(2, -2), slice(2, -2), slice(1 + n, -2 + n or None)) for n in range(-1, 3)) dx = dx[bh.newaxis, bh.newaxis, :-1] else: raise ValueError('axis must be 0, 1, or 2') uCFL = bh.abs(velfac * vel[s] * dt_tracer / dx) rjp = (var[sp2] - var[sp1]) * mask[sp1] rj = (var[sp1] - var[s]) * mask[s] rjm = (var[s] - var[sm1]) * mask[sm1] cr = limiter(_calc_cr(rjp, rj, rjm, vel[s])) return velfac * vel[s] * (var[sp1] + var[s]) * 0.5 - bh.abs(velfac * vel[s]) * ((1. - cr) + uCFL * cr) * rj * 0.5
def marble(size=(256,256),xPeriod=3.0,yPeriod=10.0,turbPower=0.8,turbSize=None,seed=None): """ Generate a marble texture akin to blender and others :param xPeriod: defines repetition of marble lines in x direction :param yPeriod: defines repetition of marble lines in y direction :param turbPower: add twists and swirls (when turbPower==0 it becomes a normal sine pattern) :param turbSize: initial size of the turbulence default is max(w,h)/10 NOTE: xPeriod and yPeriod together define the angle of the lines xPeriod and yPeriod both 0 then it becomes a normal clouds or turbulence pattern Optimized version of: https://lodev.org/cgtutor/randomnoise.html """ w,h=size turb=turbulence(size,turbSize,seed=seed)*turbPower # determine where the pixels will cycle cycleValue=np.ndarray((w,h)) for y in range(h): for x in range(w): cycleValue[x,y]=(x*xPeriod/w)+(y*yPeriod/h) # add in the turbulence and then last of all, make it a sinewave img=np.abs(np.sin((cycleValue+turb)*math.pi)) return img
def normalMapFromHeightMap(heightmap): """ Create a normal map from a height map (sometimes called a bumpmap) :param heightmap: height map to convert Comes from: http://www.juhanalankinen.com/calculating-normalmaps-with-python-and-numpy/ """ heightmap = numpyArray(heightmap) heightmap = normalize(heightmap) matI = np.identity(heightmap.shape[0] + 1) matNeg = -1 * matI[0:-1, 1:] matNeg[0, -1] = -1 matI = matI[1:, 0:-1] matI[-1, 0] = 1 matI += matNeg matGradX = (matI.dot(heightmap.T)).T matGradY = matI.dot(heightmap) matNormal = np.zeros([heightmap.shape[0], heightmap.shape[1], 3]) matNormal[:, :, 0] = -matGradX matNormal[:, :, 1] = matGradY matNormal[:, :, 2] = 1.0 fNormMax = np.max(np.abs(matNormal)) matNormal = ((matNormal / fNormMax) + 1.0) / 2.0 return matNormal
def selectHighContrast(image): """ get mask based on very bright or very dark areas returns b&w image where white=interesting, black=uninteresting NOTE: since we are using a color-weighted grayscale conversion, this does account somewhat for color discrimination of human vision. """ image = grayscale(image, method='BT.709') a = np.average(image) return normalize(np.abs(image - a))
def woodRings(size=(256,256),xyPeriod=12.0,turbPower=0.15,turbSize=32.0,seed=None): """ Draw wood rings :param xyPeriod: number of rings :param turbPower: makes twists :param turbSize: # initial size of the turbulence Optimized version of: https://lodev.org/cgtutor/randomnoise.html """ turb=turbulence(size,turbSize,seed=seed)*turbPower dc=normalize(deltaC(size,magnitude=True)) img = np.abs(np.sin(xyPeriod * (dc+turb) * math.pi)) return normalize(img)
def clock2(size=(256,256),waveform="sine",frequency=(10,10),noise=0.2,noiseBasis="perlin", noiseOctaves=4,noiseSoften=0.0,direction=0,invert=False,seed=None): """ a rotary clockface gradient """ noiseSize=max(size)/8 # TODO: pass this value in somehow turb=turbulence(size,noiseSize,seed=seed)*noise #points=np.ndarray((int(size[0]),int(size[1]))) angle=0.75-direction/360.0 dc=deltaC(size) img=np.arctan2(dc[:,:,0],dc[:,:,1])/math.pi img=np.abs(np.sin((((normalize(img)+angle)%1.0)+turb)*math.pi)) img=normalize(img) if invert: img=1.0-img return img
def imageDifference(img1, img2) -> Union[float, None]: """ returns an image difference as a decimal percent (1.0 = 100%) images can be a pil image, rgb numpy array, url, or filename NOTE: returns None if images are incomparable (including being a different size) """ if img1 is None or img2 is None: return None img1, img2 = makeSameMode([defaultLoader(img1), defaultLoader(img2)]) img1, img2 = numpyArray(img1), numpyArray(img2) if img1.shape != img2.shape: # if they're not even the same size, never mind, then return None return np.abs(img1 - img2).sum() / (img1.shape[0] * img1.shape[1])
def waveImage(size=(256,256),repeats=2,angle=0,wave='sine',radial=False): """ create an image based on a sine, saw, or triangle wave function """ ret=np.zeros(size) if radial: raise NotImplementedError() # TODO: Implement radial wave images else: twopi=2*pi thetas=np.arange(size[0])*float(repeats)/size[0]*twopi if wave=='sine': ret[:,:]=0.5+0.5*np.sin(thetas) elif wave=='saw': n=np.round(thetas/twopi) thetas-=n*twopi ret[:,:]=np.where(thetas<0,thetas+twopi,thetas)/twopi elif wave=='triangle': ret[:,:]=1.0-2.0*np.abs(np.floor((thetas*(1.0/twopi))+0.5)-(thetas*(1.0/twopi))) return ret
def weighted_line(r0, c0, r1, c1, w, rmin=0, rmax=np.inf): # The algorithm below works fine if c1 >= c0 and c1-c0 >= abs(r1-r0). # If either of these cases are violated, do some switches. if abs(c1-c0) < abs(r1-r0): # Switch x and y, and switch again when returning. xx, yy, val = weighted_line(c0, r0, c1, r1, w, rmin=rmin, rmax=rmax) return (yy, xx, val) # At this point we know that the distance in columns (x) is greater # than that in rows (y). Possibly one more switch if c0 > c1. if c0 > c1: return weighted_line(r1, c1, r0, c0, w, rmin=rmin, rmax=rmax) # The following is now always < 1 in abs num=r1-r0 denom=c1-c0 slope = np.divide(num,denom,out=np.zeros_like(denom), where=denom!=0) # Adjust weight by the slope w *= np.sqrt(1+np.abs(slope)) / 2 # We write y as a function of x, because the slope is always <= 1 # (in absolute value) x = np.arange(c0, c1+1, dtype=float) y = x * slope + (c1*r0-c0*r1) / (c1-c0) # Now instead of 2 values for y, we have 2*np.ceil(w/2). # All values are 1 except the upmost and bottommost. thickness = np.ceil(w/2) yy = (np.floor(y).reshape(-1,1) + np.arange(-thickness-1,thickness+2).reshape(1,-1)) xx = np.repeat(x, yy.shape[1]) vals = trapez(yy, y.reshape(-1,1), w).flatten() yy = yy.flatten() # Exclude useless parts and those outside of the interval # to avoid parts outside of the picture mask = np.logical_and.reduce((yy >= rmin, yy < rmax, vals > 0)) return (yy[mask].astype(int), xx[mask].astype(int), vals[mask])
def _calc_cr(rjp, rj, rjm, vel): """ Calculates cr value used in superbee advection scheme """ eps = 1e-20 # prevent division by 0 return where(vel > 0., rjm, rjp) / where(bh.abs(rj) < eps, eps, rj)
def sin(x): return np.abs(np.sin(x*math.pi))
def _difference(bottom, top): return np.abs(bottom - top)
def selectByColor(img, color, tolerance=0, soften=10, smartSoften=True, colorspace='RGB'): """ Select all pixels of a given color :param img: can be a pil image, numpy array, etc :param color: (in colorspace units) can be anything that pickColor returns: a color int array a color string to decode a color range (colorLow,colorHigh) an array of any of these :param tolerance: how close the selection must be :param soften: apply a soften radius to the edges of the selection :param smartSoften: multiply the soften radius by how near the pixel is to the selection color :param colorspace: change the given img (assumed to be RGB) into another corlorspace before matching :returns: black and white image in a numpy array (usable as a selection or a mask) """ from . import colorSpaces img = numpyArray(img) img = colorSpaces.changeColorspace(img, colorspace) if (isinstance(color, list) and isinstance(color[0], list)) or (isinstance(color, np.ndarray) and len(color.shape) > 1): # there are multiple colors, so select them all one at a time # TODO: this could possibly be made faster with array operations?? ret = None for c in color: if ret is None: ret = selectByColor(img, c, tolerance, soften, smartSoften) else: ret = ret + selectByColor(img, c, tolerance, soften, smartSoften) ret = clampImage(ret) elif isinstance(color, tuple): # color range - select all colors "between" these two in the given color space color = (matchColorToImage(color[0], img), matchColorToImage(color[1], img)) matches = np.logical_and(img >= color[0], img <= color[1]) ret = np.where(matches.all(axis=2), 1.0, 0.0) else: # a single color (or a series of colors that have been averaged down to one) color = matchColorToImage(color, img) if isFloat(color): imax = 1.0 imin = 0.0 else: imax = 255 imin = 0 numColors = img.shape[-1] avgDelta = np.sum(np.abs(img[:, :] - color), axis=-1) / numColors ret = np.where(avgDelta <= tolerance, imax, imin) if soften > 0: ret = gaussianBlur(ret, soften) if smartSoften: ret = np.minimum(imax, ret / avgDelta) return ret
def dm_taper(sx): """ tapering function for isopycnal slopes """ return 0.5 * (1. + bh.tanh((-bh.abs(sx) + iso_slopec) / iso_dslope))
def isoneutral_diffusion_pre(maskT, maskU, maskV, maskW, dxt, dxu, dyt, dyu, dzt, dzw, cost, cosu, salt, temp, zt, K_iso, K_11, K_22, K_33, Ai_ez, Ai_nz, Ai_bx, Ai_by): """ Isopycnal diffusion for tracer following functional formulation by Griffies et al Code adopted from MOM2.1 """ epsln = 1e-20 iso_slopec = 1e-3 iso_dslope = 1e-3 K_iso_steep = 50. tau = 0 dTdx = bh.zeros_like(K_11) dSdx = bh.zeros_like(K_11) dTdy = bh.zeros_like(K_11) dSdy = bh.zeros_like(K_11) dTdz = bh.zeros_like(K_11) dSdz = bh.zeros_like(K_11) """ drho_dt and drho_ds at centers of T cells """ drdT = maskT * get_drhodT(salt[:, :, :, tau], temp[:, :, :, tau], bh.abs(zt)) drdS = maskT * get_drhodS(salt[:, :, :, tau], temp[:, :, :, tau], bh.abs(zt)) """ gradients at top face of T cells """ dTdz[:, :, :-1] = maskW[:, :, :-1] * \ (temp[:, :, 1:, tau] - temp[:, :, :-1, tau]) / \ dzw[bh.newaxis, bh.newaxis, :-1] dSdz[:, :, :-1] = maskW[:, :, :-1] * \ (salt[:, :, 1:, tau] - salt[:, :, :-1, tau]) / \ dzw[bh.newaxis, bh.newaxis, :-1] """ gradients at eastern face of T cells """ dTdx[:-1, :, :] = maskU[:-1, :, :] * (temp[1:, :, :, tau] - temp[:-1, :, :, tau]) \ / (dxu[:-1, bh.newaxis, bh.newaxis] * cost[bh.newaxis, :, bh.newaxis]) dSdx[:-1, :, :] = maskU[:-1, :, :] * (salt[1:, :, :, tau] - salt[:-1, :, :, tau]) \ / (dxu[:-1, bh.newaxis, bh.newaxis] * cost[bh.newaxis, :, bh.newaxis]) """ gradients at northern face of T cells """ dTdy[:, :-1, :] = maskV[:, :-1, :] * \ (temp[:, 1:, :, tau] - temp[:, :-1, :, tau]) \ / dyu[bh.newaxis, :-1, bh.newaxis] dSdy[:, :-1, :] = maskV[:, :-1, :] * \ (salt[:, 1:, :, tau] - salt[:, :-1, :, tau]) \ / dyu[bh.newaxis, :-1, bh.newaxis] def dm_taper(sx): """ tapering function for isopycnal slopes """ return 0.5 * (1. + bh.tanh((-bh.abs(sx) + iso_slopec) / iso_dslope)) """ Compute Ai_ez and K11 on center of east face of T cell. """ diffloc = bh.zeros_like(K_11) diffloc[1:-2, 2:-2, 1:] = 0.25 * (K_iso[1:-2, 2:-2, 1:] + K_iso[1:-2, 2:-2, :-1] + K_iso[2:-1, 2:-2, 1:] + K_iso[2:-1, 2:-2, :-1]) diffloc[1:-2, 2:-2, 0] = 0.5 * \ (K_iso[1:-2, 2:-2, 0] + K_iso[2:-1, 2:-2, 0]) sumz = bh.zeros_like(K_11)[1:-2, 2:-2] for kr in range(2): ki = 0 if kr == 1 else 1 for ip in range(2): drodxe = drdT[1 + ip:-2 + ip, 2:-2, ki:] * dTdx[1:-2, 2:-2, ki:] \ + drdS[1 + ip:-2 + ip, 2:-2, ki:] * dSdx[1:-2, 2:-2, ki:] drodze = drdT[1 + ip:-2 + ip, 2:-2, ki:] * dTdz[1 + ip:-2 + ip, 2:-2, :-1 + kr or None] \ + drdS[1 + ip:-2 + ip, 2:-2, ki:] * \ dSdz[1 + ip:-2 + ip, 2:-2, :-1 + kr or None] sxe = -drodxe / (bh.minimum(0., drodze) - epsln) taper = dm_taper(sxe) sumz[:, :, ki:] += dzw[bh.newaxis, bh.newaxis, :-1 + kr or None] * maskU[1:-2, 2:-2, ki:] \ * bh.maximum(K_iso_steep, diffloc[1:-2, 2:-2, ki:] * taper) Ai_ez[1:-2, 2:-2, ki:, ip, kr] = taper * \ sxe * maskU[1:-2, 2:-2, ki:] K_11[1:-2, 2:-2, :] = sumz / (4. * dzt[bh.newaxis, bh.newaxis, :]) """ Compute Ai_nz and K_22 on center of north face of T cell. """ diffloc[...] = 0 diffloc[2:-2, 1:-2, 1:] = 0.25 * (K_iso[2:-2, 1:-2, 1:] + K_iso[2:-2, 1:-2, :-1] + K_iso[2:-2, 2:-1, 1:] + K_iso[2:-2, 2:-1, :-1]) diffloc[2:-2, 1:-2, 0] = 0.5 * \ (K_iso[2:-2, 1:-2, 0] + K_iso[2:-2, 2:-1, 0]) sumz = bh.zeros_like(K_11)[2:-2, 1:-2] for kr in range(2): ki = 0 if kr == 1 else 1 for jp in range(2): drodyn = drdT[2:-2, 1 + jp:-2 + jp, ki:] * dTdy[2:-2, 1:-2, ki:] + \ drdS[2:-2, 1 + jp:-2 + jp, ki:] * dSdy[2:-2, 1:-2, ki:] drodzn = drdT[2:-2, 1 + jp:-2 + jp, ki:] * dTdz[2:-2, 1 + jp:-2 + jp, :-1 + kr or None] \ + drdS[2:-2, 1 + jp:-2 + jp, ki:] * \ dSdz[2:-2, 1 + jp:-2 + jp, :-1 + kr or None] syn = -drodyn / (bh.minimum(0., drodzn) - epsln) taper = dm_taper(syn) sumz[:, :, ki:] += dzw[bh.newaxis, bh.newaxis, :-1 + kr or None] \ * maskV[2:-2, 1:-2, ki:] * bh.maximum(K_iso_steep, diffloc[2:-2, 1:-2, ki:] * taper) Ai_nz[2:-2, 1:-2, ki:, jp, kr] = taper * \ syn * maskV[2:-2, 1:-2, ki:] K_22[2:-2, 1:-2, :] = sumz / (4. * dzt[bh.newaxis, bh.newaxis, :]) """ compute Ai_bx, Ai_by and K33 on top face of T cell. """ sumx = bh.zeros_like(K_11)[2:-2, 2:-2, :-1] sumy = bh.zeros_like(K_11)[2:-2, 2:-2, :-1] for kr in range(2): drodzb = drdT[2:-2, 2:-2, kr:-1 + kr or None] * dTdz[2:-2, 2:-2, :-1] \ + drdS[2:-2, 2:-2, kr:-1 + kr or None] * dSdz[2:-2, 2:-2, :-1] # eastward slopes at the top of T cells for ip in range(2): drodxb = drdT[2:-2, 2:-2, kr:-1 + kr or None] * dTdx[1 + ip:-3 + ip, 2:-2, kr:-1 + kr or None] \ + drdS[2:-2, 2:-2, kr:-1 + kr or None] * \ dSdx[1 + ip:-3 + ip, 2:-2, kr:-1 + kr or None] sxb = -drodxb / (bh.minimum(0., drodzb) - epsln) taper = dm_taper(sxb) sumx += dxu[1 + ip:-3 + ip, bh.newaxis, bh.newaxis] * \ K_iso[2:-2, 2:-2, :-1] * taper * \ sxb**2 * maskW[2:-2, 2:-2, :-1] Ai_bx[2:-2, 2:-2, :-1, ip, kr] = taper * \ sxb * maskW[2:-2, 2:-2, :-1] # northward slopes at the top of T cells for jp in range(2): facty = cosu[1 + jp:-3 + jp] * dyu[1 + jp:-3 + jp] drodyb = drdT[2:-2, 2:-2, kr:-1 + kr or None] * dTdy[2:-2, 1 + jp:-3 + jp, kr:-1 + kr or None] \ + drdS[2:-2, 2:-2, kr:-1 + kr or None] * \ dSdy[2:-2, 1 + jp:-3 + jp, kr:-1 + kr or None] syb = -drodyb / (bh.minimum(0., drodzb) - epsln) taper = dm_taper(syb) sumy += facty[bh.newaxis, :, bh.newaxis] * K_iso[2:-2, 2:-2, :-1] \ * taper * syb**2 * maskW[2:-2, 2:-2, :-1] Ai_by[2:-2, 2:-2, :-1, jp, kr] = taper * \ syb * maskW[2:-2, 2:-2, :-1] K_33[2:-2, 2:-2, :-1] = sumx / (4 * dxt[2:-2, bh.newaxis, bh.newaxis]) + \ sumy / (4 * dyt[bh.newaxis, 2:-2, bh.newaxis] * cost[bh.newaxis, 2:-2, bh.newaxis]) K_33[2:-2, 2:-2, -1] = 0.