// Returns a map of focus ranks, defined as follows: // for each pixel C of input image (but borders) // for each pixel N of center's neighborhood // accumulate |C-P| * W where W is a weight depending on distance between C and N public FloatMap GetContrastMap(FloatMap imgfIn) { const float k1 = 0.104167f; const float k2 = 0.145833f; int h = imgfIn.H; int w = imgfIn.W; int stride = imgfIn.Stride; var contrImgfs = new FloatMap(w, h); int lineStart = stride; for (int y = 1; y < h - 1; ++y) { var i = lineStart + 1; for (int x = 1; x < w - 2; ++x) // -2 ????? { var c = imgfIn[i]; // TODO: Optimize with scanlines contrImgfs[i] = (Math.Abs(c - imgfIn[i + stride]) + Math.Abs(c - imgfIn[i - stride]) + Math.Abs(c - imgfIn[i + 1]) + Math.Abs(c - imgfIn[i - 1])) * k2 + (Math.Abs(c - imgfIn[i + stride + 1]) + Math.Abs(c - imgfIn[i + stride - 1]) + Math.Abs(c - imgfIn[i - stride + 1]) + Math.Abs(c - imgfIn[i - stride - 1])) * k1; i += 1; } lineStart += stride; } return(contrImgfs); }
// Blurs image; this has been written quickly and without reference; // should be modified in order to use a true gaussian kernel; // is left as is because shortly all convolution-like functions // will be handled by a single method (possibly with OpenCL) public FloatMap QuickBlurMap(FloatMap imgfIn) { int h = imgfIn.H; int w = imgfIn.W; int stride = imgfIn.Stride; var imgfOut = new FloatMap(w, h); const float k1 = 0.1715728f; // w = 2 const float k2 = 0.0857864f; // w = 1 const float k3 = 0.0606601f; // w = 1/1.4 = 0.7 int lineStart = stride; for (int y = 1; y < h - 1; ++y) { int i = lineStart + 1;; for (int x = 1; x < w - 1; ++x) { imgfOut[i] = (imgfIn[i]) * k1 + (imgfIn[i + stride] + imgfIn[i - stride] + imgfIn[i + 1] + imgfIn[i - 1]) * k2 + (imgfIn[i + stride + 1] + imgfIn[i + stride - 1] + imgfIn[i - stride + 1] + imgfIn[i - stride - 1]) * k3; ++i; } lineStart += stride; } return(imgfOut); }
// Returns an image which sizes are each half the original value; // will be probably replaced with reduction/expansion-style OpenCl operation public FloatMap HalfMap(FloatMap imgfIn) { int h = imgfIn.H; int w = imgfIn.W; int stride = imgfIn.Stride; int hh = h >> 1; int hw = w >> 1; var imgfOut = new FloatMap(hw, hh); int hStride = imgfOut.Stride; int lineStart = 0; int hLineStart = 0; for (int y = 0; y < hh; ++y) { int i = lineStart; int hi = hLineStart; for (int x = 0; x < hw; ++x) { imgfOut[hi] = (imgfIn[i] + imgfIn[i + stride] + imgfIn[i + 1] + imgfIn[i + stride + 1]) * 0.25f; i += 2; ++hi; } lineStart += stride << 1; hLineStart += hStride; } return(imgfOut); }
// returns an image which sizes are each double the original value; // will be probably replaced with reduction/expansion-style // OpenCl operation public FloatMap DoubleMap(FloatMap imgfIn) { int h = imgfIn.H; int w = imgfIn.W; int dh = h * 2; int dw = w * 2; var imgfOut = new FloatMap(dw, dh); int dstStride = imgfOut.Stride; float dx = 0, dy = 0; int dLineStart = 0; for (int y = 0; y < dh - 2; ++y) { dx = 0; int i = dLineStart; for (int x = 0; x < dw - 2; ++x) { imgfOut[i] = imgfIn[dx, dy]; dx += 0.5f; ++i; } dy += 0.5f; dLineStart += dstStride; } return(imgfOut); }
public static FloatMap GaussianBlur(FloatMap imgfIn, float sigma) { FloatMap blurMask = createBlurMask(sigma); bool dummy; return(convolute(imgfIn, blurMask, out dummy)); }
// http://www.thebigblob.com/gaussian-blur-using-opencl-and-the-built-in-images-textures/ // http://haishibai.blogspot.it/2009/09/image-processing-c-tutorial-4-gaussian.html FloatMap createBlurMask(float sigma) { int maskSize = (int)Math.Ceiling(3.0f * sigma); int _2maskSizePlus1 = (maskSize << 1) + 1; // stupid C# compiler gives precedence to sum FloatMap mask = new FloatMap(_2maskSizePlus1, _2maskSizePlus1); float sum = 0.0f; float temp = 0.0f; float _2sigmaSqrInvNeg = -1 / (sigma * sigma * 2); for (int a = -maskSize; a <= maskSize; ++a) { for (int b = -maskSize; b <= maskSize; ++b) { temp = (float)Math.Exp(((float)(a * a + b * b) * _2sigmaSqrInvNeg)); sum += temp; mask[a + maskSize + (b + maskSize) * _2maskSizePlus1] = temp; } } // Normalize the mask int _2maskSizePlus1Sqr = _2maskSizePlus1 * _2maskSizePlus1; for (int i = 0; i < _2maskSizePlus1Sqr; ++i) { mask[i] = mask[i] / sum; } return(mask); }
// Resizes map to arbitrary size (but it's better suited to upscale) public FloatMap ResizeMap(FloatMap imgfIn, int dstW, int dstH) { int srcH = imgfIn.H; int srcW = imgfIn.W; float xk = (float)srcW / (float)dstW; float yk = (float)srcH / (float)dstH; FloatMap imgOut = new FloatMap(dstW, dstH); int stride = imgOut.Stride; float dy = 0; int lineStart = 0; for (int y = 0; y < dstH; ++y) { float dx = 0; int i = lineStart; for (int x = 0; x < dstW; ++x) { imgOut[i] = imgfIn[dx, dy]; dx += xk; ++i; } lineStart += stride; dy += yk; } return(imgOut); }
// images cannot be read_write... so let's continue using plain buffers // should implement this in a way that allows imgfAccu to be loaded only once // should test for image size consistency public void Accumulate(FloatMap imgfAccu, FloatMap imgfSrc, float k) { var kernel = _kernels["accumulate"]; // Creation of on-device memory objects IMem <float> accuMapBuffer = Cl.CreateBuffer <float>(_context, MemFlags.ReadWrite, imgfAccu.Size, out err); // why MemFlags.CopyHostPtr doesn't work here (and forces me to manual copy) ??? assert(err, "accu buf creation"); IMem <float> srcMapBuffer = Cl.CreateBuffer <float>(_context, MemFlags.WriteOnly, imgfSrc.Size, out err); assert(err, "src buf creation"); // Set memory objects as parameters to kernel err = Cl.SetKernelArg(kernel, 0, intPtrSize, accuMapBuffer); assert(err, "accu map setKernelArg"); err = Cl.SetKernelArg(kernel, 1, intPtrSize, srcMapBuffer); assert(err, "src map setKernelArg"); err = Cl.SetKernelArg(kernel, 2, intSize, imgfAccu.Stride); assert(err, "in stride setKernelArg"); err = Cl.SetKernelArg(kernel, 3, intSize, imgfSrc.Stride); assert(err, "out stride setKernelArg"); err = Cl.SetKernelArg(kernel, 4, floatSize, k); assert(err, "out stride setKernelArg"); // write actual data into memory object Event clevent; err = Cl.EnqueueWriteBuffer <float>(_commandsQueue, accuMapBuffer, Bool.True, 0, imgfAccu.Size, imgfAccu._buf, 0, null, out clevent); clevent.Dispose(); assert(err, "write accu buffer"); err = Cl.EnqueueWriteBuffer <float>(_commandsQueue, srcMapBuffer, Bool.True, 0, imgfSrc.Size, imgfSrc._buf, 0, null, out clevent); clevent.Dispose(); assert(err, "write src buffer"); // execute err = Cl.EnqueueNDRangeKernel(_commandsQueue, kernel, 2, new[] { (IntPtr)0, (IntPtr)0, (IntPtr)0 }, // offset new[] { new IntPtr(imgfAccu.W), new IntPtr(imgfAccu.H), (IntPtr)1 }, // range null, 0, null, out clevent); clevent.Dispose(); assert(err, "Cl.EnqueueNDRangeKernel"); // sync Cl.Finish(_commandsQueue); // read from output memory object into actual buffer err = Cl.EnqueueReadBuffer <float>(_commandsQueue, accuMapBuffer, Bool.True, imgfAccu._buf, 0, null, out clevent); clevent.Dispose(); assert(err, "read output buffer"); Cl.ReleaseMemObject(srcMapBuffer); Cl.ReleaseMemObject(accuMapBuffer); // maybe i could return this without disposing; would affect non-OpenCl implementation }
// Returns an image which sizes are each 2^times the original value; // will be probably replaced with reduction/expansion-style // OpenCl operation public FloatMap DoubleMap(FloatMap imgfIn, int times) { for (int i = 0; i < times; ++i) { imgfIn = DoubleMap(imgfIn); } return(imgfIn); }
// Returns an image which sizes are each 1/2^times the original value; // will be probably replaced with reduction/expansion-style OpenCl operation public static FloatMap HalfMap(FloatMap imgfIn, int times) { for (int i = 0; i < times; ++i) { imgfIn = HalfMap(imgfIn); } return(imgfIn); }
// not so tailored for SIMT... public void Accumulate(FloatMap imgfAccu, FloatMap imgfSrc, float k) { var kernel = _kernels["accumulate"]; // Creation of on-device memory objects IMem<float> accuMapBuffer = Cl.CreateBuffer<float>(_context, MemFlags.ReadWrite, imgfAccu.Size, out err); assert(err, "accu buf creation"); IMem<float> srcMapBuffer = Cl.CreateBuffer<float>(_context, MemFlags.WriteOnly, imgfSrc.Size, out err); assert(err, "src buf creation"); // Set memory objects as parameters to kernel err = Cl.SetKernelArg(kernel, 0, intPtrSize, accuMapBuffer); assert(err, "accu map setKernelArg"); err = Cl.SetKernelArg(kernel, 1, intPtrSize, srcMapBuffer); assert(err, "src map setKernelArg"); err = Cl.SetKernelArg(kernel, 2, intSize, imgfAccu.Stride); assert(err, "in stride setKernelArg"); err = Cl.SetKernelArg(kernel, 3, intSize, imgfSrc.Stride); assert(err, "out stride setKernelArg"); err = Cl.SetKernelArg(kernel, 4, floatSize, k); assert(err, "out stride setKernelArg"); // write actual data into memory object Event clevent; err = Cl.EnqueueWriteBuffer<float>(_commandsQueue, accuMapBuffer, Bool.True, 0, imgfAccu.Size, imgfAccu._buf, 0, null, out clevent); clevent.Dispose(); assert(err, "write accu buffer"); err = Cl.EnqueueWriteBuffer<float>(_commandsQueue, srcMapBuffer, Bool.True, 0, imgfSrc.Size, imgfSrc._buf, 0, null, out clevent); clevent.Dispose(); assert(err, "write src buffer"); // execute err = Cl.EnqueueNDRangeKernel(_commandsQueue, kernel, 2, new[] { (IntPtr)0, (IntPtr)0, (IntPtr)0 }, // offset new[] { new IntPtr(imgfAccu.W), new IntPtr(imgfAccu.H), (IntPtr)1 }, // range null, 0, null, out clevent); clevent.Dispose(); assert(err, "Cl.EnqueueNDRangeKernel"); // sync Cl.Finish(_commandsQueue); // read from output memory object into actual buffer err = Cl.EnqueueReadBuffer<float>(_commandsQueue, accuMapBuffer, Bool.True, imgfAccu._buf, 0, null, out clevent); clevent.Dispose(); assert(err, "read output buffer"); err = Cl.ReleaseMemObject(accuMapBuffer); assert(err, "releasing accuMapBuffer mem object"); err = Cl.ReleaseMemObject(srcMapBuffer); assert(err, "releasing srcMapBuffer mem object"); }
public FloatMap GetContrastMap(FloatMap inMap) { var k = _kernels["getContrastImg"]; FloatMap outMap = new FloatMap(inMap.W, inMap.H); singlePass(k, inMap, outMap); return(outMap); }
// bleach!! should initialize two memory objects and ping-pong with them public FloatMap CapHoles(FloatMap inMap, int filterHalfSize) { for (int i = 0; i < 5; ++i) // since it's very difficult to set a bool (result of an or for each map element) from the kernel, let's just do it an arbitrary amount of times { inMap = capHoles(inMap, filterHalfSize); } return(inMap); }
public void singlePass(Kernel kernel, FloatMap inMap, FloatMap outMap) { var clInImageFormat = new OpenCL.Net.ImageFormat(ChannelOrder.Luminance, ChannelType.Float); IMem inputMapBuffer = Cl.CreateImage2D(_context, MemFlags.CopyHostPtr | MemFlags.ReadOnly, clInImageFormat, (IntPtr)inMap.W, (IntPtr)inMap.H, new IntPtr(inMap.Stride * sizeof(float)), inMap._buf, out err); assert(err, "input img creation"); IMem outputMapBuffer = Cl.CreateImage2D(_context, MemFlags.WriteOnly, clInImageFormat, (IntPtr)outMap.W, (IntPtr)outMap.H, new IntPtr(outMap.Stride * sizeof(float)), outMap._buf, out err); assert(err, "output img creation"); // Set memory objects as parameters to kernel err = Cl.SetKernelArg(kernel, 0, intPtrSize, inputMapBuffer); assert(err, "input map setKernelArg"); err = Cl.SetKernelArg(kernel, 1, intPtrSize, outputMapBuffer); assert(err, "output map setKernelArg"); // write actual data into memory object IntPtr[] originPtr = new IntPtr[] { (IntPtr)0, (IntPtr)0, (IntPtr)0 }; //x, y, z IntPtr[] inRegionPtr = new IntPtr[] { (IntPtr)inMap.W, (IntPtr)inMap.H, (IntPtr)1 }; //x, y, z IntPtr[] outRegionPtr = new IntPtr[] { (IntPtr)outMap.W, (IntPtr)outMap.H, (IntPtr)1 }; //x, y, z IntPtr[] workGroupSizePtr = new IntPtr[] { (IntPtr)outMap.W, (IntPtr)outMap.H, (IntPtr)1 }; Event clevent; //err = Cl.EnqueueWriteImage(_commandsQueue, inputMapBuffer, Bool.True, originPtr, inRegionPtr, (IntPtr)0, (IntPtr)0, inMap._buf, 0, null, out clevent); //clevent.Dispose(); //assert(err, "write input img"); // execute err = Cl.EnqueueNDRangeKernel(_commandsQueue, kernel, 2, originPtr, workGroupSizePtr, null, 0, null, out clevent); clevent.Dispose(); assert(err, "Cl.EnqueueNDRangeKernel"); // sync Cl.Finish(_commandsQueue); // read from output memory object into actual buffer err = Cl.EnqueueReadImage(_commandsQueue, outputMapBuffer, Bool.True, originPtr, outRegionPtr, new IntPtr(outMap.Stride * sizeof(float)), (IntPtr)0, outMap._buf, 0, null, out clevent); clevent.Dispose(); assert(err, "read output buffer"); Cl.ReleaseMemObject(inputMapBuffer); Cl.ReleaseMemObject(outputMapBuffer); }
// Caps holes taking values (weighted by distance) from neighborhood // for interpolation; filter can cap holes as large as filterHalfSize*2; // multiple passes could be needed. public static FloatMap CapHoles(FloatMap imgfIn, int filterHalfSize) { bool thereAreStillHoles = true; while (thereAreStillHoles) { imgfIn = MapUtils.capHoles(imgfIn, filterHalfSize, out thereAreStillHoles); } return(imgfIn); }
public FloatMap HalfMap(FloatMap inMap) { var k1 = _kernels["halfSizeImgH"]; var k2 = _kernels["halfSizeImgV"]; FloatMap outMap = new FloatMap(inMap.W / 2, inMap.H / 2); doublePass(k1, k2, inMap, outMap, inMap.W / 2, inMap.H); return(outMap); }
public FloatMap QuickBlurMap(FloatMap inMap) { var k1 = _kernels["quickBlurImgH"]; var k2 = _kernels["quickBlurImgV"]; FloatMap outMap = new FloatMap(inMap.W, inMap.H); doublePass(k1, k2, inMap, outMap); return(outMap); }
public FloatMap ResizeMap(FloatMap imgfIn, int dstW, int dstH) { int srcH = imgfIn.H; int srcW = imgfIn.W; float xk = (float)srcW / (float)dstW; float yk = (float)srcH / (float)dstH; return(invokeMapKernel(_kernels["upsizel"], imgfIn, dstW, dstH, dstW, dstH, 0, 0, xk, yk)); }
FloatMap convolve(FloatMap imgfIn, FloatMap filter) { int filterSize = filter.W; int filterHalfSize = filterSize / 2; int h = imgfIn.H; int w = imgfIn.W; var imgfOut = new FloatMap(w, h); for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { // if point in [x,y] == -1 then cap that: // foreach a,b from x-filtersize to x+filtersize (same for y) // if that point is != -1 accumulate that * weight[a,b], accumulate weight[a,b] float accu = 0; float wAccu = 0; int cMinX = x - filterHalfSize; int cMinY = y - filterHalfSize; int minX = Math.Max(0, cMinX); int minY = Math.Max(0, cMinY); int xOffs = minX - cMinX; int yOffs = minY - cMinY; int maxX = Math.Min(w, x + filterHalfSize); int maxY = Math.Min(h, y + filterHalfSize); for (int b = minY, fb = yOffs; b < maxY; ++b, ++fb) { for (int a = minX, fa = xOffs; a < maxX; ++a, ++fa) { float v = imgfIn[a, b]; if (v >= 0) { float weight = filter[fa, fb]; wAccu += weight; accu += v * weight; } } } if (wAccu != 0) { imgfOut[x, y] = accu / wAccu; } else { imgfOut[x, y] = -1; } } } return(imgfOut); }
// Caps holes taking values (weighted by distance) from neighborhood // for interpolation; filter can cap holes as large as filterHalfSize*2; // multiple passes could be needed. public FloatMap CapHoles(FloatMap imgfIn, int filterHalfSize) { var mask = getDistanceWeightMap(filterHalfSize); bool thereAreStillHoles = true; while (thereAreStillHoles) { imgfIn = convolvec(imgfIn, mask, out thereAreStillHoles); } return(imgfIn); }
public FloatMap CapHoles(FloatMap imgfIn, int filterHalfSize) { var mask = getDistanceWeightMap(filterHalfSize); var kernel = _kernels["capHoles"]; for (int i = 0; i < 5; ++i) // since it's very difficult to set a bool (result of an or for each map element) from the kernel, let's just do it an arbitrary amount of times { imgfIn = invokeConvolve(kernel, imgfIn, mask); } return(imgfIn); }
public FloatMap SpikesFilter(FloatMap inMap, float treshold) { var k = _kernels["quickSpikesFilterImg"]; FloatMap outMap = new FloatMap(inMap.W, inMap.H); err = Cl.SetKernelArg(k, 2, floatSize, treshold); assert(err, "treshold, setKernelArg"); singlePass(k, inMap, outMap); return(outMap); }
// Creates the blue-red depth map public static Bitmap Map2BmpDepthMap(FloatMap imgf, float k, int count) { int h = imgf.H; int w = imgf.W; int stride = imgf.Stride; var bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb); BitmapData dstData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); int pixelSize = 4; unsafe { var dstStride = dstData.Stride; byte *dstRow = (byte *)dstData.Scan0; int srcLineStart = 0; for (int y = 0; y < h; ++y) { int srcIdx = srcLineStart; int wb = w * pixelSize; for (int x = 0; x < wb; x += 4) { float v = imgf[srcIdx]; v = v < 0 ? -1 : 255 - v * 255 / count; if (v >= 0) { byte b = (byte)Math.Min(255, Math.Max((v * k), 0)); dstRow[x] = b; dstRow[x + 1] = 0; dstRow[x + 2] = (byte)(255 - b); dstRow[x + 3] = 255; } else { dstRow[x] = 0; dstRow[x + 1] = 0; dstRow[x + 2] = 0; dstRow[x + 3] = 255; } ++srcIdx; } srcLineStart += stride; dstRow += dstStride; } } bmp.UnlockBits(dstData); return(bmp); }
// Converts from bitmap 32bpp ARGB to float map public FloatMap Bmp2Map(Bitmap bmp) { var w = bmp.Width; var h = bmp.Height; Bitmap tmp = null; if (bmp.PixelFormat != PixelFormat.Format32bppArgb) { bmp = bmp.Clone(new Rectangle(0, 0, w, h), System.Drawing.Imaging.PixelFormat.Format32bppArgb); tmp = bmp; } var imgf = new FloatMap(w, h); int stride = imgf.Stride; int pixelSize = 4; BitmapData srcData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); unsafe { byte *srcRow = (byte *)srcData.Scan0; int srcStride = srcData.Stride; int dstLineStart = 0; for (int y = 0; y < h; ++y) { int dstIdx = dstLineStart; int wb = w * pixelSize; for (int x = 0; x < wb; x += pixelSize) { // considers Y component; in future, it would be nice to let user choose between single channels, luma, average, ... imgf[dstIdx] = getLuminance(srcRow[x + 0], srcRow[x + 1], srcRow[x + 2]); // +3 is alpha ++dstIdx; } dstLineStart += stride; srcRow += srcStride; } } bmp.UnlockBits(srcData); if (tmp != null) { tmp.Dispose(); // disposing our cloned copy... caller is responsible to dispose original bmp } return(imgf); }
// Converts from bitmap 32bpp ARGB to float map public FloatMap Bmp2Map(Bitmap bmp) { var w = bmp.Width; var h = bmp.Height; Bitmap tmp = null; if (bmp.PixelFormat != PixelFormat.Format32bppArgb) { bmp = bmp.Clone(new Rectangle(0, 0, w, h), System.Drawing.Imaging.PixelFormat.Format32bppArgb); tmp = bmp; } var imgf = new FloatMap(w, h); int stride = imgf.Stride; int pixelSize = 4; BitmapData srcData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); unsafe { byte* srcRow = (byte*)srcData.Scan0; int srcStride = srcData.Stride; int dstLineStart = 0; for (int y = 0; y < h; ++y) { int dstIdx = dstLineStart; int wb = w * pixelSize; for (int x = 0; x < wb; x += pixelSize) { // considers Y component; in future, it would be nice to let user choose between single channels, luma, average, ... imgf[dstIdx] = getLuminance(srcRow[x + 0], srcRow[x + 1], srcRow[x + 2]); // +3 is alpha ++dstIdx; } dstLineStart += stride; srcRow += srcStride; } } bmp.UnlockBits(srcData); if (tmp != null) { tmp.Dispose(); // disposing our cloned copy... caller is responsible to dispose original bmp } return imgf; }
// again: should initialize two memory objects and ping-pong with them (but this method is not crytical, after all) public float GetMapMax(FloatMap inMap) { var k1 = _kernels["maxReduceImgH"]; var k2 = _kernels["maxReduceImgV"]; FloatMap outMap = new FloatMap((int)Math.Ceiling(inMap.W / 2.0f), (int)Math.Ceiling(inMap.H / 2.0f)); while (true) { doublePass(k1, k2, inMap, outMap, (int)Math.Ceiling(inMap.W / 2.0f), inMap.H); if ((outMap.W == 1) && (outMap.W == 1)) { return(outMap[0, 0]); } inMap = outMap; outMap = new FloatMap((int)Math.Ceiling(inMap.W / 2.0f), (int)Math.Ceiling(inMap.H / 2.0f)); } }
FloatMap getMaxMap() { int h = _imgfs[0].H; int w = _imgfs[0].W; FloatMap imgfOut = new FloatMap(w, h); for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { float v = getMaxIdx(x, y); imgfOut[x, y] = v;// < 0 ? -1 : 255 - v * 255 / _imgfs.Count; // MOVED into map2BmpDepth } } return(imgfOut); }
public FloatMap GetMultiResContrastEvaluation(FloatMap imgfIn, int subSamples) { int h = imgfIn.H; int w = imgfIn.W; float k = 1; FloatMap contr = new FloatMap(w, h); var img = imgfIn; for (int i = 0; i < subSamples; ++i) { var rc = ResizeMap(QuickBlurMap(GetContrastMap(img)), w, h); Accumulate(contr, rc, k); k *= 0.5f; img = HalfMap(img); } return(contr); }
// Computes some sort of resolution independant contrast defined as follows // (don't know yet if it's ok or not) // compute contrast map on input map, then // downscales the image, gets the contrast map again, scales up contrast map to // original size and accumulates in original input map. Repeat several times. // Arguably, it could be computed more efficiently, but i don't care // optimizing code that will still have to be changed several times. public FloatMap GetMultiResContrastEvaluation(FloatMap imgfIn, int subSamples) { int h = imgfIn.H; int w = imgfIn.W; float k = 1; FloatMap contr = new FloatMap(w, h); var img = imgfIn; for (int i = 0; i < subSamples; ++i) { var rc = ResizeMap(QuickBlurMap(GetContrastMap(img)), w, h); //var rc = DoubleImg(BlurImg(GetContrImg(img)), i); // <-- multi step reduction would still be first choice with openCl Accumulate(contr, rc, k); k *= 0.5f; img = HalfMap(img); } return(contr); }
public FloatMap ResizeMap(FloatMap inMap, int dstW, int dstH) { float xk = (float)inMap.W / (float)dstW; float yk = (float)inMap.H / (float)dstH; FloatMap outMap = new FloatMap(dstW, dstH); var k = _kernels["upsizeImg"]; err = Cl.SetKernelArg(k, 2, floatSize, xk); assert(err, "xk setKernelArg"); err = Cl.SetKernelArg(k, 3, floatSize, yk); assert(err, "yk setKernelArg"); singlePass(k, inMap, outMap); return(outMap); }
private FloatMap getDistanceWeightMap(int filterHalfSize) { int size = filterHalfSize * 2 + 1; int sup = size - 1; FloatMap wMap = new FloatMap(size, size); for (int y = 0; y < filterHalfSize; ++y) { for (int x = 0; x <= filterHalfSize; ++x) { float dx = (filterHalfSize - x); float dy = (filterHalfSize - y); wMap[x, y] = wMap[y, sup - x] = wMap[sup - y, x] = wMap[sup - x, sup - y] = (float)(1.0 / Math.Sqrt(dx * dx + dy * dy)); } } wMap[filterHalfSize, filterHalfSize] = 0; return(wMap); }
public FloatMap GaussianBlur(FloatMap inMap, float sigma) { var k = _kernels["convolveImg"]; FloatMap outMap = new FloatMap(inMap.W, inMap.H); FloatMap mask = createBlurMask(sigma); IMem <float> maskBuf = Cl.CreateBuffer <float>(_context, MemFlags.CopyHostPtr | MemFlags.ReadOnly, mask._buf, out err); assert(err, "capholes mask, mem object creation"); err = Cl.SetKernelArg(k, 2, intPtrSize, maskBuf); assert(err, "capholes mask, setKernelArg"); err = Cl.SetKernelArg(k, 3, intSize, (mask.W - 1) / 2); assert(err, "capholes mask, setKernelArg"); singlePass(k, inMap, outMap); return(outMap); }
// Sets each pixel P in accumulation map to PValue + QValue, // where Q is corresponding pixel in the other provided map public void Accumulate(FloatMap imgfInAccu, FloatMap imgfIn, float k) { int h = imgfInAccu.H; int w = imgfInAccu.W; int stride = imgfInAccu.Stride; if ((imgfIn.H != h) || (imgfIn.W != w)) { throw new Exception("Images must have same size!"); } int lineStart = 0; for (int y = 0; y < h; ++y) { var i = lineStart; for (int x = 0; x < w; ++x) { imgfInAccu[i] = imgfInAccu[i] + imgfIn[i] * k; i += 1; } lineStart += stride; } }
// Returns maximum value in a map; // used to show normalized bitmaps public static float GetMapMax(FloatMap imgfIn) { int h = imgfIn.H; int w = imgfIn.W; int stride = imgfIn.Stride; float max = float.MinValue; float min = float.MaxValue; int lineStart = 0; for (int y = 0; y < h; ++y) { var i = lineStart; for (int x = 0; x < w; ++x) { var v = imgfIn[i]; if (v > max) { max = v; } // debug only if ((v > 0) && (v < min)) { min = v; } i += 1; } lineStart += stride; } Console.WriteLine("\n\nmin: {0}\nmax: {1}\n\n", min, max); return max; }
// Returns a map of focus ranks, defined as follows: // for each pixel C of input image (but borders) // for each pixel N of center's neighborhood // accumulate |C-P| * W where W is a weight depending on distance between C and N public static FloatMap GetContrastMap(FloatMap imgfIn) { const float k1 = 0.104167f; const float k2 = 0.145833f; int h = imgfIn.H; int w = imgfIn.W; int stride = imgfIn.Stride; var contrImgfs = new FloatMap(w, h); int lineStart = stride; for (int y = 1; y < h - 1; ++y) { var i = lineStart + 1; for (int x = 1; x < w - 2; ++x) // -2 ????? { var c = imgfIn[i]; // TODO: Optimize with scanlines contrImgfs[i] = (Math.Abs(c - imgfIn[i + stride]) + Math.Abs(c - imgfIn[i - stride]) + Math.Abs(c - imgfIn[i + 1]) + Math.Abs(c - imgfIn[i - 1])) * k2 + (Math.Abs(c - imgfIn[i + stride + 1]) + Math.Abs(c - imgfIn[i + stride - 1]) + Math.Abs(c - imgfIn[i - stride + 1]) + Math.Abs(c - imgfIn[i - stride - 1])) * k1; i += 1; } lineStart += stride; } return contrImgfs; }
static FloatMap convolute(FloatMap imgfIn, FloatMap filter, out bool thereAreStillHoles) { thereAreStillHoles = false; int filterSize = filter.W; int filterHalfSize = filterSize / 2; int h = imgfIn.H; int w = imgfIn.W; var imgfOut = new FloatMap(w, h); for (int y = 0; y < h ; ++y) { for (int x = 0; x < w; ++x) { // if point in [x,y] == -1 then cap that: // foreach a,b from x-filtersize to x+filtersize (same for y) // if that point is != -1 accumulate that * weight[a,b], accumulate weight[a,b] if (imgfIn[x, y] < 0) // --> need to cap { float accu = 0; float wAccu = 0; int cMinX = x - filterHalfSize; int cMinY = y - filterHalfSize; int minX = Math.Max(0, cMinX); int minY = Math.Max(0, cMinY); int xOffs = minX - cMinX; int yOffs = minY - cMinY; int maxX = Math.Min(w, x + filterHalfSize); int maxY = Math.Min(h, y + filterHalfSize); for (int b = minY, fb = yOffs; b < maxY; ++b, ++fb) { for (int a = minX, fa = xOffs; a < maxX; ++a, ++fa) { float v = imgfIn[a, b]; if (v >= 0) { float weight = filter[fa, fb]; wAccu += weight; accu += v * weight; } } } if (wAccu != 0) { imgfOut[x, y] = accu / wAccu; } else { imgfOut[x, y] = -1; thereAreStillHoles = true; } } else { imgfOut[x, y] = imgfIn[x,y]; } } } return imgfOut; }
// This is some sort of median filter, with the difference that // "outlier" values are just invalidated and left // for another step to be replaced with appropriate value // (this additional interpolation step still doesn't exist, though) public static FloatMap SpikesFilter(FloatMap imgfIn, float treshold) { int h = imgfIn.H; int w = imgfIn.W; int stride = imgfIn.Stride; var imgfOut = new FloatMap(w, h); const float k = 0.70710678118654752440084436210485f; // w = 1/sqrt(2); lazy me, i just compied result of w/wtot from calc... i know we don't have that much detail in singles // TODO: Should handle -1s correctly here, sooner or later XD // copy borders directly from src to dst int yLin = (h-1) * stride; for (int x = 0; x < w; ++x) { imgfOut[x] = imgfIn[x]; imgfOut[x + yLin] = imgfIn[x + yLin]; } yLin = 0; for (int y = 0; y < h; ++y) { imgfOut[yLin] = imgfIn[yLin]; imgfOut[yLin + stride - 1] = imgfIn[yLin + stride - 1]; yLin += stride; } // visit each pixel not belonging to borders; // for each one, consider its value and the average value // of its neighborhood (weighted proportionally to distance // from center pixel): if |value-average|>treshold // pixel is invalidated (=-1) float neighborhoodWeight; float neighborhoodAccu; float v; int lineStart = stride; for (int y = 1; y < h - 1; ++y) { int i = lineStart + 1; ; for (int x = 1; x < w - 1; ++x) { neighborhoodWeight = 0; neighborhoodAccu = 0; // considering neighborhood pixels separately to correctly handle -1s v = imgfIn[i + stride]; if (v > 0) { neighborhoodAccu += v; neighborhoodWeight += 1; } v = imgfIn[i - stride]; if (v > 0) { neighborhoodAccu += v; neighborhoodWeight += 1; } v = imgfIn[i + 1]; if (v > 0) { neighborhoodAccu += v; neighborhoodWeight += 1; } v = imgfIn[i -1]; if (v > 0) { neighborhoodAccu += v; neighborhoodWeight += 1; } v = imgfIn[i + stride + 1]; if (v > 0) { neighborhoodAccu += v * k; neighborhoodWeight += k; } v = imgfIn[i + stride -1]; if (v > 0) { neighborhoodAccu += v * k; neighborhoodWeight += k; } v = imgfIn[i - stride + 1]; if (v > 0) { neighborhoodAccu += v * k; neighborhoodWeight += k; } v = imgfIn[i - stride - 1]; if (v > 0) { neighborhoodAccu += v * k; neighborhoodWeight += k; } var d = Math.Abs(imgfIn[i] - (neighborhoodAccu / neighborhoodWeight)); imgfOut[i] = ((d > treshold) ? -1 : imgfIn[i]); // pixel value is just invalidated. A further step will take care of interpolation for missing value ++i; } lineStart += stride; } return imgfOut; }
// Converts from float map to bitmap 32bpp ARGB public static Bitmap Map2Bmp(FloatMap imgf, float k) { int h = imgf.H; int w = imgf.W; int stride = imgf.Stride; var bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb); BitmapData dstData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); int pixelSize = 4; unsafe { var dstStride = dstData.Stride; byte* dstRow = (byte*)dstData.Scan0; int srcLineStart = 0; for (int y = 0; y < h; ++y) { int srcIdx = srcLineStart; int wb = w * pixelSize; for (int x = 0; x < wb; x+=pixelSize) { byte b = (byte)(imgf[srcIdx] * k); dstRow[x] = b; dstRow[x + 1] = b; dstRow[x + 2] = b; dstRow[x + 3] = 255; ++srcIdx; } srcLineStart += stride; dstRow += dstStride; } } bmp.UnlockBits(dstData); return bmp; }
// Returns an image which sizes are each 1/2^times the original value; // will be probably replaced with reduction/expansion-style OpenCl operation public static FloatMap HalfMap(FloatMap imgfIn, int times) { for (int i = 0; i < times; ++i) { imgfIn = HalfMap(imgfIn); } return imgfIn; }
public FloatMap GaussianBlur(FloatMap imgfIn, float sigma) { FloatMap blurMask = createBlurMask(sigma); return convolve(imgfIn, blurMask); }
// Returns an image which sizes are each 2^times the original value; // will be probably replaced with reduction/expansion-style // OpenCl operation public FloatMap DoubleMap(FloatMap imgfIn, int times) { for (int i = 0; i < times; ++i) { imgfIn = DoubleMap(imgfIn); } return imgfIn; }
public FloatMap SpikesFilter(FloatMap inMap, float treshold) { var k = _kernels["quickSpikesFilterImg"]; FloatMap outMap = new FloatMap(inMap.W, inMap.H); err = Cl.SetKernelArg(k, 2, floatSize, treshold); assert(err, "treshold, setKernelArg"); singlePass(k, inMap, outMap); return outMap; }
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { if ((_fileNames == null) || (_fileNames.Length <= 3)) { return; } _imgfs.Clear(); int fileCount = _fileNames.Length; float progressStep = 100.0f / (fileCount * 2.0f); float progress = 0; backgroundWorker1.ReportProgress((int)progress,"converting"); // for each selected file for (int fileIdx = 0; fileIdx < fileCount; ++fileIdx) { string fileName = _fileNames[fileIdx]; // load bitmap using (var _bmp = new Bitmap(fileName)) { if (fileIdx == 0) { _h = _bmp.Height; _w = _bmp.Width; } else { if ((_h != _bmp.Height) || (_w != _bmp.Width)) { MessageBox.Show("Images must have same size!"); return; } } FloatMap imgf; // get luminance map imgf = MapUtils.HalfMap(MapUtils.Bmp2Map(_bmp), PreShrinkTimes); _imgfs.Add(imgf); } // update and report progress progress += progressStep; backgroundWorker1.ReportProgress((int)progress); // check for cancellation if (backgroundWorker1.CancellationPending) { return; } } List<FloatMap> newImgfs = new List<FloatMap>(); backgroundWorker1.ReportProgress((int)progress, "getting contrast"); // for each luminance map foreach (var imgf in _imgfs) { // get contrast, then shrink result (averaging pixels) FloatMap newImgf = MapUtils.HalfMap(MapUtils.GetMultiResContrastEvaluation(imgf, MultiResSteps), ShrinkContrastTimes); newImgfs.Add(newImgf); // update and report progress progress += progressStep; backgroundWorker1.ReportProgress((int)progress); // check for cancellation if (backgroundWorker1.CancellationPending) { return; } } _imgfs = newImgfs; smoothDepth(); smoothDepth(); _maxMap = getMaxMap(); // smooth for (int i = 0; i < BlurTimes; ++i) { _maxMap = MapUtils.GaussianBlur(_maxMap, BlurSigma); } // filter out spikes _maxMap = MapUtils.SpikesFilter(_maxMap, SpikeFilterTreshold); // cap holes _maxMap = MapUtils.CapHoles(_maxMap, CapHolesFilterEmisize); // TODO: correct the bell-distorsion savePLY(); saveObj(); }
private static FloatMap getDistanceWeightMap(int filterHalfSize) { int size = filterHalfSize * 2 + 1; int sup = size - 1; FloatMap wMap = new FloatMap(size, size); for (int y = 0; y < filterHalfSize; ++y) { for (int x = 0; x <= filterHalfSize; ++x) { float dx = (filterHalfSize - x); float dy = (filterHalfSize - y); wMap[x, y] = wMap[y, sup - x] = wMap[sup - y, x] = wMap[sup - x, sup - y] = (float)(1.0/Math.Sqrt(dx * dx + dy * dy)); } } wMap[filterHalfSize, filterHalfSize] = 0; return wMap; }
// Computes some sort of resolution independant contrast defined as follows // (don't know yet if it's ok or not) // compute contrast map on input map, then // downscales the image, gets the contrast map again, scales up contrast map to // original size and accumulates in original input map. Repeat several times. // Arguably, it could be computed more efficiently, but i don't care // optimizing code that will still have to be changed several times. public static FloatMap GetMultiResContrastEvaluation(FloatMap imgfIn, int subSamples) { int h = imgfIn.H; int w = imgfIn.W; float k = 1; FloatMap contr = new FloatMap(w, h); var img = imgfIn; for (int i = 0; i < subSamples; ++i) { var rc = ResizeMap(FastBlurMap(GetContrastMap(img)), w, h); //var rc = DoubleImg(BlurImg(GetContrImg(img)), i); // <-- multi step reduction would still be first choice with openCl Accumulate(contr, rc, k); k *= 0.5f; img = HalfMap(img); } return contr; }
// Code has been just replicated from SpikesFilter... // this stuff is just helping me experiment // and won't be mantained "nice" // SpikesFilter doesn't just call GetSpike // for performance reasons, too public static float GetSpikeHeight(FloatMap imgfIn, int x, int y) { const float k = 0.70710678118654752440084436210485f; // w = 1/sqrt(2); lazy me, i just compied result of w/wtot from calc... i know we don't have that much detail in singles int h = imgfIn.H; int w = imgfIn.W; int stride = imgfIn.Stride; int lineStart = y * stride; int i = y * stride + x; float neighborhoodWeight = 0; float neighborhoodAccu = 0; float v; // considering neighborhood pixels separately to correctly handle -1s v = imgfIn[i + stride]; if (v > 0) { neighborhoodAccu += v; neighborhoodWeight += 1; } v = imgfIn[i - stride]; if (v > 0) { neighborhoodAccu += v; neighborhoodWeight += 1; } v = imgfIn[i + 1]; if (v > 0) { neighborhoodAccu += v; neighborhoodWeight += 1; } v = imgfIn[i - 1]; if (v > 0) { neighborhoodAccu += v; neighborhoodWeight += 1; } v = imgfIn[i + stride + 1]; if (v > 0) { neighborhoodAccu += v * k; neighborhoodWeight += k; } v = imgfIn[i + stride - 1]; if (v > 0) { neighborhoodAccu += v * k; neighborhoodWeight += k; } v = imgfIn[i - stride + 1]; if (v > 0) { neighborhoodAccu += v * k; neighborhoodWeight += k; } v = imgfIn[i - stride - 1]; if (v > 0) { neighborhoodAccu += v * k; neighborhoodWeight += k; } var d = Math.Abs(imgfIn[i] - (neighborhoodAccu / neighborhoodWeight)); return d; }
// Caps holes taking values (weighted by distance) from neighborhood // for interpolation; filter can cap holes as large as filterHalfSize*2; // multiple passes could be needed. public static FloatMap CapHoles(FloatMap imgfIn, int filterHalfSize) { bool thereAreStillHoles = true; while (thereAreStillHoles) { imgfIn = MapUtils.capHoles(imgfIn, filterHalfSize, out thereAreStillHoles); } return imgfIn; }
// Returns an image which sizes are each half the original value; // will be probably replaced with reduction/expansion-style OpenCl operation public static FloatMap HalfMap(FloatMap imgfIn) { int h = imgfIn.H; int w = imgfIn.W; int stride = imgfIn.Stride; int hh = h >> 1; int hw = w >> 1; var imgfOut = new FloatMap(hw, hh); int hStride = imgfOut.Stride; int lineStart = 0; int hLineStart = 0; for (int y = 0; y < hh; ++y) { int i = lineStart; int hi = hLineStart; for (int x = 0; x < hw; ++x) { imgfOut[hi] = (imgfIn[i] + imgfIn[i + stride] + imgfIn[i + 1] + imgfIn[i + stride + 1]) * 0.25f; i += 2; ++hi; } lineStart += stride << 1; hLineStart += hStride; } return imgfOut; }
// returns an image which sizes are each double the original value; // will be probably replaced with reduction/expansion-style // OpenCl operation public static FloatMap DoubleMap(FloatMap imgfIn) { int h = imgfIn.H; int w = imgfIn.W; int dh = h * 2; int dw = w * 2; var imgfOut = new FloatMap(dw, dh); int dstStride = imgfOut.Stride; float dx = 0, dy = 0; int dLineStart = 0; for (int y = 0; y < dh - 2; ++y) { dx = 0; int i = dLineStart; for (int x = 0; x < dw - 2; ++x) { imgfOut[i] = imgfIn[dx, dy]; dx += 0.5f; ++i; } dy += 0.5f; dLineStart += dstStride; } return imgfOut; }
// Creates the blue-red depth map public static Bitmap Map2BmpDepthMap(FloatMap imgf, float k, int count) { int h = imgf.H; int w = imgf.W; int stride = imgf.Stride; var bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb); BitmapData dstData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); int pixelSize = 4; unsafe { var dstStride = dstData.Stride; byte* dstRow = (byte*)dstData.Scan0; int srcLineStart = 0; for (int y = 0; y < h; ++y) { int srcIdx = srcLineStart; int wb = w * pixelSize; for (int x = 0; x < wb; x+=4) { float v = imgf[srcIdx]; v = v < 0 ? -1 : 255 - v * 255 / count; if (v >= 0) { byte b = (byte)Math.Min(255, Math.Max((v * k), 0)); dstRow[x] = b; dstRow[x + 1] = 0; dstRow[x + 2] = (byte)(255 - b); dstRow[x + 3] = 255; } else { dstRow[x] = 0; dstRow[x + 1] = 0; dstRow[x + 2] = 0; dstRow[x + 3] = 255; } ++srcIdx; } srcLineStart += stride; dstRow += dstStride; } } bmp.UnlockBits(dstData); return bmp; }
// Blurs image; this has been written quickly and without reference; // should be modified in order to use a true gaussian kernel; // is left as is because shortly all convolution-like functions // will be handled by a single method (possibly with OpenCL) public static FloatMap FastBlurMap(FloatMap imgfIn) { int h = imgfIn.H; int w = imgfIn.W; int stride = imgfIn.Stride; var imgfOut = new FloatMap(w, h); const float k1 = 0.1715728f; // w = 2 const float k2 = 0.0857864f; // w = 1 const float k3 = 0.0606601f; // w = 1/1.4 = 0.7 int lineStart = stride; for (int y = 1; y < h - 1; ++y) { int i = lineStart + 1; ; for (int x = 1; x < w - 1; ++x) { imgfOut[i] = (imgfIn[i]) * k1 + (imgfIn[i + stride] + imgfIn[i - stride] + imgfIn[i+1] + imgfIn[i-1]) * k2 + (imgfIn[i + stride + 1] + imgfIn[i + stride - 1] + imgfIn[i - stride + 1] + imgfIn[i - stride - 1]) * k3; ++i; } lineStart += stride; } return imgfOut; }
static FloatMap capHoles(FloatMap imgfIn, int filterHalfSize, out bool thereAreStillHoles) { return convolute(imgfIn, getDistanceWeightMap(filterHalfSize), out thereAreStillHoles); }
public static FloatMap GaussianBlur(FloatMap imgfIn, float sigma) { FloatMap blurMask = createBlurMask(sigma); bool dummy; return convolute(imgfIn, blurMask, out dummy); }
// http://www.thebigblob.com/gaussian-blur-using-opencl-and-the-built-in-images-textures/ // http://haishibai.blogspot.it/2009/09/image-processing-c-tutorial-4-gaussian.html static FloatMap createBlurMask(float sigma) { int maskSize = (int)Math.Ceiling(3.0f * sigma); int _2maskSizePlus1 = (maskSize << 1) + 1; // stupid C# compiler gives precedence to sum FloatMap mask = new FloatMap(_2maskSizePlus1, _2maskSizePlus1); float sum = 0.0f; float temp = 0.0f; float _2sigmaSqrInvNeg = -1 / (sigma * sigma * 2); for (int a = -maskSize; a <= maskSize; ++a) { for (int b = -maskSize; b <= maskSize; ++b) { temp = (float)Math.Exp(((float)(a * a + b * b) * _2sigmaSqrInvNeg)); sum += temp; mask[a + maskSize + (b + maskSize) * _2maskSizePlus1] = temp; } } // Normalize the mask int _2maskSizePlus1Sqr = _2maskSizePlus1 * _2maskSizePlus1; for (int i = 0; i < _2maskSizePlus1Sqr; ++i) { mask[i] = mask[i] / sum; } return mask; }
public FloatMap ResizeMap(FloatMap inMap, int dstW, int dstH) { float xk = (float)inMap.W / (float)dstW; float yk = (float)inMap.H / (float)dstH; FloatMap outMap = new FloatMap(dstW, dstH); var k = _kernels["upsizeImg"]; err = Cl.SetKernelArg(k, 2, floatSize, xk); assert(err, "xk setKernelArg"); err = Cl.SetKernelArg(k, 3, floatSize, yk); assert(err, "yk setKernelArg"); singlePass(k, inMap, outMap); return outMap; }
// Resizes map to arbitrary size private static FloatMap ResizeMap(FloatMap imgfIn, int dstW, int dstH) { int srcH = imgfIn.H; int srcW = imgfIn.W; int stride = imgfIn.Stride; float xk = srcW / dstW; float yk = srcH / dstH; FloatMap imgOut = new FloatMap(dstW, dstH); float dy = 0; int lineStart = 0; for (int y = 0; y < dstH; ++y) { float dx = 0; int i = lineStart; for (int x = 0; x < dstW; ++x) { imgOut[i] = imgfIn[dx, dy]; dx += xk; ++i; } lineStart += stride; dy += yk; } return imgOut; }
// Caps holes taking values (weighted by distance) from neighborhood // for interpolation; filter can cap holes as large as filterHalfSize*2; // multiple passes could be needed. public FloatMap CapHoles(FloatMap imgfIn, int filterHalfSize) { var mask = getDistanceWeightMap(filterHalfSize); bool thereAreStillHoles = true; while (thereAreStillHoles) { imgfIn = convolvec(imgfIn, mask, out thereAreStillHoles); } return imgfIn; }
FloatMap getMaxMap() { int h = _imgfs[0].H; int w = _imgfs[0].W; FloatMap imgfOut = new FloatMap(w, h); for (int y =0; y<h; ++y) { for (int x = 0; x < w; ++x ) { float v = getMaxIdx(x, y); imgfOut[x, y] = v;// < 0 ? -1 : 255 - v * 255 / _imgfs.Count; // MOVED into map2BmpDepth } } return imgfOut; }
private FloatMap capHoles(FloatMap inMap, int filterHalfSize) { var k = _kernels["capHolesImg"]; FloatMap outMap = new FloatMap(inMap.W, inMap.H); FloatMap mask = getDistanceWeightMap(filterHalfSize); IMem<float> maskBuf = Cl.CreateBuffer<float>(_context, MemFlags.CopyHostPtr | MemFlags.ReadOnly, mask._buf, out err); assert(err, "capholes mask, mem object creation"); err = Cl.SetKernelArg(k, 2, intPtrSize, maskBuf); assert(err, "capholes mask, setKernelArg"); err = Cl.SetKernelArg(k, 3, intSize, filterHalfSize); assert(err, "capholes mask, setKernelArg"); singlePass(k, inMap, outMap); Cl.ReleaseMemObject(maskBuf); return outMap; }