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); }
// constructs a neighborhood from a list of offsets public void construct(MultiDimFloatTexture t, accessor access, bool checkcrossing, int l, int i, int j) { //CLM this used to be static... s_OffsetTable = new OffsetTableInitializer(Globals.NeighborhoodSynth_NUM_NEIGHBORS); m_iI = (short)i; m_iJ = (short)j; m_bCrossing = false; int w = t.getWidth(); int h = t.getHeight(); int n = 0; for (int k = 0; k < T_iNumNeighbors; k++) { int offsi = s_OffsetTable.m_OffsetTable[k][0]; int offsj = s_OffsetTable.m_OffsetTable[k][1]; int ni = 0, nj = 0; access.neigh_ij(i, j, offsi, offsj, ref ni, ref nj); ni = ((ni % w) + w) % w; // FIXME TODO make this faster nj = ((nj % h) + h) % h; for (int c = 0; c < T_iC; c++) { float v = t.get(ni, nj, c); m_Values[n++] = v; } } // border detection // . if the neighborhood crosses the boundary of a non-toroidal texture, // it will not be used as a candidate. Therefore, synthesis will not use it. if (checkcrossing) //l < FIRST_LEVEL_WITH_BORDER) // FIXME TODO: how to choose this automatically ? { int hl = (1 << l); if (i < Globals.NeighborhoodSynth_SIZE / 2 * hl || i >= w - Globals.NeighborhoodSynth_SIZE / 2 * hl) { m_bCrossing = true; } if (j < Globals.NeighborhoodSynth_SIZE / 2 * hl || j >= h - Globals.NeighborhoodSynth_SIZE / 2 * hl) { m_bCrossing = true; } } Globals.Assert(n == e_numdim); }
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); }
public Quantizer(MultiDimFloatTexture tex, int qbits, float percent) { Globals.Assert(percent > 0.0f && percent <= 100.0f); ScopeTimer tm = new ScopeTimer("[Quantizer]"); m_Texture = tex; m_Quantized = new MultiDimIntTexture(tex.width(), tex.height(), tex.numComp()); m_iQBits = qbits; m_Mean = new float[tex.numComp()]; m_StdDev = new float[tex.numComp()]; m_Center = new float[tex.numComp()]; m_Radius = new float[tex.numComp()]; // . compute std dev and mean of every components float [] sum = new float[tex.numComp()]; float [] sumsq = new float[tex.numComp()]; for (int j = 0; j < tex.height(); j++) { for (int i = 0; i < tex.width(); i++) { for (int c = 0; c < tex.numComp(); c++) { float f = tex.get(i, j, c); sum[c] += f; sumsq[c] += f * f; } } } float num = (float)(tex.width() * tex.height()); for (int c = 0; c < tex.numComp(); c++) { m_Mean[c] = sum[c] / num; float sqstddev = (sumsq[c] - sum[c] * sum[c] / num) / (num - 1.0f); if (sqstddev > BMathLib.cFloatCompareEpsilon) { m_StdDev[c] = (float)Math.Sqrt(sqstddev); } else { m_StdDev[c] = 0.0f; } } // . for every component // compute center and radius so that 'percent' samples are within quantization space for (int c = 0; c < tex.numComp(); c++) { float [] samples = new float[tex.width() * tex.height()]; // add samples to array for (int j = 0; j < tex.height(); j++) { for (int i = 0; i < tex.width(); i++) { samples[i + j * tex.width()] = tex.get(i, j, c); } } // sort array Sort.RadixSort rs = new Sort.RadixSort(); rs.Sort(samples);//sort(samples.begin(),samples.end()); // find left and right elements so that 'percent' elements are inside float pout = ((100.0f - percent) / 2) / 100.0f; int left = (int)((samples.Length - 1) * pout); int right = (int)((samples.Length - 1) * (1.0f - pout)); m_Center[c] = (samples[right] + samples[left]) / 2.0f; m_Radius[c] = samples[right] - samples[left]; } // . quantize int num_outside = 0; for (int j = 0; j < tex.height(); j++) { for (int i = 0; i < tex.width(); i++) { if (!quantizePixel(tex.numComp(), tex, tex.getpixIndex(i, j), m_Quantized.getpixIndex(i, j))) { num_outside++; } } } float percent_out = num_outside * 100.0f / (tex.width() * tex.height()); if (Globals.PRINT_DEBUG_MSG) { Debug.Print("-----------.>> Quantizer: num outside = " + percent_out + "%"); } tm.destroy(); tm = null; }
// 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); }