static MultiDimFloatTexture makeGaussKernel(int filtersz, float sigma) { MultiDimFloatTexture kernel = new MultiDimFloatTexture(filtersz, filtersz, 1); float sum = 0; for (int j = 0; j < filtersz; j++) { for (int i = 0; i < filtersz; i++) { float di = (float)(i - filtersz / 2); float dj = (float)(j - filtersz / 2); float u2 = (di * di + dj * dj) / ((float)filtersz * filtersz); kernel.set((float)Math.Exp(-u2 / (2.0f * sigma * sigma)), i, j, 0); sum += kernel.get(i, j, 0); } } // . normalize for (int j = 0; j < filtersz; j++) { for (int i = 0; i < filtersz; i++) { kernel.set(kernel.get(i, j, 0) / sum, i, j, 0); } } return(kernel); }
// ------ // Extract a sub-tile of the texture public MultiDimFloatTexture extract(int x, int y, int w, int h) { MultiDimFloatTexture res = new MultiDimFloatTexture(w, h, m_iNumComp); for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { int xs = x + i; if (xs < 0 || xs >= m_iW) { continue; } int ys = y + j; if (ys < 0 || ys >= m_iH) { continue; } for (int c = 0; c < m_iNumComp; c++) { res.set(get(xs, ys, c), i, j, c); } } } return(res); }
// ------ public MultiDimFloatTexture computeNextMIPMapLevel_BoxFilter() { int w = (int)Math.Max(1, m_iW >> 1); int h = (int)Math.Max(1, m_iH >> 1); MultiDimFloatTexture tex = new MultiDimFloatTexture(w, h, m_iNumComp); for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { for (int c = 0; c < m_iNumComp; c++) { float val = 0.25f * ( get(i * 2, j * 2, c) + get(i * 2 + 1, j * 2, c) + get(i * 2, j * 2 + 1, c) + get(i * 2 + 1, j * 2 + 1, c)); tex.set(val, i, j, c); } } } return(tex); }
public MultiDimFloatTexture computeNextMIPMapLevel_GaussianFilter(int filtersz) { MultiDimFloatTexture filtered = applyGaussianFilter_Separable(filtersz); int w = (int)Math.Max(1, m_iW / 2); int h = (int)Math.Max(1, m_iH / 2); MultiDimFloatTexture tex = new MultiDimFloatTexture(w, h, m_iNumComp); for (int v = 0; v < h; v++) { for (int u = 0; u < w; u++) { for (int c = 0; c < m_iNumComp; c++) { tex.set(filtered.get(u * 2, v * 2, c), u, v, c); } } } filtered = null; return(tex); }
unsafe void synthesisNeighborhoodsToD3DTexture(Exemplar a, int l) { // synthesis neighborhoods // . build float multidim texture from projected neighborhoods MultiDimFloatTexture tex = new MultiDimFloatTexture(a.recoloredStack(l).width(), a.recoloredStack(l).height(), Globals.NUM_RUNTIME_PCA_COMPONENTS); for (int j = 0; j < tex.height(); j++) { for (int i = 0; i < tex.width(); i++) { NeighborhoodSynth nproj = a.getProjectedSynthNeighborhood(l, i, j); for (int c = 0; c < tex.numComp(); c++) { tex.set(nproj.getValue(c), i, j, c); } } } // . quantize Quantizer q = new Quantizer(tex, Globals.QUANTIZE_NUM_BITS, Globals.QUANTIZE_PERCENT_INSIDE); m_d3dNeighborhoods_0_3 = new Texture(BRenderDevice.getDevice(), tex.width(), tex.height(), 1, 0, Format.A8R8G8B8, Pool.Managed); // . fill GraphicsStream texstream = m_d3dNeighborhoods_0_3.LockRectangle(0, LockFlags.None); byte * data = (byte *)texstream.InternalDataPointer; int rectPitch = tex.width() * 4; for (int j = 0; j < tex.height(); j++) { for (int i = 0; i < tex.width(); i++) { int v0 = q.quantized().get(i, j, 0); int v1 = q.quantized().get(i, j, 1); int v2 = q.quantized().get(i, j, 2); int v3 = q.quantized().get(i, j, 3); Globals.Assert(v0 >= 0 && v0 <= 255); Globals.Assert(v1 >= 0 && v1 <= 255); Globals.Assert(v2 >= 0 && v2 <= 255); Globals.Assert(v3 >= 0 && v3 <= 255); data[i * 4 + j * rectPitch + 2] = (byte)(v0); data[i * 4 + j * rectPitch + 1] = (byte)(v1); data[i * 4 + j * rectPitch + 0] = (byte)(v2); data[i * 4 + j * rectPitch + 3] = (byte)(v3); } } m_d3dNeighborhoods_0_3.UnlockRectangle(0); // de-quantization parameters m_UnqNeighborhoods_Scale = new List <float>(8); m_UnqNeighborhoods_Mean = new List <float>(8); for (int c = 0; c < q.quantized().numComp(); c++) { m_UnqNeighborhoods_Scale.Add(q.radius(c)); m_UnqNeighborhoods_Mean.Add(q.center(c)); } qn_mean_0_3 = new Vector4(m_UnqNeighborhoods_Mean[0], m_UnqNeighborhoods_Mean[1], m_UnqNeighborhoods_Mean[2], m_UnqNeighborhoods_Mean[3]); qn_scale_0_3 = new Vector4(m_UnqNeighborhoods_Scale[0], m_UnqNeighborhoods_Scale[1], m_UnqNeighborhoods_Scale[2], m_UnqNeighborhoods_Scale[3]); // expression in the shader is // (v*2.0-1.0)*UnqNeighborhoods_Scale_0_3 + UnqNeighborhoods_Mean_0_3 // => this is baked into the ants to reduce work load qn_mean_0_3 = qn_mean_0_3 - qn_scale_0_3; qn_scale_0_3 = qn_scale_0_3 * 2.0f; }
// Apply a Gaussian filter of size filtersz - separable implementation private MultiDimFloatTexture applyGaussianFilter_Separable(int filtersz) { // . compute Gauss kernel MultiDimFloatTexture kernel = new MultiDimFloatTexture(filtersz, 1, 1); float sum = 0; for (int i = 0; i < filtersz; i++) { float di = (float)(i - filtersz / 2); float u2 = (di * di) / ((float)filtersz * filtersz); float sigma = 1.0f / 3.0f; // > 3 std dev => assume 0 kernel.set((float)Math.Exp(-u2 / (2.0f * sigma * sigma)), i, 0, 0); sum += kernel.get(i, 0, 0); } // . normalize for (int i = 0; i < filtersz; i++) { kernel.set(kernel.get(i, 0, 0) / sum, i, 0, 0); } // . alloc result and tmp buffer (initialized to 0) MultiDimFloatTexture tmp = new MultiDimFloatTexture(m_iW, m_iH, m_iNumComp); MultiDimFloatTexture res = new MultiDimFloatTexture(m_iW, m_iH, m_iNumComp); // . convolve - pass 1 (treat texture as toroidal) for (int v = 0; v < m_iH; v++) { for (int u = 0; u < m_iW; u++) { for (int i = 0; i < filtersz; i++) { int x = u + i - filtersz / 2; int y = v; for (int c = 0; c < numComp(); c++) { float val = tmp.get(u, v, c); tmp.set(val + ((float)getmod(x, y, c)) * kernel.get(i, 0, 0), u, v, c); } } } } // . convolve - pass 2 (treat texture as toroidal) for (int v = 0; v < m_iH; v++) { for (int u = 0; u < m_iW; u++) { for (int j = 0; j < filtersz; j++) { int x = u; int y = v + j - filtersz / 2; for (int c = 0; c < m_iNumComp; c++) { float val = res.get(u, v, c); res.set(val + ((float)tmp.getmod(x, y, c)) * kernel.get(j, 0, 0), u, v, c); } } } } kernel = null; tmp = null; return(res); }
// ----------------------------------------------------- MultiDimFloatTexture enlargeTexture(MultiDimFloatTexture ex, int type) { ScopeTimer tm = new ScopeTimer("[Exemplar::enlargeTexture]"); int w = ex.getWidth(); int h = ex.getHeight(); MultiDimFloatTexture large = new MultiDimFloatTexture(w * 2, h * 2, ex.numComp()); for (int j = 0; j < h * 2; j++) { for (int i = 0; i < w * 2; i++) { int ri, rj; // where to read ? if (type == 0) { // Toroidal // ri if (i < w / 2) { ri = (i + w / 2) % w; } else if (i < w + w / 2) { ri = i - w / 2; } else { ri = ((i - w / 2) % w); } // rj if (j < h / 2) { rj = (j + h / 2) % h; } else if (j < h + h / 2) { rj = j - h / 2; } else { rj = ((j - h / 2) % h); } } else { // Mirror // ri if (i < w / 2) { ri = (w / 2 - i); } else if (i < w + w / 2) { ri = i - w / 2; } else { ri = (w - 1 - (i - (w / 2 + w))); } // rj if (j < h / 2) { rj = (h / 2 - j); } else if (j < h + h / 2) { rj = j - h / 2; } else { rj = (h - 1 - (j - (h / 2 + h))); } } for (int c = 0; c < ex.numComp(); c++) { large.set(ex.get(ri, rj, c), i, j, c); } } } tm.destroy(); tm = null; return(large); }
void computeSynthNeighborhoods() { ScopeTimer tm = new ScopeTimer("[computeSynthNeighborhoods]"); m_SynthNeighborhoods = new NeighborhoodSynth[mNumLevels][]; // foreach level for (int level = 0; level < mNumLevels; level++) { MultiDimFloatTexture recolored_level = null; if (Globals.isDefined("4D")) { // . keep only 4 dimension from recolored exemplar MultiDimFloatTexture level_4D = new MultiDimFloatTexture(mOwner.recoloredStack(level).width(), mOwner.recoloredStack(level).height(), mOwner.recoloredStack(level).numComp()); int w = level_4D.getWidth(); int h = level_4D.getHeight(); Globals.Assert(w == mOwner.stack(level).getWidth() && h == mOwner.stack(level).height()); Globals.Assert(level_4D.numComp() == Globals.NUM_RECOLORED_PCA_COMPONENTS); for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { // . copy first four channels for (int c = 0; c < 4; c++) { level_4D.set(mOwner.recoloredStack(level).get(i, j, c), i, j, c); } // . zero out all channels above 4 for (int c = 4; c < level_4D.numComp(); c++) { level_4D.set(0, i, j, c); } } } recolored_level = level_4D; } else { // . keep all dimensions recolored_level = mOwner.recoloredStack(level); } m_SynthNeighborhoods[level] = new NeighborhoodSynth[recolored_level.width() * recolored_level.height()]; stack_accessor_v2 access = new stack_accessor_v2(level); for (int j = 0; j < recolored_level.height(); j++) { for (int i = 0; i < recolored_level.width(); i++) { int index = i + j * recolored_level.width(); m_SynthNeighborhoods[level][index] = new NeighborhoodSynth(); m_SynthNeighborhoods[level][index].construct( recolored_level, access, (!mOwner.isToroidal()) && level < (mNumLevels - Globals.NUM_LEVELS_WITHOUT_BORDER), //(!m_bToroidal) && l < FIRST_LEVEL_WITH_BORDER, level, i, j); } } } tm.destroy(); tm = null; }