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; }
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; }
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; }