/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image, Rectangle rect ) { int pixelSize = ( image.PixelFormat == PixelFormat.Format24bppRgb ) ? 3 : 4; int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; int offset = image.Stride - rect.Width * pixelSize; // do the job byte* ptr = (byte*) image.ImageData.ToPointer( ); byte t; // allign pointer to the first pixel to process ptr += ( startY * image.Stride + startX * pixelSize ); // for each line for ( int y = startY; y < stopY; y++ ) { // for each pixel for ( int x = startX; x < stopX; x++, ptr += pixelSize ) { // rotate colors of each pixel t = ptr[RGB.R]; ptr[RGB.R] = ptr[RGB.G]; ptr[RGB.G] = ptr[RGB.B]; ptr[RGB.B] = t; } ptr += offset; } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// protected unsafe override void ProcessFilter(UnmanagedImage image) { int width = image.Width; int height = image.Height; int pixelSize = System.Drawing.Image.GetPixelFormatSize(image.PixelFormat) / 8; int stride = image.Stride; int offset = stride - image.Width * pixelSize; byte* src = (byte*)image.ImageData.ToPointer(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++, src += pixelSize) { double sum = src[RGB.R] + src[RGB.G] + src[RGB.B]; sum = sum == 0 ? 1 : sum; double red = src[RGB.R] / sum; double green = src[RGB.G] / sum; double blue = 1 - red - green; src[RGB.R] = (byte)(red * 255); src[RGB.G] = (byte)(green * 255); src[RGB.B] = (byte)(blue * 255); } src += offset; } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage sourceData, UnmanagedImage destinationData ) { // get width and height int width = sourceData.Width; int height = sourceData.Height; int srcOffset = sourceData.Stride - width; int dstOffset = destinationData.Stride - width * 3; // do the job byte * src = (byte*) sourceData.ImageData.ToPointer( ); byte * dst = (byte*) destinationData.ImageData.ToPointer( ); // for each line for ( int y = 0; y < height; y++ ) { // for each pixel for ( int x = 0; x < width; x++, src++, dst += 3 ) { dst[RGB.R] = dst[RGB.G] = dst[RGB.B] = *src; } src += srcOffset; dst += dstOffset; } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage sourceData, UnmanagedImage destinationData ) { // get source image size int width = sourceData.Width; int height = sourceData.Height; int pixelSize = Image.GetPixelFormatSize( sourceData.PixelFormat ) / 8; int srcStride = sourceData.Stride; int dstStride = destinationData.Stride; double xFactor = (double) width / newWidth; double yFactor = (double) height / newHeight; // do the job byte* baseSrc = (byte*) sourceData.ImageData.ToPointer( ); byte* baseDst = (byte*) destinationData.ImageData.ToPointer( ); // for each line for ( int y = 0; y < newHeight; y++ ) { byte* dst = baseDst + dstStride * y; byte* src = baseSrc + srcStride * ( (int) ( y * yFactor ) ); byte* p; // for each pixel for ( int x = 0; x < newWidth; x++ ) { p = src + pixelSize * ( (int) ( x * xFactor ) ); for ( int i = 0; i < pixelSize; i++, dst++, p++ ) { *dst = *p; } } } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image, Rectangle rect ) { int pixelSize = ( ( image.PixelFormat == PixelFormat.Format8bppIndexed ) || ( image.PixelFormat == PixelFormat.Format16bppGrayScale ) ) ? 1 : 3; int startY = rect.Top; int stopY = startY + rect.Height; int startX = rect.Left * pixelSize; int stopX = startX + rect.Width * pixelSize; byte* basePtr = (byte*) image.ImageData.ToPointer( ); if ( ( image.PixelFormat == PixelFormat.Format8bppIndexed ) || ( image.PixelFormat == PixelFormat.Format24bppRgb ) ) { int offset = image.Stride - ( stopX - startX ); // allign pointer to the first pixel to process byte* ptr = basePtr + ( startY * image.Stride + rect.Left * pixelSize ); // invert for ( int y = startY; y < stopY; y++ ) { for ( int x = startX; x < stopX; x++, ptr++ ) { // ivert each pixel *ptr = (byte) ( 255 - *ptr ); } ptr += offset; } } else { int stride = image.Stride; // allign pointer to the first pixel to process basePtr += ( startY * image.Stride + rect.Left * pixelSize * 2 ); // invert for ( int y = startY; y < stopY; y++ ) { ushort* ptr = (ushort*) ( basePtr ); for ( int x = startX; x < stopX; x++, ptr++ ) { // ivert each pixel *ptr = (ushort) ( 65535 - *ptr ); } basePtr += stride; } } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// protected override void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData) { // Lock the overlay image (left image) BitmapData overlayData = overlayImage.LockBits( new Rectangle(0, 0, overlayImage.Width, overlayImage.Height), ImageLockMode.ReadOnly, overlayImage.PixelFormat); int dstHeight = destinationData.Height; int src1Height = overlayData.Height; int src2Height = sourceData.Height; int src1Stride = overlayData.Stride; int src2Stride = sourceData.Stride; int dstStride = destinationData.Stride; int pixelSize = System.Drawing.Image.GetPixelFormatSize(sourceData.PixelFormat) / 8; int copySize1 = overlayData.Width * pixelSize; int copySize2 = sourceData.Width * pixelSize; // do the job unsafe { byte* src1 = (byte*)overlayData.Scan0.ToPointer(); byte* src2 = (byte*)sourceData.ImageData.ToPointer(); byte* dst = (byte*)destinationData.ImageData.ToPointer(); // for each line for (int y = 0; y < dstHeight; y++) { if (y < src1Height) Accord.SystemTools.CopyUnmanagedMemory(dst, src1, copySize1); if (y < src2Height) Accord.SystemTools.CopyUnmanagedMemory(dst + copySize1, src2, copySize2); src1 += src1Stride; src2 += src2Stride; dst += dstStride; } } // Release overlayImage.UnlockBits(overlayData); }
/// <summary> /// Initializes a new instance of the <see cref="Morph"/> class. /// </summary> /// /// <param name="unmanagedOverlayImage">Unmanaged overlay image.</param> /// public Morph( UnmanagedImage unmanagedOverlayImage ) : base( unmanagedOverlayImage ) { InitFormatTranslations( ); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image ) { int width = image.Width; int height = image.Height; // 1 - invert the source image Invert invertFilter = new Invert( ); UnmanagedImage invertedImage = invertFilter.Apply( image ); // 2 - use blob counter to find holes (they are white objects now on the inverted image) BlobCounter blobCounter = new BlobCounter( ); blobCounter.ProcessImage( invertedImage ); Blob[] blobs = blobCounter.GetObjectsInformation( ); // 3 - check all blobs and determine which should be filtered byte[] newObjectColors = new byte[blobs.Length + 1]; newObjectColors[0] = 255; // don't touch the objects, which have 0 ID for ( int i = 0, n = blobs.Length; i < n; i++ ) { Blob blob = blobs[i]; if ( ( blob.Rectangle.Left == 0 ) || ( blob.Rectangle.Top == 0 ) || ( blob.Rectangle.Right == width ) || ( blob.Rectangle.Bottom == height ) ) { newObjectColors[blob.ID] = 0; } else { if ( ( ( coupledSizeFiltering ) && ( blob.Rectangle.Width <= maxHoleWidth ) && ( blob.Rectangle.Height <= maxHoleHeight ) ) | ( ( !coupledSizeFiltering ) && ( ( blob.Rectangle.Width <= maxHoleWidth ) || ( blob.Rectangle.Height <= maxHoleHeight ) ) ) ) { newObjectColors[blob.ID] = 255; } else { newObjectColors[blob.ID] = 0; } } } // 4 - process the source image image and fill holes byte* ptr = (byte*) image.ImageData.ToPointer( ); int offset = image.Stride - width; int[] objectLabels = blobCounter.ObjectLabels; for ( int y = 0, i = 0; y < height; y++ ) { for ( int x = 0; x < width; x++, i++, ptr++ ) { *ptr = newObjectColors[objectLabels[i]]; } ptr += offset; } }
protected override unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData) { // get width and height int width = sourceData.Width; int height = sourceData.Height; if (SaveColorChannels && SaveLumChannel) { LRGBArrays = new LRGBArrays(new ushort[width * height], new ushort[width * height], new ushort[width * height], new ushort[width * height]); } else if (!SaveColorChannels && SaveLumChannel) { LRGBArrays = new LRGBArrays(new ushort[width * height], new ushort[0], new ushort[0], new ushort[0]); } else if (SaveColorChannels && !SaveLumChannel) { LRGBArrays = new LRGBArrays(new ushort[0], new ushort[width * height], new ushort[width * height], new ushort[width * height]); } int widthM1 = width - 1; int heightM1 = height - 1; int srcStride = sourceData.Stride / 2; int srcOffset = (srcStride - width) / 2; int dstOffset = (destinationData.Stride - width * 6) / 6; // do the job ushort *src = (ushort *)sourceData.ImageData.ToPointer(); ushort *dst = (ushort *)destinationData.ImageData.ToPointer(); int[] rgbValues = new int[3]; int[] rgbCounters = new int[3]; if (!PerformDemosaicing) { // for each line for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, src++, dst += 3) { dst[RGB.R] = dst[RGB.G] = dst[RGB.B] = 0; dst[BayerPattern[y & 1, x & 1]] = *src; } src += srcOffset; dst += dstOffset; } } else { int counter = 0; // for each line for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, src++, dst += 3) { rgbValues[0] = rgbValues[1] = rgbValues[2] = 0; rgbCounters[0] = rgbCounters[1] = rgbCounters[2] = 0; int bayerIndex = BayerPattern[y & 1, x & 1]; rgbValues[bayerIndex] += *src; rgbCounters[bayerIndex]++; if (x != 0) { bayerIndex = BayerPattern[y & 1, (x - 1) & 1]; rgbValues[bayerIndex] += src[-1]; rgbCounters[bayerIndex]++; } if (x != widthM1) { bayerIndex = BayerPattern[y & 1, (x + 1) & 1]; rgbValues[bayerIndex] += src[1]; rgbCounters[bayerIndex]++; } if (y != 0) { bayerIndex = BayerPattern[(y - 1) & 1, x & 1]; rgbValues[bayerIndex] += src[-srcStride]; rgbCounters[bayerIndex]++; if (x != 0) { bayerIndex = BayerPattern[(y - 1) & 1, (x - 1) & 1]; rgbValues[bayerIndex] += src[-srcStride - 1]; rgbCounters[bayerIndex]++; } if (x != widthM1) { bayerIndex = BayerPattern[(y - 1) & 1, (x + 1) & 1]; rgbValues[bayerIndex] += src[-srcStride + 1]; rgbCounters[bayerIndex]++; } } if (y != heightM1) { bayerIndex = BayerPattern[(y + 1) & 1, x & 1]; rgbValues[bayerIndex] += src[srcStride]; rgbCounters[bayerIndex]++; if (x != 0) { bayerIndex = BayerPattern[(y + 1) & 1, (x - 1) & 1]; rgbValues[bayerIndex] += src[srcStride - 1]; rgbCounters[bayerIndex]++; } if (x != widthM1) { bayerIndex = BayerPattern[(y + 1) & 1, (x + 1) & 1]; rgbValues[bayerIndex] += src[srcStride + 1]; rgbCounters[bayerIndex]++; } } dst[RGB.R] = (ushort)(rgbValues[RGB.R] / rgbCounters[RGB.R]); dst[RGB.G] = (ushort)(rgbValues[RGB.G] / rgbCounters[RGB.G]); dst[RGB.B] = (ushort)(rgbValues[RGB.B] / rgbCounters[RGB.B]); if (SaveColorChannels) { LRGBArrays.Red[counter] = dst[RGB.R]; LRGBArrays.Green[counter] = dst[RGB.G]; LRGBArrays.Blue[counter] = dst[RGB.B]; } if (SaveLumChannel) { LRGBArrays.Lum[counter] = (ushort)Math.Floor((dst[RGB.R] + dst[RGB.G] + dst[RGB.B]) / 3d); } counter++; } src += srcOffset; dst += dstOffset; } } }
/// <summary> /// Apply filter to an image (not implemented). /// </summary> /// /// <param name="image">Image in unmanaged memory.</param> /// /// <returns>Returns filter's result obtained by applying the filter to /// the source image.</returns> /// /// <exception cref="NotImplementedException">The method is not implemented.</exception> /// public UnmanagedImage Apply( UnmanagedImage image ) { throw new NotImplementedException( "The method is not implemented for the filter." ); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image, Rectangle rect ) { // calculate threshold for the given image thresholdFilter.ThresholdValue = CalculateThreshold( image, rect ); // thresholding thresholdFilter.ApplyInPlace( image, rect ); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="source">Source image data.</param> /// <param name="destination">Destination image data.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage source, UnmanagedImage destination ) { int pixelSize = Image.GetPixelFormatSize( source.PixelFormat ) / 8; // image width and height int width = source.Width; int height = source.Height; int widthToProcess = System.Math.Min( width, warpMap.GetLength( 1 ) ); int heightToProcess = System.Math.Min( height, warpMap.GetLength( 0 ) ); int srcStride = source.Stride; int dstStride = destination.Stride; int dstOffset = dstStride - widthToProcess * pixelSize; // new pixel's position int ox, oy; byte* src = (byte*) source.ImageData.ToPointer( ); byte* dst = (byte*) destination.ImageData.ToPointer( ); byte* p; // for each line for ( int y = 0; y < heightToProcess; y++ ) { // for each pixel for ( int x = 0; x < widthToProcess; x++ ) { // get original pixel's coordinates ox = x + warpMap[y, x].X; oy = y + warpMap[y, x].Y; // check if the random pixel is inside of image if ( ( ox >= 0 ) && ( oy >= 0 ) && ( ox < width ) && ( oy < height ) ) { p = src + oy * srcStride + ox * pixelSize; for ( int i = 0; i < pixelSize; i++, dst++, p++ ) { *dst = *p; } } else { for ( int i = 0; i < pixelSize; i++, dst++ ) { *dst = 0; } } } // copy remaining pixel in the row if ( width != widthToProcess ) { AForge.SystemTools.CopyUnmanagedMemory( dst, src + y * srcStride + widthToProcess * pixelSize, ( width - widthToProcess ) * pixelSize ); } dst += dstOffset; } // copy remaining rows of pixels for ( int y = heightToProcess; y < height; y++, dst += dstStride ) { AForge.SystemTools.CopyUnmanagedMemory( dst, src + y * srcStride, width * pixelSize ); } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image, Rectangle rect ) { int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; int offset = image.Stride - rect.Width; // value which is caried from pixel to pixel short carry = 0; // do the job byte* ptr = (byte*) image.ImageData.ToPointer( ); // allign pointer to the first pixel to process ptr += ( startY * image.Stride + startX ); // for each line for ( int y = startY; y < stopY; y++ ) { carry = 0; // for each pixel for ( int x = startX; x < stopX; x++, ptr++ ) { carry += *ptr; if ( carry >= threshold ) { *ptr = (byte) 255; carry -= 255; } else { *ptr = (byte) 0; } } ptr += offset; } }
// Process the filter on the image with 16 bits per color channel private unsafe void ProcessFilter16bpc(UnmanagedImage image) { int pixelSize = Image.GetPixelFormatSize(image.PixelFormat) / 8; bool is64bpp = (pixelSize == 8); // pad fill colours to 16-bits ushort fillRed = (ushort)(this.fillRed << 8); ushort fillGreen = (ushort)(this.fillGreen << 8); ushort fillBlue = (ushort)(this.fillBlue << 8); ushort fillAlpha = (ushort)(this.fillAlpha << 8); // get image width and height int width = image.Width; int height = image.Height; int stride = image.Stride; int movePointX = movePoint.X; int movePointY = movePoint.Y; // intersection rectangle Rectangle intersect = Rectangle.Intersect( new Rectangle(0, 0, width, height), new Rectangle(movePointX, movePointY, width, height)); // start, stop and step for X and Y int yStart = 0; int yStop = height; int yStep = 1; int xStart = 0; int xStop = width; int xStep = 1; if (movePointY > 0) { yStart = height - 1; yStop = -1; yStep = -1; } if (movePointX > 0) { xStart = width - 1; xStop = -1; xStep = -1; } // do the job byte * src = (byte *)image.ImageData.ToPointer( ); ushort *pixel, moved; if (image.PixelFormat == PixelFormat.Format16bppGrayScale) { // grayscale image for (int y = yStart; y != yStop; y += yStep) { for (int x = xStart; x != xStop; x += xStep) { // current pixel pixel = (ushort *)(src + y * stride + x * 2); if (intersect.Contains(x, y)) { moved = (ushort *)(src + (y - movePointY) * stride + (x - movePointX) * 2); *pixel = *moved; } else { *pixel = fillGray; } } } } else { // color image for (int y = yStart; y != yStop; y += yStep) { for (int x = xStart; x != xStop; x += xStep) { // current pixel pixel = (ushort *)(src + y * stride + x * pixelSize); if (intersect.Contains(x, y)) { moved = (ushort *)(src + (y - movePointY) * stride + (x - movePointX) * pixelSize); pixel[RGB.R] = moved[RGB.R]; pixel[RGB.G] = moved[RGB.G]; pixel[RGB.B] = moved[RGB.B]; if (is64bpp) { pixel[RGB.A] = moved[RGB.A]; } } else { pixel[RGB.R] = fillRed; pixel[RGB.G] = fillGreen; pixel[RGB.B] = fillBlue; if (is64bpp) { pixel[RGB.A] = fillAlpha; } } } } } }
/// <summary> /// Apply filter to an image (not implemented). /// </summary> /// /// <param name="image">Image in unmanaged memory.</param> /// /// <returns>Returns filter's result obtained by applying the filter to /// the source image.</returns> /// /// <exception cref="NotImplementedException">The method is not implemented.</exception> /// public UnmanagedImage Apply(UnmanagedImage image) { throw new NotImplementedException("The method is not implemented for the filter."); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData) { // get source image size int width = sourceData.Width; int height = sourceData.Height; double oldXradius = (double)(width - 1) / 2; double oldYradius = (double)(height - 1) / 2; // get destination image size int newWidth = destinationData.Width; int newHeight = destinationData.Height; double newXradius = (double)(newWidth - 1) / 2; double newYradius = (double)(newHeight - 1) / 2; // angle's sine and cosine double angleRad = -angle * Math.PI / 180; double angleCos = Math.Cos(angleRad); double angleSin = Math.Sin(angleRad); int srcStride = sourceData.Stride; int dstOffset = destinationData.Stride - ((destinationData.PixelFormat == PixelFormat.Format8bppIndexed) ? newWidth : newWidth * 3); // fill values byte fillR = fillColor.R; byte fillG = fillColor.G; byte fillB = fillColor.B; // do the job byte *src = (byte *)sourceData.ImageData.ToPointer( ); byte *dst = (byte *)destinationData.ImageData.ToPointer( ); // destination pixel's coordinate relative to image center double cx, cy; // coordinates of source points double ox, oy, tx, ty, dx1, dy1, dx2, dy2; int ox1, oy1, ox2, oy2; // width and height decreased by 1 int ymax = height - 1; int xmax = width - 1; // temporary pointers byte *p1, p2, p3, p4; // check pixel format if (destinationData.PixelFormat == PixelFormat.Format8bppIndexed) { // grayscale cy = -newYradius; for (int y = 0; y < newHeight; y++) { // do some pre-calculations of source points' coordinates // (calculate the part which depends on y-loop, but does not // depend on x-loop) tx = angleSin * cy + oldXradius; ty = angleCos * cy + oldYradius; cx = -newXradius; for (int x = 0; x < newWidth; x++, dst++) { // coordinates of source point ox = tx + angleCos * cx; oy = ty - angleSin * cx; // top-left coordinate ox1 = (int)ox; oy1 = (int)oy; // validate source pixel's coordinates if ((ox1 < 0) || (oy1 < 0) || (ox1 >= width) || (oy1 >= height)) { // fill destination image with filler *dst = fillG; } else { // bottom-right coordinate ox2 = (ox1 == xmax) ? ox1 : ox1 + 1; oy2 = (oy1 == ymax) ? oy1 : oy1 + 1; if ((dx1 = ox - (double)ox1) < 0) { dx1 = 0; } dx2 = 1.0 - dx1; if ((dy1 = oy - (double)oy1) < 0) { dy1 = 0; } dy2 = 1.0 - dy1; p1 = src + oy1 * srcStride; p2 = src + oy2 * srcStride; // interpolate using 4 points *dst = (byte)( dy2 * (dx2 * p1[ox1] + dx1 * p1[ox2]) + dy1 * (dx2 * p2[ox1] + dx1 * p2[ox2])); } cx++; } cy++; dst += dstOffset; } } else { // RGB cy = -newYradius; for (int y = 0; y < newHeight; y++) { // do some pre-calculations of source points' coordinates // (calculate the part which depends on y-loop, but does not // depend on x-loop) tx = angleSin * cy + oldXradius; ty = angleCos * cy + oldYradius; cx = -newXradius; for (int x = 0; x < newWidth; x++, dst += 3) { // coordinates of source point ox = tx + angleCos * cx; oy = ty - angleSin * cx; // top-left coordinate ox1 = (int)ox; oy1 = (int)oy; // validate source pixel's coordinates if ((ox1 < 0) || (oy1 < 0) || (ox1 >= width) || (oy1 >= height)) { // fill destination image with filler dst[RGB.R] = fillR; dst[RGB.G] = fillG; dst[RGB.B] = fillB; } else { // bottom-right coordinate ox2 = (ox1 == xmax) ? ox1 : ox1 + 1; oy2 = (oy1 == ymax) ? oy1 : oy1 + 1; if ((dx1 = ox - (float)ox1) < 0) { dx1 = 0; } dx2 = 1.0f - dx1; if ((dy1 = oy - (float)oy1) < 0) { dy1 = 0; } dy2 = 1.0f - dy1; // get four points p1 = p2 = src + oy1 * srcStride; p1 += ox1 * 3; p2 += ox2 * 3; p3 = p4 = src + oy2 * srcStride; p3 += ox1 * 3; p4 += ox2 * 3; // interpolate using 4 points // red dst[RGB.R] = (byte)( dy2 * (dx2 * p1[RGB.R] + dx1 * p2[RGB.R]) + dy1 * (dx2 * p3[RGB.R] + dx1 * p4[RGB.R])); // green dst[RGB.G] = (byte)( dy2 * (dx2 * p1[RGB.G] + dx1 * p2[RGB.G]) + dy1 * (dx2 * p3[RGB.G] + dx1 * p4[RGB.G])); // blue dst[RGB.B] = (byte)( dy2 * (dx2 * p1[RGB.B] + dx1 * p2[RGB.B]) + dy1 * (dx2 * p3[RGB.B] + dx1 * p4[RGB.B])); } cx++; } cy++; dst += dstOffset; } } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage image, Rectangle rect) { // get pixel size int pixelSize = (image.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; int offset = image.Stride - rect.Width * pixelSize; RGB rgb = new RGB( ); HSL hsl = new HSL( ); bool updated; // do the job byte *ptr = (byte *)image.ImageData.ToPointer( ); // allign pointer to the first pixel to process ptr += (startY * image.Stride + startX * pixelSize); // for each row for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, ptr += pixelSize) { updated = false; rgb.Red = ptr[RGB.R]; rgb.Green = ptr[RGB.G]; rgb.Blue = ptr[RGB.B]; // convert to HSL AForge.Imaging.HSL.FromRGB(rgb, hsl); // check HSL values if ( (hsl.Saturation >= saturation.Min) && (hsl.Saturation <= saturation.Max) && (hsl.Luminance >= luminance.Min) && (hsl.Luminance <= luminance.Max) && ( ((hue.Min < hue.Max) && (hsl.Hue >= hue.Min) && (hsl.Hue <= hue.Max)) || ((hue.Min > hue.Max) && ((hsl.Hue >= hue.Min) || (hsl.Hue <= hue.Max))) ) ) { if (!fillOutsideRange) { if (updateH) { hsl.Hue = fillH; } if (updateS) { hsl.Saturation = fillS; } if (updateL) { hsl.Luminance = fillL; } updated = true; } } else { if (fillOutsideRange) { if (updateH) { hsl.Hue = fillH; } if (updateS) { hsl.Saturation = fillS; } if (updateL) { hsl.Luminance = fillL; } updated = true; } } if (updated) { // convert back to RGB AForge.Imaging.HSL.ToRGB(hsl, rgb); ptr[RGB.R] = rgb.Red; ptr[RGB.G] = rgb.Green; ptr[RGB.B] = rgb.Blue; } } ptr += offset; } }
protected unsafe override void ProcessFilter(UnmanagedImage image, UnmanagedImage overlay) { PixelFormat pixelFormat = image.PixelFormat; int width = image.Width; int height = image.Height; int num; switch (pixelFormat) { case PixelFormat.Format24bppRgb: case PixelFormat.Format32bppRgb: case PixelFormat.Format8bppIndexed: case PixelFormat.Format32bppArgb: { int num2; switch (pixelFormat) { default: num2 = 4; break; case PixelFormat.Format24bppRgb: num2 = 3; break; case PixelFormat.Format8bppIndexed: num2 = 1; break; } int num3 = num2; int num4 = width * num3; int num5 = image.Stride - num4; int num6 = overlay.Stride - num4; byte *ptr = (byte *)image.ImageData.ToPointer(); byte *ptr2 = (byte *)overlay.ImageData.ToPointer(); for (int i = 0; i < height; i++) { int num7 = 0; while (num7 < num4) { if (*ptr2 < *ptr) { *ptr = *ptr2; } num7++; ptr++; ptr2++; } ptr += num5; ptr2 += num6; } return; } default: num = 4; break; case PixelFormat.Format48bppRgb: num = 3; break; case PixelFormat.Format16bppGrayScale: num = 1; break; } int num8 = num; int num9 = width * num8; int stride = image.Stride; int stride2 = overlay.Stride; byte *ptr3 = (byte *)image.ImageData.ToPointer(); byte *ptr4 = (byte *)overlay.ImageData.ToPointer(); for (int j = 0; j < height; j++) { ushort *ptr5 = (ushort *)(ptr3 + (long)j * (long)stride); ushort *ptr6 = (ushort *)(ptr4 + (long)j * (long)stride2); int num10 = 0; while (num10 < num9) { if (*ptr6 < *ptr5) { *ptr5 = *ptr6; } num10++; ptr5++; ptr6++; } } }
protected unsafe override void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData, Rectangle rect) { if (rect.Width < 3 || rect.Height < 3) { throw new InvalidImagePropertiesException("Processing rectangle mast be at least 3x3 in size."); } int num = rect.Left + 1; int num2 = rect.Top + 1; int num3 = rect.Right - 1; int num4 = rect.Bottom - 1; int stride = destinationData.Stride; int stride2 = sourceData.Stride; int num5 = stride - rect.Width + 1; int num6 = stride2 - rect.Width + 1; byte *ptr = (byte *)sourceData.ImageData.ToPointer(); byte *ptr2 = (byte *)destinationData.ImageData.ToPointer(); ptr += num - 1 + (num2 - 1) * stride2; ptr2 += num - 1 + (num2 - 1) * stride; byte b = *ptr; if (ptr[1] > b) { b = ptr[1]; } if (ptr[stride2] > b) { b = ptr[stride2]; } if (ptr[stride2 + 1] > b) { b = ptr[stride2 + 1]; } *ptr2 = b; ptr++; ptr2++; int num7 = num; while (num7 < num3) { b = *ptr; if (ptr[-1] > b) { b = ptr[-1]; } if (ptr[1] > b) { b = ptr[1]; } if (ptr[stride2 - 1] > b) { b = ptr[stride2 - 1]; } if (ptr[stride2] > b) { b = ptr[stride2]; } if (ptr[stride2 + 1] > b) { b = ptr[stride2 + 1]; } *ptr2 = b; num7++; ptr++; ptr2++; } b = *ptr; if (ptr[-1] > b) { b = ptr[-1]; } if (ptr[stride2 - 1] > b) { b = ptr[stride2 - 1]; } if (ptr[stride2] > b) { b = ptr[stride2]; } *ptr2 = b; ptr += num6; ptr2 += num5; for (int i = num2; i < num4; i++) { b = *ptr; if (ptr[1] > b) { b = ptr[1]; } if (ptr[-stride2] > b) { b = ptr[-stride2]; } if (ptr[-stride2 + 1] > b) { b = ptr[-stride2 + 1]; } if (ptr[stride2] > b) { b = ptr[stride2]; } if (ptr[stride2 + 1] > b) { b = ptr[stride2 + 1]; } *ptr2 = b; ptr++; ptr2++; int num8 = num; while (num8 < num3) { b = *ptr; if (ptr[-1] > b) { b = ptr[-1]; } if (ptr[1] > b) { b = ptr[1]; } if (ptr[-stride2 - 1] > b) { b = ptr[-stride2 - 1]; } if (ptr[-stride2] > b) { b = ptr[-stride2]; } if (ptr[-stride2 + 1] > b) { b = ptr[-stride2 + 1]; } if (ptr[stride2 - 1] > b) { b = ptr[stride2 - 1]; } if (ptr[stride2] > b) { b = ptr[stride2]; } if (ptr[stride2 + 1] > b) { b = ptr[stride2 + 1]; } *ptr2 = b; num8++; ptr++; ptr2++; } b = *ptr; if (ptr[-1] > b) { b = ptr[-1]; } if (ptr[-stride2 - 1] > b) { b = ptr[-stride2 - 1]; } if (ptr[-stride2] > b) { b = ptr[-stride2]; } if (ptr[stride2 - 1] > b) { b = ptr[stride2 - 1]; } if (ptr[stride2] > b) { b = ptr[stride2]; } *ptr2 = b; ptr += num6; ptr2 += num5; } *ptr2 = (byte)(*ptr | ptr[1] | ptr[-stride2] | ptr[-stride2 + 1]); b = *ptr; if (ptr[1] > b) { b = ptr[1]; } if (ptr[-stride2] > b) { b = ptr[-stride2]; } if (ptr[-stride2 + 1] > b) { b = ptr[-stride2 + 1]; } *ptr2 = b; ptr++; ptr2++; int num9 = num; while (num9 < num3) { b = *ptr; if (ptr[-1] > b) { b = ptr[-1]; } if (ptr[1] > b) { b = ptr[1]; } if (ptr[-stride2 - 1] > b) { b = ptr[-stride2 - 1]; } if (ptr[-stride2] > b) { b = ptr[-stride2]; } if (ptr[-stride2 + 1] > b) { b = ptr[-stride2 + 1]; } *ptr2 = b; num9++; ptr++; ptr2++; } b = *ptr; if (ptr[-1] > b) { b = ptr[-1]; } if (ptr[-stride2 - 1] > b) { b = ptr[-stride2 - 1]; } if (ptr[-stride2] > b) { b = ptr[-stride2]; } *ptr2 = b; }
/// <summary> /// Apply filter to an unmanaged image or its part. /// </summary> /// /// <param name="image">Unmanaged image to apply filter to.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// /// <remarks>The method applies the filter directly to the provided source image.</remarks> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ApplyInPlace(UnmanagedImage image, Rectangle rect) { dilation.ApplyInPlace(image, rect); errosion.ApplyInPlace(image, rect); }
/// <summary> /// Apply filter to an image in unmanaged memory. /// </summary> /// /// <param name="sourceImage">Source image in unmanaged memory to apply filter to.</param> /// <param name="destinationImage">Destination image in unmanaged memory to put result into.</param> /// /// <remarks><para>The method keeps the source image unchanged and puts result of image processing /// into destination image.</para> /// /// <para><note>The destination image must have the same width and height as source image. Also /// destination image must have pixel format, which is expected by particular filter (see /// <see cref="FormatTranslations"/> property for information about pixel format conversions).</note></para> /// </remarks> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// <exception cref="InvalidImagePropertiesException">Incorrect destination pixel format.</exception> /// <exception cref="InvalidImagePropertiesException">Destination image has wrong width and/or height.</exception> /// public void Apply( UnmanagedImage sourceImage, UnmanagedImage destinationImage ) { errosion.Apply( sourceImage, destinationImage ); dilatation.ApplyInPlace( destinationImage ); }
/// <summary> /// Apply filter to an image (not implemented). /// </summary> /// /// <param name="sourceImage">Source image to be processed.</param> /// <param name="destinationImage">Destination image to store filter's result.</param> /// /// <exception cref="NotImplementedException">The method is not implemented.</exception> /// public void Apply(UnmanagedImage sourceImage, UnmanagedImage destinationImage) { throw new NotImplementedException("The method is not implemented filter."); }
/// <summary> /// Apply filter to an unmanaged image or its part. /// </summary> /// /// <param name="image">Unmanaged image to apply filter to.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// /// <remarks>The method applies the filter directly to the provided source image.</remarks> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ApplyInPlace( UnmanagedImage image, Rectangle rect ) { errosion.ApplyInPlace( image, rect ); dilatation.ApplyInPlace( image, rect ); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="overlay">Overlay image data.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage image, UnmanagedImage overlay) { PixelFormat pixelFormat = image.PixelFormat; // get image dimension int width = image.Width; int height = image.Height; // pixel value int v; if ( (pixelFormat == PixelFormat.Format8bppIndexed) || (pixelFormat == PixelFormat.Format24bppRgb) || (pixelFormat == PixelFormat.Format32bppRgb) || (pixelFormat == PixelFormat.Format32bppArgb)) { // initialize other variables int pixelSize = (pixelFormat == PixelFormat.Format8bppIndexed) ? 1 : (pixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; int lineSize = width * pixelSize; int srcOffset = image.Stride - lineSize; int ovrOffset = overlay.Stride - lineSize; // do the job byte *ptr = (byte *)image.ImageData.ToPointer( ); byte *ovr = (byte *)overlay.ImageData.ToPointer( ); // for each line for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < lineSize; x++, ptr++, ovr++) { // abs(sub) v = (int)*ptr - (int)*ovr; *ptr = (v < 0) ? (byte)-v : (byte)v; } ptr += srcOffset; ovr += ovrOffset; } } else { // initialize other variables int pixelSize = (pixelFormat == PixelFormat.Format16bppGrayScale) ? 1 : (pixelFormat == PixelFormat.Format48bppRgb) ? 3 : 4; int lineSize = width * pixelSize; int srcStride = image.Stride; int ovrStride = overlay.Stride; // do the job byte *basePtr = (byte *)image.ImageData.ToPointer( ); byte *baseOvr = (byte *)overlay.ImageData.ToPointer( ); // for each line for (int y = 0; y < height; y++) { ushort *ptr = (ushort *)(basePtr + y * srcStride); ushort *ovr = (ushort *)(baseOvr + y * ovrStride); // for each pixel for (int x = 0; x < lineSize; x++, ptr++, ovr++) { // abs(sub) v = (int)*ptr - (int)*ovr; *ptr = (v < 0) ? (ushort)-v : (ushort)v; } } } }
// Perform parallel image processing without checking pixels' coordinates to make sure those are in bounds private unsafe void ProcessWithoutChecksParallel( UnmanagedImage source, UnmanagedImage destination, Rectangle rect ) { int startX = rect.Left; int startY = rect.Top; int stopX = rect.Right; int stopY = rect.Bottom; int pixelSize = System.Drawing.Image.GetPixelFormatSize( source.PixelFormat ) / 8; int kernelHalf = kernelSize / 2; int bytesInKernelRow = kernelSize * pixelSize; int srcStride = source.Stride; int dstStride = destination.Stride; int srcOffset = srcStride - rect.Width * pixelSize; int dstOffset = dstStride - rect.Width * pixelSize; // offset of the first kernel's pixel int srcKernelFistPixelOffset = kernelHalf * ( srcStride + pixelSize ); // offset to move to the next kernel's pixel after processing one kernel's row int srcKernelOffset = srcStride - bytesInKernelRow; byte* srcBase = (byte*) source.ImageData.ToPointer( ); byte* dstBase = (byte*) destination.ImageData.ToPointer( ); // allign pointers to the left most pixel in the first row srcBase += startX * pixelSize; dstBase += startX * pixelSize; if ( pixelSize > 1 ) { Parallel.For( startY, stopY, delegate( int y ) { byte* src = srcBase + y * srcStride; byte* dst = dstBase + y * dstStride; byte srcR, srcG, srcB; byte srcR0, srcG0, srcB0; byte* srcPixel; int tx, ty; double sCoefR, sCoefG, sCoefB, sMembR, sMembG, sMembB, coefR, coefG, coefB; for ( int x = startX; x < stopX; x++, src += pixelSize, dst += pixelSize ) { // lower right corner - to start processing from that point srcPixel = src + srcKernelFistPixelOffset; sCoefR = 0; sCoefG = 0; sCoefB = 0; sMembR = 0; sMembG = 0; sMembB = 0; srcR0 = src[RGB.R]; srcG0 = src[RGB.G]; srcB0 = src[RGB.B]; // move from lower right to upper left corner ty = kernelSize; while ( ty != 0 ) { ty--; tx = kernelSize; while ( tx != 0 ) { tx--; srcR = srcPixel[RGB.R]; srcG = srcPixel[RGB.G]; srcB = srcPixel[RGB.B]; coefR = spatialFunc[tx, ty] * colorFunc[srcR, srcR0]; coefG = spatialFunc[tx, ty] * colorFunc[srcG, srcG0]; coefB = spatialFunc[tx, ty] * colorFunc[srcB, srcB0]; sCoefR += coefR; sCoefG += coefG; sCoefB += coefB; sMembR += coefR * srcR; sMembG += coefG * srcG; sMembB += coefB * srcB; srcPixel -= pixelSize; } srcPixel -= srcKernelOffset; } dst[RGB.R] = (byte) ( sMembR / sCoefR ); dst[RGB.G] = (byte) ( sMembG / sCoefG ); dst[RGB.B] = (byte) ( sMembB / sCoefB ); } } ); } else { // 8bpp grayscale images Parallel.For( startY, stopY, delegate( int y ) { byte* src = srcBase + y * srcStride; byte* dst = dstBase + y * dstStride; byte srcC; byte srcC0; byte* srcPixel; double sCoefC, sMembC, coefC; int tx, ty; for ( int x = startX; x < stopX; x++, src++, dst++ ) { // lower right corner - to start processing from that point srcPixel = src + srcKernelFistPixelOffset; sCoefC = 0; sMembC = 0; srcC0 = *src; // move from lower right to upper left corner ty = kernelSize; while ( ty != 0 ) { ty--; tx = kernelSize; while ( tx != 0 ) { tx--; srcC = *( srcPixel ); coefC = spatialFunc[tx, ty] * colorFunc[srcC, srcC0]; sCoefC += coefC; sMembC += coefC * srcC; srcPixel -= pixelSize; } srcPixel -= srcKernelOffset; } *dst = (byte) ( sMembC / sCoefC ); } } ); } }
/// <summary> /// Computes the new image size. /// </summary> /// protected override Size CalculateNewImageSize(UnmanagedImage sourceData) { // Calculate source size float w = sourceData.Width; float h = sourceData.Height; // Get the four corners and the center of the image PointF[] corners = { new PointF(0, 0), new PointF(w, 0), new PointF(0, h), new PointF(w, h), new PointF(w / 2f, h / 2f) }; // Project those points corners = homography.Inverse().TransformPoints(corners); // Recalculate image size float[] px = { corners[0].X, corners[1].X, corners[2].X, corners[3].X }; float[] py = { corners[0].Y, corners[1].Y, corners[2].Y, corners[3].Y }; float maxX = Matrix.Max(px); float minX = Matrix.Min(px); float newWidth = Math.Max(maxX, overlayImage.Width) - Math.Min(0, minX); float maxY = Accord.Math.Matrix.Max(py); float minY = Accord.Math.Matrix.Min(py); float newHeight = Math.Max(maxY, overlayImage.Height) - Math.Min(0, minY); // Store overlay image size this.imageSize = new Size((int)Math.Round(maxX - minX), (int)Math.Round(maxY - minY)); // Store image center this.center = Point.Round(corners[4]); // Calculate and store image offset int offsetX = 0, offsetY = 0; if (minX < 0) { offsetX = (int)Math.Round(minX); } if (minY < 0) { offsetY = (int)Math.Round(minY); } this.offset = new Point(offsetX, offsetY); if (Double.IsNaN(newWidth) || newWidth == 0) { newWidth = 1; } if (Double.IsNaN(newHeight) || newHeight == 0) { newHeight = 1; } // Return the final image size return(new Size((int)Math.Ceiling(newWidth), (int)Math.Ceiling(newHeight))); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// protected override void ProcessFilter( UnmanagedImage sourceData, UnmanagedImage destinationData ) { // get width and height int width = sourceData.Width; int height = sourceData.Height; if ( ( ( width & 1 ) == 1 ) || ( ( height & 1 ) == 1 ) || ( width < 2 ) || ( height < 2 ) ) { throw new InvalidImagePropertiesException( "Source image must have even width and height. Width and height can not be smaller than 2." ); } switch ( bayerPattern ) { case BayerPattern.GRBG: ApplyGRBG( sourceData, destinationData ); break; case BayerPattern.BGGR: ApplyBGGR( sourceData, destinationData ); break; } }
/// <summary> /// Process the image filter. /// </summary> /// protected override void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData) { // Locks the overlay image BitmapData overlayData = overlayImage.LockBits( new Rectangle(0, 0, overlayImage.Width, overlayImage.Height), ImageLockMode.ReadOnly, overlayImage.PixelFormat); // get source image size int width = sourceData.Width; int height = sourceData.Height; // get destination image size int newWidth = destinationData.Width; int newHeight = destinationData.Height; int srcPixelSize = System.Drawing.Image.GetPixelFormatSize(sourceData.PixelFormat) / 8; int orgPixelSize = System.Drawing.Image.GetPixelFormatSize(overlayData.PixelFormat) / 8; int srcStride = sourceData.Stride; int dstOffset = destinationData.Stride - newWidth * 4; // destination always 32bpp argb // Get center of first image Point center1 = new Point((int)(overlayImage.Width / 2f), (int)(overlayImage.Height / 2f)); // Get center of second image Point center2 = this.center; // Compute maximum center distances float dmax1 = Math.Min( distance(center1.X, center1.Y, center2.X - imageSize.Width / 2f, center1.Y), distance(center1.X, center1.Y, center1.X, center1.Y + overlayImage.Height / 2f)); float dmax2 = Math.Min( distance(center2.X, center2.Y, center2.X + imageSize.Width / 2f, center2.Y), distance(center2.X, center2.Y, center2.X, center2.Y + imageSize.Height / 2f)); float dmax = -System.Math.Abs(dmax2 - dmax1); // fill values byte fillR = fillColor.R; byte fillG = fillColor.G; byte fillB = fillColor.B; byte fillA = 0;//fillColor.A; // Retrieve homography matrix as float array float[,] H = (float[, ])homography; // do the job unsafe { byte *org = (byte *)overlayData.Scan0.ToPointer(); byte *src = (byte *)sourceData.ImageData.ToPointer(); byte *dst = (byte *)destinationData.ImageData.ToPointer(); // destination pixel's coordinate relative to image center double cx, cy; // destination pixel's homogenous coordinate double hx, hy, hw; // source pixel's coordinates int ox, oy; // Copy the overlay image for (int y = 0; y < newHeight; y++) { for (int x = 0; x < newWidth; x++, dst += 4) { ox = (int)(x + offset.X); oy = (int)(y + offset.Y); // validate source pixel's coordinates if ((ox < 0) || (oy < 0) || (ox >= overlayData.Width) || (oy >= overlayData.Height)) { // fill destination image with filler dst[0] = fillB; dst[1] = fillG; dst[2] = fillR; dst[3] = fillA; } else { int c = oy * overlayData.Stride + ox * orgPixelSize; // fill destination image with pixel from original image if (orgPixelSize == 3) { // 24 bpp dst[0] = org[c + 0]; dst[1] = org[c + 1]; dst[2] = org[c + 2]; dst[3] = (byte)255; } else if (orgPixelSize == 4) { // 32 bpp dst[0] = org[c + 0]; dst[1] = org[c + 1]; dst[2] = org[c + 2]; dst[3] = org[c + 3]; } else { // 8 bpp dst[0] = org[c]; dst[1] = org[c]; dst[2] = org[c]; dst[3] = org[c]; } } } dst += dstOffset; } org = (byte *)overlayData.Scan0.ToPointer(); src = (byte *)sourceData.ImageData.ToPointer(); dst = (byte *)destinationData.ImageData.ToPointer(); // Project and blend the second image for (int y = 0; y < newHeight; y++) { for (int x = 0; x < newWidth; x++, dst += 4) { cx = x + offset.X; cy = y + offset.Y; // projection using homogenous coordinates hw = (H[2, 0] * cx + H[2, 1] * cy + H[2, 2]); hx = (H[0, 0] * cx + H[0, 1] * cy + H[0, 2]) / hw; hy = (H[1, 0] * cx + H[1, 1] * cy + H[1, 2]) / hw; // coordinate of the nearest point ox = (int)(hx); oy = (int)(hy); // validate source pixel's coordinates if ((ox >= 0) && (oy >= 0) && (ox < width) && (oy < height)) { int c = oy * srcStride + ox * srcPixelSize; // fill destination image with pixel from source image if (srcPixelSize == 4 && src[c + 3] == 0) { // source pixel is fully transparent, nothing to copy } else if (dst[3] > 0) { float f1 = 0.5f, f2 = 0.5f; if (Gradient) { // there is a pixel from the other image here, blend float d1 = distance(x, y, center1.X, center1.Y); float d2 = distance(x, y, center2.X, center2.Y); f1 = Accord.Math.Tools.Scale(0, dmax, 0, 1, d1 - d2); if (f1 < 0) { f1 = 0f; } if (f1 > 1) { f1 = 1f; } f2 = (1f - f1); } if (!AlphaOnly) { if (srcPixelSize == 3) { // 24 bpp dst[0] = (byte)(src[c + 0] * f2 + dst[0] * f1); dst[1] = (byte)(src[c + 1] * f2 + dst[1] * f1); dst[2] = (byte)(src[c + 2] * f2 + dst[2] * f1); dst[3] = (byte)255; } else if (srcPixelSize == 4) { // 32 bpp dst[0] = (byte)(src[c + 0] * f2 + dst[0] * f1); dst[1] = (byte)(src[c + 1] * f2 + dst[1] * f1); dst[2] = (byte)(src[c + 2] * f2 + dst[2] * f1); dst[3] = (byte)(src[c + 3] * f2 + dst[3] * f1); } else { // 8 bpp dst[0] = (byte)(src[c] * f2 + dst[0] * f1); dst[1] = (byte)(src[c] * f2 + dst[1] * f1); dst[2] = (byte)(src[c] * f2 + dst[2] * f1); dst[3] = (byte)255; } } else { if (srcPixelSize == 3) { // 24 bpp dst[0] = (byte)(src[c + 0]); dst[1] = (byte)(src[c + 1]); dst[2] = (byte)(src[c + 2]); } else if (srcPixelSize == 4) { // 32 bpp dst[0] = (byte)(src[c + 0]); dst[1] = (byte)(src[c + 1]); dst[2] = (byte)(src[c + 2]); } else { // 8 bpp dst[0] = (byte)(src[c]); dst[1] = (byte)(src[c]); dst[2] = (byte)(src[c]); } } } else { // just copy the source into the destination image if (srcPixelSize == 3) { // 24bpp dst[0] = src[c + 0]; dst[1] = src[c + 1]; dst[2] = src[c + 2]; dst[3] = (byte)255; } else if (srcPixelSize == 4) { // 32bpp dst[0] = src[c + 0]; dst[1] = src[c + 1]; dst[2] = src[c + 2]; dst[3] = src[c + 3]; } else { // 8bpp dst[0] = src[c]; dst[1] = src[c]; dst[2] = src[c]; dst[3] = 0; } } } } dst += dstOffset; } } overlayImage.UnlockBits(overlayData); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image, Rectangle rect ) { // get pixel size int pixelSize = ( image.PixelFormat == PixelFormat.Format24bppRgb ) ? 3 : 4; int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; int offset = image.Stride - rect.Width * pixelSize; RGB rgb = new RGB( ); HSL hsl = new HSL( ); bool updated; // do the job byte* ptr = (byte*) image.ImageData.ToPointer( ); // allign pointer to the first pixel to process ptr += ( startY * image.Stride + startX * pixelSize ); // for each row for ( int y = startY; y < stopY; y++ ) { // for each pixel for ( int x = startX; x < stopX; x++, ptr += pixelSize ) { updated = false; rgb.Red = ptr[RGB.R]; rgb.Green = ptr[RGB.G]; rgb.Blue = ptr[RGB.B]; // convert to HSL AForge.Imaging.HSL.FromRGB( rgb, hsl ); // check HSL values if ( ( hsl.Saturation >= saturation.Min ) && ( hsl.Saturation <= saturation.Max ) && ( hsl.Luminance >= luminance.Min ) && ( hsl.Luminance <= luminance.Max ) && ( ( ( hue.Min < hue.Max ) && ( hsl.Hue >= hue.Min ) && ( hsl.Hue <= hue.Max ) ) || ( ( hue.Min > hue.Max ) && ( ( hsl.Hue >= hue.Min ) || ( hsl.Hue <= hue.Max ) ) ) ) ) { if ( !fillOutsideRange ) { if ( updateH ) hsl.Hue = fillH; if ( updateS ) hsl.Saturation = fillS; if ( updateL ) hsl.Luminance = fillL; updated = true; } } else { if ( fillOutsideRange ) { if ( updateH ) hsl.Hue = fillH; if ( updateS ) hsl.Saturation = fillS; if ( updateL ) hsl.Luminance = fillL; updated = true; } } if ( updated ) { // convert back to RGB AForge.Imaging.HSL.ToRGB( hsl, rgb ); ptr[RGB.R] = rgb.Red; ptr[RGB.G] = rgb.Green; ptr[RGB.B] = rgb.Blue; } } ptr += offset; } }
/// <summary> /// Initializes a new instance of the <see cref="Divide"/> class. /// </summary> /// /// <param name="unmanagedOverlayImage">Unmanaged overlay image.</param> /// public Divide(UnmanagedImage unmanagedOverlayImage) : base(unmanagedOverlayImage) { InitFormatTranslations(); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image, Rectangle rect ) { int pixelSize = Image.GetPixelFormatSize( image.PixelFormat ) / 8; // processing start and stop X,Y positions int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; int offset = image.Stride - rect.Width * pixelSize; // do the job byte* ptr = (byte*) image.ImageData.ToPointer( ); // allign pointer to the first pixel to process ptr += ( startY * image.Stride + startX * pixelSize ); if ( image.PixelFormat == PixelFormat.Format8bppIndexed ) { // grayscale image for ( int y = startY; y < stopY; y++ ) { for ( int x = startX; x < stopX; x++, ptr++ ) { // gray *ptr = mapGreen[*ptr]; } ptr += offset; } } else { // RGB image for ( int y = startY; y < stopY; y++ ) { for ( int x = startX; x < stopX; x++, ptr += pixelSize ) { // red ptr[RGB.R] = mapRed[ptr[RGB.R]]; // green ptr[RGB.G] = mapGreen[ptr[RGB.G]]; // blue ptr[RGB.B] = mapBlue[ptr[RGB.B]]; } ptr += offset; } } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="overlay">Overlay image data.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage image, UnmanagedImage overlay) { PixelFormat pixelFormat = image.PixelFormat; int width = image.Width; int height = image.Height; if ((pixelFormat == PixelFormat.Format8bppIndexed) || (pixelFormat == PixelFormat.Format24bppRgb) || (pixelFormat == PixelFormat.Format32bppRgb) || (pixelFormat == PixelFormat.Format32bppArgb)) { // initialize other variables var pixelSize = (pixelFormat == PixelFormat.Format8bppIndexed) ? 1 : (pixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; var lineSize = width * pixelSize; var srcOffset = image.Stride - lineSize; var ovrOffset = overlay.Stride - lineSize; // new pixel value // do the job var ptr = (byte *)image.ImageData.ToPointer(); var ovr = (byte *)overlay.ImageData.ToPointer(); // for each line for (var y = 0; y < height; y++) { // for each pixel for (var x = 0; x < lineSize; x++, ptr++, ovr++) { var v = (*ptr * 256f) / (*ovr + 1f); * ptr = (v > 255) ? (byte)255 : (byte)v; } ptr += srcOffset; ovr += ovrOffset; } } else { // initialize other variables var pixelSize = (pixelFormat == PixelFormat.Format16bppGrayScale) ? 1 : (pixelFormat == PixelFormat.Format48bppRgb) ? 3 : 4; var lineSize = width * pixelSize; var srcStride = image.Stride; var ovrStride = overlay.Stride; // new pixel value // do the job var basePtr = (byte *)image.ImageData.ToPointer(); var baseOvr = (byte *)overlay.ImageData.ToPointer(); // for each line for (var y = 0; y < height; y++) { var ptr = (ushort *)(basePtr + y * srcStride); var ovr = (ushort *)(baseOvr + y * ovrStride); // for each pixel for (var x = 0; x < lineSize; x++, ptr++, ovr++) { var v = (*ptr * 65536f) / (*ovr + 1f); * ptr = (v > 65535) ? (ushort)65535 : (ushort)v; } } } }
/// <summary> /// Apply filter to an unmanaged image. /// </summary> /// /// <param name="image">Unmanaged image to apply filter to.</param> /// /// <remarks>The method applies the filter directly to the provided source unmanaged image.</remarks> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ApplyInPlace(UnmanagedImage image) { dilation.ApplyInPlace(image); errosion.ApplyInPlace(image); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="overlay">Overlay image data.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage image, UnmanagedImage overlay) { var pixelFormat = image.PixelFormat; // get image dimension var width = image.Width; var height = image.Height; if ( (pixelFormat == PixelFormat.Format8bppIndexed) || (pixelFormat == PixelFormat.Format24bppRgb) || (pixelFormat == PixelFormat.Format32bppRgb) || (pixelFormat == PixelFormat.Format32bppArgb)) { // initialize other variables var pixelSize = (pixelFormat == PixelFormat.Format8bppIndexed) ? 1 : (pixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; var lineSize = width * pixelSize; var srcOffset = image.Stride - lineSize; var ovrOffset = overlay.Stride - lineSize; // do the job var ptr = (byte *)image.ImageData.ToPointer( ); var ovr = (byte *)overlay.ImageData.ToPointer( ); // for each line for (var y = 0; y < height; y++) { // for each pixel for (var x = 0; x < lineSize; x++, ptr++, ovr++) { if (*ovr < *ptr) { *ptr = *ovr; } } ptr += srcOffset; ovr += ovrOffset; } } else { // initialize other variables var pixelSize = (pixelFormat == PixelFormat.Format16bppGrayScale) ? 1 : (pixelFormat == PixelFormat.Format48bppRgb) ? 3 : 4; var lineSize = width * pixelSize; var srcStride = image.Stride; var ovrStride = overlay.Stride; // do the job var basePtr = (byte *)image.ImageData.ToPointer( ); var baseOvr = (byte *)overlay.ImageData.ToPointer( ); // for each line for (var y = 0; y < height; y++) { var ptr = (ushort *)(basePtr + y * srcStride); var ovr = (ushort *)(baseOvr + y * ovrStride); // for each pixel for (var x = 0; x < lineSize; x++, ptr++, ovr++) { if (*ovr < *ptr) { *ptr = *ovr; } } } } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="overlay">Overlay image data.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image, UnmanagedImage overlay ) { // get image dimension int width = image.Width; int height = image.Height; // initialize other variables int pixelSize = ( image.PixelFormat == PixelFormat.Format8bppIndexed ) ? 1 : 3; int lineSize = width * pixelSize; int offset = image.Stride - lineSize; int ovrOffset = overlay.Stride - lineSize; // percentage of overlay image double q = 1.0 - sourcePercent; // do the job byte * ptr = (byte*) image.ImageData.ToPointer( ); byte * ovr = (byte*) overlay.ImageData.ToPointer( ); // for each line for ( int y = 0; y < height; y++ ) { // for each pixel for ( int x = 0; x < lineSize; x++, ptr++, ovr++ ) { *ptr = (byte) ( ( sourcePercent * ( *ptr ) ) + ( q * ( *ovr ) ) ); } ptr += offset; ovr += ovrOffset; } }
/// <summary> /// Initializes a new instance of the <see cref="Intersect"/> class. /// </summary> /// /// <param name="unmanagedOverlayImage">Unmanaged overlay image.</param> /// public Intersect(UnmanagedImage unmanagedOverlayImage) : base(unmanagedOverlayImage) { this.InitFormatTranslations( ); }
/// <summary> /// Apply filter to an image in unmanaged memory. /// </summary> /// /// <param name="image">Source image in unmanaged memory to apply filter to.</param> /// /// <returns>Returns filter's result obtained by applying the filter to /// the source image.</returns> /// /// <remarks>The method keeps the source image unchanged and returns /// the result of image processing filter as new image.</remarks> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public UnmanagedImage Apply( UnmanagedImage image ) { UnmanagedImage destImage = errosion.Apply( image ); dilatation.ApplyInPlace( destImage ); return destImage; }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage image, Rectangle rect) { int pixelSize = Image.GetPixelFormatSize(image.PixelFormat) / 8; int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; int stride = image.Stride; int offset = stride - rect.Width * pixelSize; // levels linear correction filter is going to be used on STEP 2 LevelsLinear levelsLinear = new LevelsLinear(); // STEP 1 - search for min and max pixel values byte *ptr = (byte *)image.ImageData.ToPointer(); // check image format if (image.PixelFormat == PixelFormat.Format8bppIndexed) { // allign pointer to the first pixel to process ptr += (startY * stride + startX); byte min = 255; byte max = 0; for (int y = startY; y < stopY; y++) { for (int x = startX; x < stopX; x++, ptr++) { byte value = *ptr; if (value < min) { min = value; } if (value > max) { max = value; } } ptr += offset; } levelsLinear.InGray = new IntRange(min, max); } else { // allign pointer to the first pixel to process ptr += (startY * stride + startX * pixelSize); byte minR = 255, minG = 255, minB = 255; byte maxR = 0, maxG = 0, maxB = 0; for (int y = startY; y < stopY; y++) { for (int x = startX; x < stopX; x++, ptr += pixelSize) { // red byte value = ptr[RGB.R]; if (value < minR) { minR = value; } if (value > maxR) { maxR = value; } // green value = ptr[RGB.G]; if (value < minG) { minG = value; } if (value > maxG) { maxG = value; } // blue value = ptr[RGB.B]; if (value < minB) { minB = value; } if (value > maxB) { maxB = value; } } ptr += offset; } levelsLinear.InRed = new IntRange(minR, maxR); levelsLinear.InGreen = new IntRange(minG, maxG); levelsLinear.InBlue = new IntRange(minB, maxB); } // STEP 2 - run levels linear correction levelsLinear.ApplyInPlace(image, rect); }
/// <summary> /// Apply filter to an unmanaged image. /// </summary> /// /// <param name="image">Unmanaged image to apply filter to.</param> /// /// <remarks>The method applies the filter directly to the provided source unmanaged image.</remarks> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ApplyInPlace( UnmanagedImage image ) { errosion.ApplyInPlace( image ); dilatation.ApplyInPlace( image ); }
/// <summary> /// Perform color dithering for the specified image. /// </summary> /// /// <param name="sourceImage">Source image to do color dithering for.</param> /// /// <returns>Returns color dithered image. See <see cref="ColorTable"/> for information about format of /// the result image.</returns> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image. It must 24 or 32 bpp color image.</exception> /// public Bitmap Apply(UnmanagedImage sourceImage) { if ((sourceImage.PixelFormat != PixelFormat.Format24bppRgb) && (sourceImage.PixelFormat != PixelFormat.Format32bppRgb) && (sourceImage.PixelFormat != PixelFormat.Format32bppArgb) && (sourceImage.PixelFormat != PixelFormat.Format32bppPArgb)) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source image."); } cache.Clear(); // get image size int width = sourceImage.Width; int height = sourceImage.Height; int stride = sourceImage.Stride; int pixelSize = Bitmap.GetPixelFormatSize(sourceImage.PixelFormat) / 8; // create destination image Bitmap destImage = new Bitmap(width, height, (colorTable.Length > 16) ? PixelFormat.Format8bppIndexed : PixelFormat.Format4bppIndexed); // and init its palette ColorPalette cp = destImage.Palette; for (int i = 0, n = colorTable.Length; i < n; i++) { cp.Entries[i] = colorTable[i]; } destImage.Palette = cp; // lock destination image BitmapData destData = destImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, destImage.PixelFormat); // pixel values int r, g, b, toAdd; int rows = matrix.GetLength(0); int cols = matrix.GetLength(1); // do the job unsafe { byte *ptr = (byte *)sourceImage.ImageData.ToPointer(); byte *dstBase = (byte *)destData.Scan0.ToPointer(); byte colorIndex; bool is8bpp = (colorTable.Length > 16); // for each line for (int y = 0; y < height; y++) { byte *dst = dstBase + y * destData.Stride; // for each pixels for (int x = 0; x < width; x++, ptr += pixelSize) { toAdd = matrix[(y % rows), (x % cols)]; r = ptr[RGB.R] + toAdd; g = ptr[RGB.G] + toAdd; b = ptr[RGB.B] + toAdd; if (r > 255) { r = 255; } if (g > 255) { g = 255; } if (b > 255) { b = 255; } // get color from palette, which is the closest to current pixel's value GetClosestColor(r, g, b, out colorIndex); // write color index as pixel's value to destination image if (is8bpp) { *dst = colorIndex; dst++; } else { if (x % 2 == 0) { *dst |= (byte)(colorIndex << 4); } else { *dst |= (colorIndex); dst++; } } } } } destImage.UnlockBits(destData); return(destImage); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// /// <exception cref="InvalidImagePropertiesException">Processing rectangle mast be at least 3x3 in size.</exception> /// protected override unsafe void ProcessFilter( UnmanagedImage sourceData, UnmanagedImage destinationData, Rectangle rect ) { if ( ( rect.Width < 3 ) || ( rect.Height < 3 ) ) { throw new InvalidImagePropertiesException( "Processing rectangle mast be at least 3x3 in size." ); } // processing start and stop X,Y positions int startX = rect.Left + 1; int startY = rect.Top + 1; int stopX = rect.Right - 1; int stopY = rect.Bottom - 1; int dstStride = destinationData.Stride; int srcStride = sourceData.Stride; int dstOffset = dstStride - rect.Width + 1; int srcOffset = srcStride - rect.Width + 1; // image pointers byte* src = (byte*) sourceData.ImageData.ToPointer( ); byte* dst = (byte*) destinationData.ImageData.ToPointer( ); // allign pointers by X and Y src += ( startX - 1 ) + ( startY - 1 ) * srcStride; dst += ( startX - 1 ) + ( startY - 1 ) * dstStride; // --- process the first line setting all to black for ( int x = startX - 1; x < stopX; x++, src++, dst++ ) { *dst = 0; } *dst = 0; src += srcOffset; dst += dstOffset; // --- process all lines except the last one for ( int y = startY; y < stopY; y++ ) { // set edge pixel to black *dst = 0; src++; dst++; // for each pixel for ( int x = startX; x < stopX; x++, src++, dst++ ) { *dst = (byte) ( *src & src[-1] & src[1] & src[-srcStride] & src[-srcStride - 1] & src[-srcStride + 1] & src[srcStride] & src[srcStride - 1] & src[srcStride + 1] ); } // set edge pixel to black *dst = 0; src += srcOffset; dst += dstOffset; } // --- process the last line setting all to black // for each pixel for ( int x = startX - 1; x < stopX; x++, src++, dst++ ) { *dst = 0; } *dst = 0; }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="source">Source image data.</param> /// <param name="destination">Destination image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage source, UnmanagedImage destination, Rectangle rect) { // processing start and stop X,Y positions int startX = rect.Left + 1; int startY = rect.Top + 1; int stopX = startX + rect.Width - 2; int stopY = startY + rect.Height - 2; int width = rect.Width - 2; int height = rect.Height - 2; int dstStride = destination.Stride; int srcStride = source.Stride; int dstOffset = dstStride - rect.Width + 2; int srcOffset = srcStride - rect.Width + 2; // pixel's value and gradients int gx, gy; // double orientation, toAngle = 180.0 / System.Math.PI; float leftPixel = 0, rightPixel = 0; // STEP 1 - blur image UnmanagedImage blurredImage = gaussianFilter.Apply(source); // orientation array byte[] orients = new byte[width * height]; // gradients array float[,] gradients = new float[source.Width, source.Height]; float maxGradient = float.NegativeInfinity; // do the job byte *src = (byte *)blurredImage.ImageData.ToPointer( ); // allign pointer src += srcStride * startY + startX; // STEP 2 - calculate magnitude and edge orientation int p = 0; // for each line for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, src++, p++) { gx = src[-srcStride + 1] + src[srcStride + 1] - src[-srcStride - 1] - src[srcStride - 1] + 2 * (src[1] - src[-1]); gy = src[-srcStride - 1] + src[-srcStride + 1] - src[srcStride - 1] - src[srcStride + 1] + 2 * (src[-srcStride] - src[srcStride]); // get gradient value gradients[x, y] = (float)Math.Sqrt(gx * gx + gy * gy); if (gradients[x, y] > maxGradient) { maxGradient = gradients[x, y]; } // --- get orientation if (gx == 0) { // can not divide by zero orientation = (gy == 0) ? 0 : 90; } else { double div = (double)gy / gx; // handle angles of the 2nd and 4th quads if (div < 0) { orientation = 180 - System.Math.Atan(-div) * toAngle; } // handle angles of the 1st and 3rd quads else { orientation = System.Math.Atan(div) * toAngle; } // get closest angle from 0, 45, 90, 135 set if (orientation < 22.5) { orientation = 0; } else if (orientation < 67.5) { orientation = 45; } else if (orientation < 112.5) { orientation = 90; } else if (orientation < 157.5) { orientation = 135; } else { orientation = 0; } } // save orientation orients[p] = (byte)orientation; } src += srcOffset; } // STEP 3 - suppres non maximums byte *dst = (byte *)destination.ImageData.ToPointer( ); // allign pointer dst += dstStride * startY + startX; p = 0; // for each line for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, dst++, p++) { // get two adjacent pixels switch (orients[p]) { case 0: leftPixel = gradients[x - 1, y]; rightPixel = gradients[x + 1, y]; break; case 45: leftPixel = gradients[x - 1, y + 1]; rightPixel = gradients[x + 1, y - 1]; break; case 90: leftPixel = gradients[x, y + 1]; rightPixel = gradients[x, y - 1]; break; case 135: leftPixel = gradients[x + 1, y + 1]; rightPixel = gradients[x - 1, y - 1]; break; } // compare current pixels value with adjacent pixels if ((gradients[x, y] < leftPixel) || (gradients[x, y] < rightPixel)) { *dst = 0; } else { *dst = (byte)(gradients[x, y] / maxGradient * 255); } } dst += dstOffset; } // STEP 4 - hysteresis dst = (byte *)destination.ImageData.ToPointer( ); // allign pointer dst += dstStride * startY + startX; // for each line for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, dst++) { if (*dst < highThreshold) { if (*dst < lowThreshold) { // non edge *dst = 0; } else { // check 8 neighboring pixels if ((dst[-1] < highThreshold) && (dst[1] < highThreshold) && (dst[-dstStride - 1] < highThreshold) && (dst[-dstStride] < highThreshold) && (dst[-dstStride + 1] < highThreshold) && (dst[dstStride - 1] < highThreshold) && (dst[dstStride] < highThreshold) && (dst[dstStride + 1] < highThreshold)) { *dst = 0; } } } } dst += dstOffset; } // STEP 5 - draw black rectangle to remove those pixels, which were not processed // (this needs to be done for those cases, when filter is applied "in place" - // source image is modified instead of creating new copy) Drawing.Rectangle(destination, rect, Color.Black); // release blurred image blurredImage.Dispose( ); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="source">Source image data.</param> /// <param name="destination">Destination image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage source, UnmanagedImage destination, Rectangle rect ) { int kernelHalf = kernelSize / 2; InitFilter( ); if ( ( rect.Width <= kernelSize ) || ( rect.Height <= kernelSize ) ) { ProcessWithEdgeChecks( source, destination, rect ); } else { Rectangle safeArea = rect; safeArea.Inflate( -kernelHalf, -kernelHalf ); if ( ( Environment.ProcessorCount > 1 ) && ( enableParallelProcessing ) ) { ProcessWithoutChecksParallel( source, destination, safeArea ); } else { ProcessWithoutChecks( source, destination, safeArea ); } // top ProcessWithEdgeChecks( source, destination, new Rectangle( rect.Left, rect.Top, rect.Width, kernelHalf ) ); // bottom ProcessWithEdgeChecks( source, destination, new Rectangle( rect.Left, rect.Bottom - kernelHalf, rect.Width, kernelHalf ) ); // left ProcessWithEdgeChecks( source, destination, new Rectangle( rect.Left, rect.Top + kernelHalf, kernelHalf, rect.Height - kernelHalf * 2 ) ); // right ProcessWithEdgeChecks( source, destination, new Rectangle( rect.Right - kernelHalf, rect.Top + kernelHalf, kernelHalf, rect.Height - kernelHalf * 2 ) ); } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData) { // get source and destination images size var srcWidth = sourceData.Width; var srcHeight = sourceData.Height; var dstWidth = destinationData.Width; var dstHeight = destinationData.Height; var pixelSize = Image.GetPixelFormatSize(sourceData.PixelFormat) / 8; var srcStride = sourceData.Stride; var dstStride = destinationData.Stride; // find equations of four quadrilateral's edges ( f(x) = k*x + b ) double kTop, bTop; double kBottom, bBottom; double kLeft, bLeft; double kRight, bRight; // top edge if (this.sourceQuadrilateral[1].X == this.sourceQuadrilateral[0].X) { kTop = 0; bTop = this.sourceQuadrilateral[1].X; } else { kTop = (double)(this.sourceQuadrilateral[1].Y - this.sourceQuadrilateral[0].Y) / (this.sourceQuadrilateral[1].X - this.sourceQuadrilateral[0].X); bTop = (double)this.sourceQuadrilateral[0].Y - kTop * this.sourceQuadrilateral[0].X; } // bottom edge if (this.sourceQuadrilateral[2].X == this.sourceQuadrilateral[3].X) { kBottom = 0; bBottom = this.sourceQuadrilateral[2].X; } else { kBottom = (double)(this.sourceQuadrilateral[2].Y - this.sourceQuadrilateral[3].Y) / (this.sourceQuadrilateral[2].X - this.sourceQuadrilateral[3].X); bBottom = (double)this.sourceQuadrilateral[3].Y - kBottom * this.sourceQuadrilateral[3].X; } // left edge if (this.sourceQuadrilateral[3].X == this.sourceQuadrilateral[0].X) { kLeft = 0; bLeft = this.sourceQuadrilateral[3].X; } else { kLeft = (double)(this.sourceQuadrilateral[3].Y - this.sourceQuadrilateral[0].Y) / (this.sourceQuadrilateral[3].X - this.sourceQuadrilateral[0].X); bLeft = (double)this.sourceQuadrilateral[0].Y - kLeft * this.sourceQuadrilateral[0].X; } // right edge if (this.sourceQuadrilateral[2].X == this.sourceQuadrilateral[1].X) { kRight = 0; bRight = this.sourceQuadrilateral[2].X; } else { kRight = (double)(this.sourceQuadrilateral[2].Y - this.sourceQuadrilateral[1].Y) / (this.sourceQuadrilateral[2].X - this.sourceQuadrilateral[1].X); bRight = (double)this.sourceQuadrilateral[1].Y - kRight * this.sourceQuadrilateral[1].X; } // some precalculated values var leftFactor = (double)(this.sourceQuadrilateral[3].Y - this.sourceQuadrilateral[0].Y) / dstHeight; var rightFactor = (double)(this.sourceQuadrilateral[2].Y - this.sourceQuadrilateral[1].Y) / dstHeight; var srcY0 = this.sourceQuadrilateral[0].Y; var srcY1 = this.sourceQuadrilateral[1].Y; // do the job var baseSrc = (byte *)sourceData.ImageData.ToPointer( ); var baseDst = (byte *)destinationData.ImageData.ToPointer( ); // source width and height decreased by 1 var ymax = srcHeight - 1; var xmax = srcWidth - 1; // coordinates of source points double dx1, dy1, dx2, dy2; int sx1, sy1, sx2, sy2; // temporary pointers byte *p1, p2, p3, p4, p; // for each line for (var y = 0; y < dstHeight; y++) { var dst = baseDst + dstStride * y; // find corresponding Y on the left edge of the quadrilateral var yHorizLeft = leftFactor * y + srcY0; // find corresponding X on the left edge of the quadrilateral var xHorizLeft = (kLeft == 0) ? bLeft : (yHorizLeft - bLeft) / kLeft; // find corresponding Y on the right edge of the quadrilateral var yHorizRight = rightFactor * y + srcY1; // find corresponding X on the left edge of the quadrilateral var xHorizRight = (kRight == 0) ? bRight : (yHorizRight - bRight) / kRight; // find equation of the line joining points on the left and right edges double kHoriz, bHoriz; if (xHorizLeft == xHorizRight) { kHoriz = 0; bHoriz = xHorizRight; } else { kHoriz = (yHorizRight - yHorizLeft) / (xHorizRight - xHorizLeft); bHoriz = yHorizLeft - kHoriz * xHorizLeft; } var horizFactor = (xHorizRight - xHorizLeft) / dstWidth; if (!this.useInterpolation) { for (var x = 0; x < dstWidth; x++) { var xs = horizFactor * x + xHorizLeft; var ys = kHoriz * xs + bHoriz; if ((xs >= 0) && (ys >= 0) && (xs < srcWidth) && (ys < srcHeight)) { // get pointer to the pixel in the source image p = baseSrc + ((int)ys * srcStride + (int)xs * pixelSize); // copy pixel's values for (var i = 0; i < pixelSize; i++, dst++, p++) { *dst = *p; } } else { dst += pixelSize; } } } else { for (var x = 0; x < dstWidth; x++) { var xs = horizFactor * x + xHorizLeft; var ys = kHoriz * xs + bHoriz; if ((xs >= 0) && (ys >= 0) && (xs < srcWidth) && (ys < srcHeight)) { sx1 = (int)xs; sx2 = (sx1 == xmax) ? sx1 : sx1 + 1; dx1 = xs - sx1; dx2 = 1.0 - dx1; sy1 = (int)ys; sy2 = (sy1 == ymax) ? sy1 : sy1 + 1; dy1 = ys - sy1; dy2 = 1.0 - dy1; // get four points p1 = p2 = baseSrc + sy1 * srcStride; p1 += sx1 * pixelSize; p2 += sx2 * pixelSize; p3 = p4 = baseSrc + sy2 * srcStride; p3 += sx1 * pixelSize; p4 += sx2 * pixelSize; // interpolate using 4 points for (var i = 0; i < pixelSize; i++, dst++, p1++, p2++, p3++, p4++) { *dst = (byte)( dy2 * (dx2 * (*p1) + dx1 * (*p2)) + dy1 * (dx2 * (*p3) + dx1 * (*p4))); } } else { dst += pixelSize; } } } } }
// Perform image processing with checking pixels' coordinates to make sure those are in bounds private unsafe void ProcessWithEdgeChecks( UnmanagedImage source, UnmanagedImage destination, Rectangle rect ) { int width = source.Width; int height = source.Height; int startX = rect.Left; int startY = rect.Top; int stopX = rect.Right; int stopY = rect.Bottom; int pixelSize = System.Drawing.Image.GetPixelFormatSize( source.PixelFormat ) / 8; int kernelHalf = kernelSize / 2; int bytesInKernelRow = kernelSize * pixelSize; int srcStride = source.Stride; int dstStride = destination.Stride; int srcOffset = srcStride - rect.Width * pixelSize; int dstOffset = dstStride - rect.Width * pixelSize; // offset of the first kernel's pixel int srcKernelFistPixelOffset = kernelHalf * ( srcStride + pixelSize ); // offset to move to the next kernel's pixel after processing one kernel's row int srcKernelOffset = srcStride - bytesInKernelRow; int rx, ry; int tx, ty; byte* src = (byte*) source.ImageData.ToPointer( ); byte* dst = (byte*) destination.ImageData.ToPointer( ); // allign pointers to the first pixel to process src += startY * srcStride + startX * pixelSize; dst += startY * dstStride + startX * pixelSize; if ( pixelSize > 1 ) { // color images byte srcR, srcG, srcB; byte srcR0, srcG0, srcB0; byte* srcPixel; double sCoefR, sCoefG, sCoefB, sMembR, sMembG, sMembB, coefR, coefG, coefB; for ( int y = startY; y < stopY; y++ ) { for ( int x = startX; x < stopX; x++, src += pixelSize, dst += pixelSize ) { // lower right corner - to start processing from that point srcPixel = src + srcKernelFistPixelOffset; sCoefR = 0; sCoefG = 0; sCoefB = 0; sMembR = 0; sMembG = 0; sMembB = 0; srcR0 = src[RGB.R]; srcG0 = src[RGB.G]; srcB0 = src[RGB.B]; // move from lower right to upper left corner ty = kernelSize; while ( ty != 0 ) { ty--; ry = ty - kernelHalf; if ( ( ry + y >= height ) || ( ry + y < 0 ) ) // bounds check { srcPixel -= srcStride; continue; } tx = kernelSize; while ( tx != 0 ) { tx--; rx = tx - kernelHalf; if ( ( rx + x >= width ) || ( rx + x < 0 ) ) // bounds check { srcPixel -= pixelSize; continue; } srcR = srcPixel[RGB.R]; srcG = srcPixel[RGB.G]; srcB = srcPixel[RGB.B]; coefR = spatialFunc[tx, ty] * colorFunc[srcR, srcR0]; coefG = spatialFunc[tx, ty] * colorFunc[srcG, srcG0]; coefB = spatialFunc[tx, ty] * colorFunc[srcB, srcB0]; sCoefR += coefR; sCoefG += coefG; sCoefB += coefB; sMembR += coefR * srcR; sMembG += coefG * srcG; sMembB += coefB * srcB; srcPixel -= pixelSize; } srcPixel -= srcKernelOffset; } dst[RGB.R] = (byte) ( sMembR / sCoefR ); dst[RGB.G] = (byte) ( sMembG / sCoefG ); dst[RGB.B] = (byte) ( sMembB / sCoefB ); } src += srcOffset; dst += dstOffset; } } else { // 8bpp grayscale images byte srcC; byte srcC0; byte* srcPixel; double sCoefC, sMembC, coefC; for ( int y = startY; y < stopY; y++ ) { for ( int x = startX; x < stopX; x++, src++, dst++ ) { // lower right corner - to start processing from that point srcPixel = src + srcKernelFistPixelOffset; sCoefC = 0; sMembC = 0; srcC0 = *src; // move from lower right to upper left corner ty = kernelSize; while ( ty != 0 ) { ty--; ry = (int) ( ty - kernelHalf ); if ( ( ry + y >= height ) || ( ry + y < 0 ) ) // bounds check { srcPixel -= srcStride; continue; } tx = kernelSize; while ( tx != 0 ) { tx--; rx = (int) ( tx - kernelHalf ); if ( ( rx + x >= source.Width ) || ( rx + x < 0 ) ) // bounds check { srcPixel -= pixelSize; continue; } srcC = *( srcPixel ); coefC = spatialFunc[tx, ty] * colorFunc[srcC, srcC0]; sCoefC += coefC; sMembC += coefC * srcC; srcPixel -= pixelSize; } srcPixel -= srcKernelOffset; } *dst = (byte) ( sMembC / sCoefC ); } src += srcOffset; dst += dstOffset; } } }
/// <summary> /// Process new video frame. /// </summary> /// /// <param name="videoFrame">Video frame to process (detect motion in).</param> /// /// <remarks><para>Processes new frame from video source and detects motion in it.</para> /// /// <para>Check <see cref="MotionLevel"/> property to get information about amount of motion /// (changes) in the processed frame.</para> /// </remarks> /// public void ProcessFrame(UnmanagedImage videoFrame) { lock ( sync ) { // check background frame if (backgroundFrame == null) { lastTimeMeasurment = DateTime.Now; // save image dimension width = videoFrame.Width; height = videoFrame.Height; // alocate memory for previous and current frames backgroundFrame = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed); motionFrame = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed); frameSize = motionFrame.Stride * height; // temporary buffer if (suppressNoise) { tempFrame = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed); } // convert source frame to grayscale Accord.Vision.Tools.ConvertToGrayscale(videoFrame, backgroundFrame); return; } // check image dimension if ((videoFrame.Width != width) || (videoFrame.Height != height)) { return; } // convert current image to grayscale Accord.Vision.Tools.ConvertToGrayscale(videoFrame, motionFrame); unsafe { // pointers to background and current frames byte *backFrame; byte *currFrame; int diff; // update background frame if (millisecondsPerBackgroundUpdate == 0) { // update background frame using frame counter as a base if (++framesCounter == framesPerBackgroundUpdate) { framesCounter = 0; backFrame = (byte *)backgroundFrame.ImageData.ToPointer( ); currFrame = (byte *)motionFrame.ImageData.ToPointer( ); for (int i = 0; i < frameSize; i++, backFrame++, currFrame++) { diff = *currFrame - *backFrame; if (diff > 0) { (*backFrame)++; } else if (diff < 0) { (*backFrame)--; } } } } else { // update background frame using timer as a base // get current time and calculate difference DateTime currentTime = DateTime.Now; TimeSpan timeDff = currentTime - lastTimeMeasurment; // save current time as the last measurment lastTimeMeasurment = currentTime; int millisonds = (int)timeDff.TotalMilliseconds + millisecondsLeftUnprocessed; // save remainder so it could be taken into account in the future millisecondsLeftUnprocessed = millisonds % millisecondsPerBackgroundUpdate; // get amount for background update int updateAmount = (int)(millisonds / millisecondsPerBackgroundUpdate); backFrame = (byte *)backgroundFrame.ImageData.ToPointer( ); currFrame = (byte *)motionFrame.ImageData.ToPointer( ); for (int i = 0; i < frameSize; i++, backFrame++, currFrame++) { diff = *currFrame - *backFrame; if (diff > 0) { (*backFrame) += (byte)((diff < updateAmount) ? diff : updateAmount); } else if (diff < 0) { (*backFrame) += (byte)((-diff < updateAmount) ? diff : -updateAmount); } } } backFrame = (byte *)backgroundFrame.ImageData.ToPointer( ); currFrame = (byte *)motionFrame.ImageData.ToPointer( ); // 1 - get difference between frames // 2 - threshold the difference for (int i = 0; i < frameSize; i++, backFrame++, currFrame++) { // difference diff = (int)*currFrame - (int)*backFrame; // treshold *currFrame = ((diff >= differenceThreshold) || (diff <= differenceThresholdNeg)) ? (byte)255 : (byte)0; } if (suppressNoise) { // suppress noise and calculate motion amount Accord.SystemTools.CopyUnmanagedMemory(tempFrame.ImageData, motionFrame.ImageData, frameSize); erosionFilter.Apply(tempFrame, motionFrame); if (keepObjectEdges) { Accord.SystemTools.CopyUnmanagedMemory(tempFrame.ImageData, motionFrame.ImageData, frameSize); dilatationFilter.Apply(tempFrame, motionFrame); } } // calculate amount of motion pixels pixelsChanged = 0; byte *motion = (byte *)motionFrame.ImageData.ToPointer( ); for (int i = 0; i < frameSize; i++, motion++) { pixelsChanged += (*motion & 1); } } } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData) { // get width and height int width = sourceData.Width; int height = sourceData.Height; PixelFormat srcPixelFormat = sourceData.PixelFormat; if ( (srcPixelFormat == PixelFormat.Format24bppRgb) || (srcPixelFormat == PixelFormat.Format32bppRgb) || (srcPixelFormat == PixelFormat.Format32bppArgb)) { int pixelSize = (srcPixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; int srcOffset = sourceData.Stride - width * pixelSize; int dstOffset = destinationData.Stride - width; // do the job byte* src = (byte*)sourceData.ImageData.ToPointer(); byte* dst = (byte*)destinationData.ImageData.ToPointer(); // for each line for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, src += pixelSize, dst++) { *dst = (byte)(RedCoefficient * src[RGB.R] + GreenCoefficient * src[RGB.G] + BlueCoefficient * src[RGB.B]); } src += srcOffset; dst += dstOffset; } } else { int pixelSize = (srcPixelFormat == PixelFormat.Format48bppRgb) ? 3 : 4; byte* srcBase = (byte*)sourceData.ImageData.ToPointer(); byte* dstBase = (byte*)destinationData.ImageData.ToPointer(); int srcStride = sourceData.Stride; int dstStride = destinationData.Stride; // for each line for (int y = 0; y < height; y++) { ushort* src = (ushort*)(srcBase + y * srcStride); ushort* dst = (ushort*)(dstBase + y * dstStride); // for each pixel for (int x = 0; x < width; x++, src += pixelSize, dst++) { *dst = (ushort)(RedCoefficient * src[RGB.R] + GreenCoefficient * src[RGB.G] + BlueCoefficient * src[RGB.B]); } } } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="source">Source image data.</param> /// <param name="destination">Destination image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage source, UnmanagedImage destination, Rectangle rect) { int pixelSize = Image.GetPixelFormatSize(source.PixelFormat) / 8; // processing start and stop X,Y positions int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; int srcStride = source.Stride; int dstStride = destination.Stride; int srcOffset = srcStride - rect.Width * pixelSize; int dstOffset = dstStride - rect.Width * pixelSize; // loop and array indexes int i, j, t; // processing square's radius int radius = size >> 1; // number of elements int c; // array to hold pixel values (R, G, B) byte[] r = new byte[size * size]; byte[] g = new byte[size * size]; byte[] b = new byte[size * size]; byte *src = (byte *)source.ImageData.ToPointer( ); byte *dst = (byte *)destination.ImageData.ToPointer( ); byte *p; // allign pointers to the first pixel to process src += (startY * srcStride + startX * pixelSize); dst += (startY * dstStride + startX * pixelSize); // do the processing job if (destination.PixelFormat == PixelFormat.Format8bppIndexed) { // grayscale image // for each line for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, src++, dst++) { c = 0; // for each kernel row for (i = -radius; i <= radius; i++) { t = y + i; // skip row if (t < startY) { continue; } // break if (t >= stopY) { break; } // for each kernel column for (j = -radius; j <= radius; j++) { t = x + j; // skip column if (t < startX) { continue; } if (t < stopX) { g[c++] = src[i * srcStride + j]; } } } // sort elements Array.Sort(g, 0, c); // get the median *dst = g[c >> 1]; } src += srcOffset; dst += dstOffset; } } else { // RGB image // for each line for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, src += pixelSize, dst += pixelSize) { c = 0; // for each kernel row for (i = -radius; i <= radius; i++) { t = y + i; // skip row if (t < startY) { continue; } // break if (t >= stopY) { break; } // for each kernel column for (j = -radius; j <= radius; j++) { t = x + j; // skip column if (t < startX) { continue; } if (t < stopX) { p = &src[i * srcStride + j * pixelSize]; r[c] = p[RGB.R]; g[c] = p[RGB.G]; b[c] = p[RGB.B]; c++; } } } // sort elements Array.Sort(r, 0, c); Array.Sort(g, 0, c); Array.Sort(b, 0, c); // get the median t = c >> 1; dst[RGB.R] = r[t]; dst[RGB.G] = g[t]; dst[RGB.B] = b[t]; } src += srcOffset; dst += dstOffset; } } }
private unsafe void ApplyBGGR( UnmanagedImage sourceData, UnmanagedImage destinationData ) { int width = sourceData.Width; int height = sourceData.Height; int widthM1 = width - 1; int heightM1 = height - 1; int srcStride = sourceData.Stride; int dstStride = destinationData.Stride; int srcStrideP1 = srcStride + 1; int srcStrideM1 = srcStride - 1; int srcMStride = -srcStride; int srcMStrideP1 = srcMStride + 1; int srcMStrideM1 = srcMStride - 1; int srcOffset = srcStride - width; int dstOffset = dstStride - width * 3; // do the job byte * src = (byte*) sourceData.ImageData.ToPointer( ); byte * dst = (byte*) destinationData.ImageData.ToPointer( ); // --- process the first line // . . . // . B G // . G R dst[RGB.R] = src[srcStrideP1]; dst[RGB.G] = (byte) ( ( src[1] + src[srcStride] ) >> 1 ); dst[RGB.B] = *src; src++; dst += 3; for ( int x = 1; x < widthM1; x += 2 ) { // . . . // B G B // G R G dst[RGB.R] = src[srcStride]; dst[RGB.G] = (byte) ( ( *src + src[srcStrideM1] + src[srcStrideP1] ) / 3 ); dst[RGB.B] = (byte) ( ( src[-1] + src[1] ) >> 1 ); src++; dst += 3; // . . . // G B G // R G R dst[RGB.R] = (byte) ( ( src[srcStrideM1] + src[srcStrideP1] ) >> 1 ); dst[RGB.G] = (byte) ( ( src[-1] + src[srcStride] + src[1] ) / 3 ); dst[RGB.B] = *src; src++; dst += 3; } // . . . // B G . // G R . dst[RGB.R] = src[srcStride]; dst[RGB.G] = (byte) ( ( *src + src[srcStrideM1] ) >> 1 ); dst[RGB.B] = src[-1]; // allign to the next line src += srcOffset + 1; dst += dstOffset + 3; // --- process all lines except the first one and the last one for ( int y = 1; y < heightM1; y += 2 ) { // . B G // . G R // . B G dst[RGB.R] = src[1]; dst[RGB.G] = (byte) ( ( src[srcMStrideP1] + src[srcStrideP1] + *src ) / 3 ); dst[RGB.B] = (byte) ( ( src[srcMStride] + src[srcStride] ) >> 1 ); dst += dstStride; src += srcStride; // ( y+1 pixel ) // . G R // . B G // . G R dst[RGB.R] = (byte) ( ( src[srcMStrideP1] + src[srcStrideP1] ) >> 1 ); dst[RGB.G] = (byte) ( ( src[1] + src[srcMStride] + src[srcStride] ) / 3 ); dst[RGB.B] = *src; dst -= dstStride; src -= srcStride; src++; dst += 3; for ( int x = 1; x < widthM1; x += 2 ) { // B G B // G R G // B G B dst[RGB.R] = *src; dst[RGB.G] = (byte) ( ( src[srcMStride] + src[srcStride] + src[-1] + src[1] ) >> 2 ); dst[RGB.B] = (byte) ( ( src[srcMStrideM1] + src[srcMStrideP1] + src[srcStrideM1] + src[srcStrideP1] ) >> 2 ); // ( y+1 pixel ) // G R G // B G B // G R G dst += dstStride; src += srcStride; dst[RGB.R] = (byte) ( ( src[srcMStride] + src[srcStride] ) >> 1 ); dst[RGB.G] = (byte) ( ( *src + src[srcMStrideM1] + src[srcMStrideP1] + src[srcStrideM1] + src[srcStrideP1] ) / 5 ); dst[RGB.B] = (byte) ( ( src[-1] + src[1] ) >> 1 ); // ( y+1 x+1 pixel ) // R G R // G B G // R G R dst += 3; src++; dst[RGB.R] = (byte) ( ( src[srcMStrideM1] + src[srcMStrideP1] + src[srcStrideM1] + src[srcStrideP1] ) >> 2 ); dst[RGB.G] = (byte) ( ( src[srcMStride] + src[srcStride] + src[-1] + src[1] ) >> 2 ); dst[RGB.B] = *src; // ( x+1 pixel ) // G B G // R G R // G B G dst -= dstStride; src -= srcStride; dst[RGB.R] = (byte) ( ( src[-1] + src[1] ) >> 1 ); dst[RGB.G] = (byte) ( ( src[srcMStrideM1] + src[srcMStrideP1] + src[srcStrideM1] + src[srcStrideP1] + *src ) / 5 ); dst[RGB.B] = (byte) ( ( src[srcMStride] + src[srcStride] ) >> 1 ); dst += 3; src++; } // B G . // G R . // B G . dst[RGB.R] = *src; dst[RGB.G] = (byte) ( ( src[srcMStride] + src[srcStride] + src[-1] ) / 3 ); dst[RGB.B] = (byte) ( ( src[srcMStrideM1] + src[srcStrideM1] ) >> 1 ); src += srcStride; dst += dstStride; // ( y+1 pixel ) // G R . // B G . // G R . dst[RGB.R] = (byte) ( ( src[srcMStride] + src[srcStride] ) >> 1 ); dst[RGB.G] = (byte) ( ( src[srcMStrideM1] + src[srcStrideM1] + *src ) / 3 ); dst[RGB.B] = src[-1]; // align to the next line src += srcOffset + 1; dst += dstOffset + 3; } // --- process the first line // . B G // . G R // . . . dst[RGB.R] = src[1]; dst[RGB.G] = (byte) ( ( src[srcMStrideP1] + *src ) >> 1 ); dst[RGB.B] = src[srcMStride]; src++; dst += 3; for ( int x = 1; x < widthM1; x += 2 ) { // B G B // G R G // . . . dst[RGB.R] = *src; dst[RGB.G] = (byte) ( ( src[-1] + src[1] + src[srcMStride] ) / 3 ); dst[RGB.B] = (byte) ( ( src[srcMStrideM1] + src[srcMStrideP1] ) >> 1 ); src++; dst += 3; // G B G // R G R // . . . dst[RGB.R] = (byte) ( ( src[-1] + src[1] ) >> 1 ); dst[RGB.G] = (byte) ( ( *src + src[srcMStrideM1] + src[srcMStrideP1] ) / 3 ); dst[RGB.B] = src[srcMStride]; src++; dst += 3; } // B G . // G R . // . . . dst[RGB.R] = *src; dst[RGB.G] = (byte) ( ( src[srcMStride] + src[-1] ) >> 1 ); dst[RGB.B] = src[srcMStrideM1]; }
protected abstract void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData);
/// <summary> /// Apply filter to an image (not implemented). /// </summary> /// /// <param name="sourceImage">Source image to be processed.</param> /// <param name="destinationImage">Destination image to store filter's result.</param> /// /// <exception cref="NotImplementedException">The method is not implemented.</exception> /// public void Apply( UnmanagedImage sourceImage, UnmanagedImage destinationImage ) { throw new NotImplementedException( "The method is not implemented filter." ); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="source">Source image data.</param> /// <param name="destination">Destination image data.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage source, UnmanagedImage destination) { int pixelSize = Image.GetPixelFormatSize(source.PixelFormat) / 8; // processing start and stop X,Y positions int width = source.Width; int height = source.Height; int srcStride = source.Stride; int dstStride = destination.Stride; int dstOffset = dstStride - width * pixelSize; // coordinates of source points double ox, oy, dx1, dy1, dx2, dy2; int ox1, oy1, ox2, oy2; // width and height decreased by 1 int ymax = height - 1; int xmax = width - 1; byte *src = (byte *)source.ImageData.ToPointer( ); byte *dst = (byte *)destination.ImageData.ToPointer( ); byte *p1, p2, p3, p4; double xFactor = 2 * Math.PI * xWavesCount / width; double yFactor = 2 * Math.PI * yWavesCount / height; // for each line for (int y = 0; y < height; y++) { double yPart = Math.Sin(yFactor * y) * yWavesAmplitude; // for each pixel for (int x = 0; x < width; x++) { ox = x + yPart; oy = y + Math.Cos(xFactor * x) * xWavesAmplitude; // check if the source pixel is inside of image if ((ox >= 0) && (oy >= 0) && (ox < width) && (oy < height)) { // perform bilinear interpolation oy1 = (int)oy; oy2 = (oy1 == ymax) ? oy1 : oy1 + 1; dy1 = oy - (double)oy1; dy2 = 1.0 - dy1; ox1 = (int)ox; ox2 = (ox1 == xmax) ? ox1 : ox1 + 1; dx1 = ox - (double)ox1; dx2 = 1.0 - dx1; p1 = src + oy1 * srcStride + ox1 * pixelSize; p2 = src + oy1 * srcStride + ox2 * pixelSize; p3 = src + oy2 * srcStride + ox1 * pixelSize; p4 = src + oy2 * srcStride + ox2 * pixelSize; for (int i = 0; i < pixelSize; i++, dst++, p1++, p2++, p3++, p4++) { *dst = (byte)( dy2 * (dx2 * (*p1) + dx1 * (*p2)) + dy1 * (dx2 * (*p3) + dx1 * (*p4))); } } else { for (int i = 0; i < pixelSize; i++, dst++) { *dst = 0; } } } dst += dstOffset; } }
/// <summary> /// Calculate binarization threshold for the given image. /// </summary> /// /// <param name="image">Image to calculate binarization threshold for.</param> /// <param name="rect">Rectangle to calculate binarization threshold for.</param> /// /// <returns>Returns binarization threshold.</returns> /// /// <remarks><para>The method is used to calculate binarization threshold only. The threshold /// later may be applied to the image using <see cref="Threshold"/> image processing filter.</para></remarks> /// /// <exception cref="UnsupportedImageFormatException">Source pixel format is not supported by the routine. It should be /// 8 bpp grayscale (indexed) image.</exception> /// public int CalculateThreshold( UnmanagedImage image, Rectangle rect ) { if ( image.PixelFormat != PixelFormat.Format8bppIndexed ) throw new UnsupportedImageFormatException( "Source pixel format is not supported by the routine." ); int calculatedThreshold = 0; // get start and stop X-Y coordinates int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; int offset = image.Stride - rect.Width; // histogram array int[] integerHistogram = new int[256]; double[] histogram = new double[256]; unsafe { // collect histogram first byte* ptr = (byte*) image.ImageData.ToPointer( ); // allign pointer to the first pixel to process ptr += ( startY * image.Stride + startX ); // for each line for ( int y = startY; y < stopY; y++ ) { // for each pixel for ( int x = startX; x < stopX; x++, ptr++ ) { integerHistogram[*ptr]++; } ptr += offset; } // pixels count in the processing region int pixelCount = ( stopX - startX ) * ( stopY - startY ); // mean value of the processing region double imageMean = 0; for ( int i = 0; i < 256; i++ ) { histogram[i] = (double) integerHistogram[i] / pixelCount; imageMean += histogram[i] * i; } double max = double.MinValue; // initial class probabilities double class1Probability = 0; double class2Probability = 1; // initial class 1 mean value double class1MeanInit = 0; // check all thresholds for ( int t = 0; ( t < 256 ) && ( class2Probability > 0 ); t++ ) { // calculate class means for the given threshold double class1Mean = class1MeanInit; double class2Mean = ( imageMean - ( class1Mean * class1Probability ) ) / class2Probability; // calculate between class variance double betweenClassVariance = ( class1Probability ) * ( 1.0 - class1Probability ) * Math.Pow( class1Mean - class2Mean, 2 ); // check if we found new threshold candidate if ( betweenClassVariance > max ) { max = betweenClassVariance; calculatedThreshold = t; } // update initial probabilities and mean value class1MeanInit *= class1Probability; class1Probability += histogram[t]; class2Probability -= histogram[t]; class1MeanInit += (double) t * (double) histogram[t]; if ( class1Probability != 0 ) { class1MeanInit /= class1Probability; } } } return calculatedThreshold; }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// /// <exception cref="InvalidImagePropertiesException">Texture size does not match image size.</exception> /// <exception cref="ApplicationException">Filters should not change image dimension.</exception> /// protected override unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData) { // get source image dimension var width = sourceData.Width; var height = sourceData.Height; // if generator was specified, then generate a texture // otherwise use provided texture if (textureGenerator != null) { texture = textureGenerator.Generate(width, height); } else { // check existing texture if ((texture.GetLength(0) != height) || (texture.GetLength(1) != width)) { // sorry, but source image must have the same dimension as texture throw new InvalidImagePropertiesException("Texture size does not match image size."); } } // apply first filter var filteredImage1 = filter1.Apply(sourceData); // check size of the result image if ((width != filteredImage1.Width) || (height != filteredImage1.Height)) { filteredImage1.Dispose(); throw new ApplicationException("Filters should not change image dimension."); } // convert 1st image to RGB if required if (filteredImage1.PixelFormat == PixelFormat.Format8bppIndexed) { var coloringFilter = new GrayscaleToRGB(); var temp = coloringFilter.Apply(filteredImage1); filteredImage1.Dispose(); filteredImage1 = temp; } UnmanagedImage filteredImage2 = null; // apply second filter, if it was specified if (filter2 != null) { filteredImage2 = filter2.Apply(sourceData); // check size of the result image if ((width != filteredImage2.Width) || (height != filteredImage2.Height)) { filteredImage1.Dispose(); filteredImage2.Dispose(); // we are not handling such situations yet throw new ApplicationException("Filters should not change image dimension."); } // convert 2nd image to RGB if required if (filteredImage2.PixelFormat == PixelFormat.Format8bppIndexed) { var coloringFilter = new GrayscaleToRGB(); var temp = coloringFilter.Apply(filteredImage2); filteredImage2.Dispose(); filteredImage2 = temp; } } // use source image as a second image, if second filter is not set if (filteredImage2 == null) { filteredImage2 = sourceData; } // do the job unsafe { var dst = (byte *)destinationData.ImageData.ToPointer(); var src1 = (byte *)filteredImage1.ImageData.ToPointer(); var src2 = (byte *)filteredImage2.ImageData.ToPointer(); var dstOffset = destinationData.Stride - 3 * width; var src1Offset = filteredImage1.Stride - 3 * width; var src2Offset = filteredImage2.Stride - 3 * width; if (preserveLevel != 0.0) { // for each line for (var y = 0; y < height; y++) { // for each pixel for (var x = 0; x < width; x++) { double t1 = texture[y, x]; var t2 = 1 - t1; for (var i = 0; i < 3; i++, src1++, src2++, dst++) { *dst = (byte)System.Math.Min(255.0f, filterLevel * (t1 * (*src1) + t2 * (*src2)) + preserveLevel * (*src2)); } } src1 += src1Offset; src2 += src2Offset; dst += dstOffset; } } else { // for each line for (var y = 0; y < height; y++) { // for each pixel for (var x = 0; x < width; x++) { double t1 = texture[y, x]; var t2 = 1 - t1; for (var i = 0; i < 3; i++, src1++, src2++, dst++) { *dst = (byte)System.Math.Min(255.0f, t1 * *src1 + t2 * *src2); } } src1 += src1Offset; src2 += src2Offset; dst += dstOffset; } } } // dispose temp images filteredImage1.Dispose(); if (filteredImage2 != sourceData) { filteredImage2.Dispose(); } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image, Rectangle rect ) { int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; if ( image.PixelFormat == PixelFormat.Format8bppIndexed ) { int offset = image.Stride - rect.Width; // do the job byte* ptr = (byte*) image.ImageData.ToPointer( ); // allign pointer to the first pixel to process ptr += ( startY * image.Stride + startX ); // for each line for ( int y = startY; y < stopY; y++ ) { // for each pixel for ( int x = startX; x < stopX; x++, ptr++ ) { *ptr = (byte) ( ( *ptr >= threshold ) ? 255 : 0 ); } ptr += offset; } } else { byte* basePtr = (byte*) image.ImageData.ToPointer( ) + startX * 2; int stride = image.Stride; // for each line for ( int y = startY; y < stopY; y++ ) { ushort* ptr = (ushort*) ( basePtr + stride * y ); // for each pixel for ( int x = startX; x < stopX; x++, ptr++ ) { *ptr = (ushort) ( ( *ptr >= threshold ) ? 65535 : 0 ); } } } }
private unsafe void ProcessImage(UnmanagedImage image, Rectangle rect, byte *mask, int maskLineSize) { UnmanagedImage unmanagedImage = baseFilter.Apply(image); if (image.Width != unmanagedImage.Width || image.Height != unmanagedImage.Height) { throw new ArgumentException("Base filter must not change image size."); } int num = System.Drawing.Image.GetPixelFormatSize(image.PixelFormat) / 8; int top = rect.Top; int num2 = top + rect.Height; int left = rect.Left; int num3 = left + rect.Width; int stride = image.Stride; int stride2 = unmanagedImage.Stride; int num4 = maskLineSize - rect.Width; mask += maskLineSize * top + left; if (num <= 4 && num != 2) { byte *ptr = (byte *)image.ImageData.ToPointer() + (long)stride * (long)top + (long)num * (long)left; int num5 = stride - rect.Width * num; byte *ptr2 = (byte *)unmanagedImage.ImageData.ToPointer() + (long)stride2 * (long)top + (long)num * (long)left; int num6 = stride2 - rect.Width * num; switch (num) { case 2: break; case 1: { for (int j = top; j < num2; j++) { int num8 = left; while (num8 < num3) { if (*mask != 0) { *ptr = *ptr2; } num8++; ptr++; ptr2++; mask++; } ptr += num5; ptr2 += num6; mask += num4; } break; } case 3: { for (int k = top; k < num2; k++) { int num9 = left; while (num9 < num3) { if (*mask != 0) { ptr[2] = ptr2[2]; ptr[1] = ptr2[1]; *ptr = *ptr2; } num9++; ptr += 3; ptr2 += 3; mask++; } ptr += num5; ptr2 += num6; mask += num4; } break; } case 4: { for (int i = top; i < num2; i++) { int num7 = left; while (num7 < num3) { if (*mask != 0) { ptr[2] = ptr2[2]; ptr[1] = ptr2[1]; *ptr = *ptr2; ptr[3] = ptr2[3]; } num7++; ptr += 4; ptr2 += 4; mask++; } ptr += num5; ptr2 += num6; mask += num4; } break; } } return; } byte *ptr3 = (byte *)image.ImageData.ToPointer() + (long)stride * (long)top + (long)num * (long)left; byte *ptr4 = (byte *)unmanagedImage.ImageData.ToPointer() + (long)stride2 * (long)top + (long)num * (long)left; switch (num) { case 2: { for (int m = top; m < num2; m++) { ushort *ptr7 = (ushort *)ptr3; ushort *ptr8 = (ushort *)ptr4; int num11 = left; while (num11 < num3) { if (*mask != 0) { *ptr7 = *ptr8; } num11++; ptr7++; ptr8++; mask++; } ptr3 += stride; ptr4 += stride2; mask += num4; } break; } case 6: { for (int n = top; n < num2; n++) { ushort *ptr9 = (ushort *)ptr3; ushort *ptr10 = (ushort *)ptr4; int num12 = left; while (num12 < num3) { if (*mask != 0) { ptr9[2] = ptr10[2]; ptr9[1] = ptr10[1]; *ptr9 = *ptr10; } num12++; ptr9 += 3; ptr10 += 3; mask++; } ptr3 += stride; ptr4 += stride2; mask += num4; } break; } case 8: { for (int l = top; l < num2; l++) { ushort *ptr5 = (ushort *)ptr3; ushort *ptr6 = (ushort *)ptr4; int num10 = left; while (num10 < num3) { if (*mask != 0) { ptr5[2] = ptr6[2]; ptr5[1] = ptr6[1]; *ptr5 = *ptr6; ptr5[3] = ptr6[3]; } num10++; ptr5 += 4; ptr6 += 4; mask++; } ptr3 += stride; ptr4 += stride2; mask += num4; } break; } } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage sourceData, UnmanagedImage destinationData, Rectangle rect ) { PixelFormat pixelFormat = sourceData.PixelFormat; // processing start and stop X,Y positions int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; // structuring element's radius int r = size >> 1; // flag to indicate if at least one pixel for the given structuring element was found bool foundSomething; if ( ( pixelFormat == PixelFormat.Format8bppIndexed ) || ( pixelFormat == PixelFormat.Format24bppRgb ) ) { int pixelSize = ( pixelFormat == PixelFormat.Format8bppIndexed ) ? 1 : 3; int dstStride = destinationData.Stride; int srcStride = sourceData.Stride; // base pointers byte* baseSrc = (byte*) sourceData.ImageData.ToPointer( ); byte* baseDst = (byte*) destinationData.ImageData.ToPointer( ); // allign pointers by X baseSrc += ( startX * pixelSize ); baseDst += ( startX * pixelSize ); if ( pixelFormat == PixelFormat.Format8bppIndexed ) { // grayscale image // compute each line for ( int y = startY; y < stopY; y++ ) { byte* src = baseSrc + y * srcStride; byte* dst = baseDst + y * dstStride; byte min, v; // loop and array indexes int t, ir, jr, i, j; // for each pixel for ( int x = startX; x < stopX; x++, src++, dst++ ) { min = 255; foundSomething = false; // for each structuring element's row for ( i = 0; i < size; i++ ) { ir = i - r; t = y + ir; // skip row if ( t < startY ) continue; // break if ( t >= stopY ) break; // for each structuring element's column for ( j = 0; j < size; j++ ) { jr = j - r; t = x + jr; // skip column if ( t < startX ) continue; if ( t < stopX ) { if ( se[i, j] == 1 ) { foundSomething = true; // get new MIN value v = src[ir * srcStride + jr]; if ( v < min ) min = v; } } } } // result pixel *dst = ( foundSomething ) ? min : *src; } } } else { // 24 bpp color image // compute each line for ( int y = startY; y < stopY; y++ ) { byte* src = baseSrc + y * srcStride; byte* dst = baseDst + y * dstStride; byte minR, minG, minB, v; byte* p; // loop and array indexes int t, ir, jr, i, j; // for each pixel for ( int x = startX; x < stopX; x++, src += 3, dst += 3 ) { minR = minG = minB = 255; foundSomething = false; // for each structuring element's row for ( i = 0; i < size; i++ ) { ir = i - r; t = y + ir; // skip row if ( t < startY ) continue; // break if ( t >= stopY ) break; // for each structuring element's column for ( j = 0; j < size; j++ ) { jr = j - r; t = x + jr; // skip column if ( t < startX ) continue; if ( t < stopX ) { if ( se[i, j] == 1 ) { foundSomething = true; // get new MIN values p = &src[ir * srcStride + jr * 3]; // red v = p[RGB.R]; if ( v < minR ) minR = v; // green v = p[RGB.G]; if ( v < minG ) minG = v; // blue v = p[RGB.B]; if ( v < minB ) minB = v; } } } } // result pixel if ( foundSomething ) { dst[RGB.R] = minR; dst[RGB.G] = minG; dst[RGB.B] = minB; } else { dst[RGB.R] = src[RGB.R]; dst[RGB.G] = src[RGB.G]; dst[RGB.B] = src[RGB.B]; } } } } } else { int pixelSize = ( pixelFormat == PixelFormat.Format16bppGrayScale ) ? 1 : 3; int dstStride = destinationData.Stride / 2; int srcStride = sourceData.Stride / 2; // base pointers ushort* baseSrc = (ushort*) sourceData.ImageData.ToPointer( ); ushort* baseDst = (ushort*) destinationData.ImageData.ToPointer( ); // allign pointers by X baseSrc += ( startX * pixelSize ); baseDst += ( startX * pixelSize ); if ( pixelFormat == PixelFormat.Format16bppGrayScale ) { // 16 bpp grayscale image // compute each line for ( int y = startY; y < stopY; y++ ) { ushort* src = baseSrc + y * srcStride; ushort* dst = baseDst + y * dstStride; ushort min, v; // loop and array indexes int t, ir, jr, i, j; // for each pixel for ( int x = startX; x < stopX; x++, src++, dst++ ) { min = 65535; foundSomething = false; // for each structuring element's row for ( i = 0; i < size; i++ ) { ir = i - r; t = y + ir; // skip row if ( t < startY ) continue; // break if ( t >= stopY ) break; // for each structuring element's column for ( j = 0; j < size; j++ ) { jr = j - r; t = x + jr; // skip column if ( t < startX ) continue; if ( t < stopX ) { if ( se[i, j] == 1 ) { foundSomething = true; // get new MIN value v = src[ir * srcStride + jr]; if ( v < min ) min = v; } } } } // result pixel *dst = ( foundSomething ) ? min : *src; } } } else { // 48 bpp color image // compute each line for ( int y = startY; y < stopY; y++ ) { ushort* src = baseSrc + y * srcStride; ushort* dst = baseDst + y * dstStride; ushort minR, minG, minB, v; ushort* p; // loop and array indexes int t, ir, jr, i, j; // for each pixel for ( int x = startX; x < stopX; x++, src += 3, dst += 3 ) { minR = minG = minB = 65535; foundSomething = false; // for each structuring element's row for ( i = 0; i < size; i++ ) { ir = i - r; t = y + ir; // skip row if ( t < startY ) continue; // break if ( t >= stopY ) break; // for each structuring element's column for ( j = 0; j < size; j++ ) { jr = j - r; t = x + jr; // skip column if ( t < startX ) continue; if ( t < stopX ) { if ( se[i, j] == 1 ) { foundSomething = true; // get new MIN values p = &src[ir * srcStride + jr * 3]; // red v = p[RGB.R]; if ( v < minR ) minR = v; // green v = p[RGB.G]; if ( v < minG ) minG = v; // blue v = p[RGB.B]; if ( v < minB ) minB = v; } } } } // result pixel if ( foundSomething ) { dst[RGB.R] = minR; dst[RGB.G] = minG; dst[RGB.B] = minB; } else { dst[RGB.R] = src[RGB.R]; dst[RGB.G] = src[RGB.G]; dst[RGB.B] = src[RGB.B]; } } } } } }
public MaskedFilter(IFilter baseFiler, UnmanagedImage unmanagedMaskImage) { BaseFilter = baseFiler; UnmanagedMaskImage = unmanagedMaskImage; }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected abstract unsafe void ProcessFilter(UnmanagedImage image, Rectangle rect);
/// <summary> /// Apply filter to an image in unmanaged memory. /// </summary> /// /// <param name="sourceImage">Source image in unmanaged memory to apply filter to.</param> /// <param name="destinationImage">Destination image in unmanaged memory to put result into.</param> /// /// <remarks><para>The method keeps the source image unchanged and puts result of image processing /// into destination image.</para> /// /// <para><note>The destination image must have the same width and height as source image. Also /// destination image must have pixel format, which is expected by particular filter (see /// <see cref="FormatTranslations"/> property for information about pixel format conversions).</note></para> /// </remarks> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// <exception cref="InvalidImagePropertiesException">Incorrect destination pixel format.</exception> /// <exception cref="InvalidImagePropertiesException">Destination image has wrong width and/or height.</exception> /// public void Apply(UnmanagedImage sourceImage, UnmanagedImage destinationImage) { dilation.Apply(sourceImage, destinationImage); errosion.ApplyInPlace(destinationImage); }