/// <summary> /// Performs object detection on the given frame on GPU /// </summary> /// <param name="image">image where to perform the detection</param> /// <exception cref="ArgumentNullException">image</exception> public override int ProcessFrame(IImage2DByteA image) { if (image == null) throw new ArgumentNullException("image"); if (image.Width > _integralImage.Width || image.Height > _integralImage.Height) throw new ArgumentException("Specified image (" + image.Width + " x " + image.Height + ") is too big, maximum size is (" + _integralImage.Width + " x " + _integralImage.Height + ")"); // create integral image _clooProgram.Integral(Queue, (ClooImage2DByteA)image, (ClooImage2DUIntA)_integralImage); _clooProgram.IntegralSquare(Queue, (ClooImage2DByteA)image, (ClooImage2DUIntA)_integral2Image); return ProcessFrame(); }
/// <summary> /// Convert an float image to an integral image /// </summary> /// <remarks> /// We skip the last line to keep the original size (better performance) /// </remarks> /// <param name="source">image source</param> /// <param name="dest">image destination</param> public void Integral(IImage2DByteA source, IImage2DUIntA dest) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); if ((source.Width > dest.Width) || (source.Height > dest.Height)) throw new ArgumentException("Destination image (" + dest.Width + "x" + dest.Height + ") must have at least the source image width and height but is only " + source.Width + "x" + source.Height); int heightS = source.Height; int widthS = source.Width; int heightD = dest.Height; int widthD = dest.Width; byte[] sBuf = source.HostBuffer; uint[] dBuf = dest.HostBuffer; for (int x = 0; x < widthD; x++) dest.HostBuffer[x] = 0; // zero first line for (int y = 0, a = widthD * heightD; y < a; y += widthD) dest.HostBuffer[y] = 0; // zero first column int y1IndexS = 0; int yIndexD = widthD; int y1IndexD = 0; // last // for each line for (int y = 1; y < heightS; y++) { // for each pixel for (int x = 1; x < widthS; x++) { uint p = sBuf[y1IndexS + x - 1]; dBuf[yIndexD + x] = p + dBuf[yIndexD + x - 1] + dBuf[y1IndexD + x] - dBuf[y1IndexD + x - 1]; } yIndexD += widthD; y1IndexS += widthS; y1IndexD += widthD; } }
/// <summary> /// Convert an float image to a squared integral image /// </summary> /// <remarks> /// We skip the last line to keep the original size (better performance) /// </remarks> /// <param name="source">image source</param> /// <param name="dest">image destination</param> public void IntegralSquare(IImage2DByteA source, IImage2DUIntA dest) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); if ((source.Width > dest.Width) || (source.Height > dest.Height)) throw new ArgumentException("Destination image (" + dest.Width + "x" + dest.Height + ") must have at least the source image width and height but is only " + source.Width + "x" + source.Height); int height = source.Height; int width = source.Width; byte[] sBuf = source.HostBuffer; uint[] dBuf = dest.HostBuffer; for (int x = 0; x < width; x++) dest.HostBuffer[x] = 0; // zero first line for (int y = 0, a = width * height; y < a; y += width) dest.HostBuffer[y] = 0; // zero first column // for each line int ySumIndex = 0; int y1SumIndex; int yIndex = 0; for (int y = 1; y < height; y++) { y1SumIndex = ySumIndex; ySumIndex += width; // for each pixel for (int x = 1; x < width; x++) { uint p = sBuf[yIndex + x - 1]; dBuf[ySumIndex + x] = p * p + dBuf[ySumIndex + x - 1] + dBuf[y1SumIndex + x] - dBuf[y1SumIndex + x - 1]; } yIndex += width; } }
/// <summary> /// Create histogram /// </summary> /// <param name="source">image source</param> /// <param name="histogram">byte buffer (256 bytes)</param> public void Histogram256(IImage2DByteA source, IBuffer<uint> histogram, int startX, int startY = 0, int width = 0, int height = 0) { Histogram256(source, histogram.HostBuffer, startX, startY, width, height); }
/// <summary> /// Create histogram /// </summary> /// <param name="source">image source</param> /// <param name="histogram">byte buffer (256 bytes)</param> public void Histogram256(IImage2DByteA source, uint[] histogram, int startX, int startY = 0, int width = 0, int height = 0) { if (source == null) throw new ArgumentNullException("source"); if (histogram == null) throw new ArgumentNullException("histogram"); if (histogram.Length < 256) throw new ArgumentException("Buffer size for histogram must be at least 256 bytes", "histogram"); if (width == 0) width = source.Width - startX; if (height == 0) height = source.Height - startY; for (int i = 0; i < 256; i++) histogram[i] = 0; for (int y = startY, yh = startY + height; y < yh; y++) { int pos = y * source.Width + startX; for (int x = startX, xw = startX + width; x < xw; x++) histogram[source.HostBuffer[pos++]]++; } }
/// <summary> /// Create histogram /// </summary> /// <param name="source">image source</param> /// <param name="histogram">byte buffer (256 bytes)</param> public void Histogram256(IImage2DByteA source, IBuffer<uint> histogram) { Histogram256(source, histogram.HostBuffer); }
/// <summary> /// Create histogram /// </summary> /// <param name="source">image source</param> /// <param name="histogram">byte buffer (256 bytes)</param> public void Histogram256(IImage2DByteA source, uint[] histogram) { if (source == null) throw new ArgumentNullException("source"); if (histogram == null) throw new ArgumentNullException("histogram"); if (histogram.Length < 256) throw new ArgumentException("Buffer size for histogram must be at least 256 bytes", "histogram"); for (int i = 0; i < 256; i++) histogram[i] = 0; for (int i = 0, length = source.HostBuffer.Length; i < length; i++) histogram[source.HostBuffer[i]]++; }
/// <summary> /// GrayScale image /// </summary> /// <param name="source">image source</param> /// <param name="dest">image destination</param> public void GrayScale(IImage2DByteRgbA source, IImage2DByteA dest) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); if ((source.Width > dest.Width) || (source.Height > dest.Height)) throw new ArgumentException("Destination image (" + dest.Width + "x" + dest.Height + ") must have at least the same size as the source image (" + source.Width + "x" + source.Height + ")"); int length = source.Width * source.Height; int pos = 0; for (int i = 0; i < length; i++) { float gray = 0.2989f * (float)source.HostBuffer[pos++] + 0.5870f * (float)source.HostBuffer[pos++] + 0.1140f * (float)source.HostBuffer[pos++]; pos++; dest.HostBuffer[i] = (byte)gray; } }
/// <summary> /// Flip image Y coordinate /// </summary> /// <param name="source">image source</param> /// <param name="dest">image destination</param> public void FlipY(IImage2DByteA source, IImage2DByteA dest) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); if (source == dest) throw new ArgumentException("Flipping kernel is not designed to run inline therefore source and destination must be different images"); if ((source.Width > dest.Width) || (source.Height > dest.Height)) throw new ArgumentException("Destination image (" + dest.Width + "x" + dest.Height + ") must have at least the same size as the source image (" + source.Width + "x" + source.Height + ")"); var sBuf = source.HostBuffer; var dBuf = dest.HostBuffer; int posSource = 0; int posDest = (source.Height - 1) * dest.Width; for (int y = 0, h = source.Height; y < h; y++) { for (int x = 0, w = source.Width; x < w; x++) { byte color = sBuf[posSource++]; dBuf[posDest++] = color; } posDest -= dest.Width + source.Width; } }
/// <summary> /// Extracts a channel of an RGB image /// </summary> /// <param name="source">image source</param> /// <param name="dest">image destination</param> /// <param name="offset">offset (0..3)</param> public void ExtractChannel(IImage2DByteRgbA source, IImage2DByteA dest, byte offset) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); if (offset > 3) throw new ArgumentOutOfRangeException("offset", String.Format("offset must be between 0..3 but was {0}", offset)); if ((source.Width > dest.Width) || (source.Height > dest.Height)) throw new ArgumentException("Destination image (" + dest.Width + "x" + dest.Height + ") must have at least the same size as the source image (" + source.Width + "x" + source.Height + ")"); int length = source.Width * source.Height; int pos = 0; for (int i = 0; i < length; i++) for (int j = 0; j < 4; j++) if (j == offset) dest.HostBuffer[i] = source.HostBuffer[pos++]; else pos++; }
/// <summary> /// Convert gray byte image to RGB byte image /// </summary> /// <param name="source">image source</param> /// <param name="dest">image destination</param> public void ByteAToByteRgbA(IImage2DByteA source, IImage2DByteRgbA dest) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); if ((source.Width > dest.Width) || (source.Height > dest.Height)) throw new ArgumentException("Destination image (" + dest.Width + "x" + dest.Height + ") must have at least the same size as the source image (" + source.Width + "x" + source.Height + ")"); int length = source.HostBuffer.Length; int pos = 0; for (int i = 0; i < length; i++) { byte val = source.HostBuffer[i]; dest.HostBuffer[pos++] = val; dest.HostBuffer[pos++] = val; dest.HostBuffer[pos++] = val; dest.HostBuffer[pos++] = 255; } }
/// <summary> /// Performs object detection on the given frame /// </summary> /// <param name="image">image where to perform the detection</param> /// <exception cref="ArgumentNullException">image</exception> public abstract int ProcessFrame(IImage2DByteA image);