/// <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; int rc = (int)(0x10000 * RedCoefficient); int gc = (int)(0x10000 * GreenCoefficient); int bc = (int)(0x10000 * BlueCoefficient); // make sure sum of coefficients equals to 0x10000 while (rc + gc + bc < 0x10000) { bc++; } // 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++) { destinationData.CheckBounds(dst); *dst = (byte)((rc * src[RGB.R] + gc * src[RGB.G] + bc * src[RGB.B]) >> 16); } 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]); } } } }
public List <IntPoint> FindContour(UnmanagedImage image) { CheckPixelFormat(image.PixelFormat); int width = image.Width; int height = image.Height; int stride = image.Stride; List <IntPoint> contour = new List <IntPoint>(); unsafe { byte src = (byte)image.ImageData.ToPointer(); int start = 0; IntPoint prevPosition = new IntPoint(); // 1. Find the lowest point in the image // The lowest point is searched first by lowest X, then lowest Y, to use // the same ordering of AForge.NET's GrahamConvexHull. Unfortunately, this // means we have to search our image by inspecting columns rather than rows. bool found = false; int col = (int)src; for (int x = 0; x < width && !found; x++, col++) { int row = col; for (int y = 0; y < height && !found; y++, row += stride) { image.CheckBounds(row); if (row > Threshold) { start = row; prevPosition = new IntPoint(x, y); contour.Add(prevPosition); found = true; // 현재 시작점 후보가 threshold 이상이면 컨투어 시작점으로 고른다. } } } if (contour.Count == 0) { // Empty image return(contour); } // 2. Beginning on the first point, starting from left // neighbor and going into counter-clockwise direction, // find a neighbor pixel which is black. int[] windowOffset = { +1, // 0: Right -stride + 1, // 1: Top-Right -stride, // 2: Top -stride - 1, // 3: Top-Left -1, // 4: Left +stride - 1, // 5: Bottom-Left +stride, // 6: Bottom +stride + 1, // 7: Bottom-Right }; int direction = 4; // 4: Left int current = start; int previous = 0; #region find do // Search until we find a dead end (or the starting pixel) { found = false; // Search in the neighborhood window for (int i = 0; i < windowOffset.Length; i++) { // Find the next candidate neighbor point IntPoint next = prevPosition + positionOffset[direction]; // Check if it is inside the blob area if (next.X < 0 || next.X >= width || next.Y < 0 || next.Y >= height) { // It isn't. Change direction and continue. direction = (direction + 1) % windowOffset.Length; continue; } // It is inside. Then find the next candidate neighbor pixel int neighbor = unchecked (current + windowOffset[direction]); CheckBounds(image, neighbor); // Make sure we are in the image // Check if it is a colored pixel if (neighbor <= Threshold) { // It isn't. Change direction and continue. direction = (direction + 1) % windowOffset.Length; continue; } // Check if it is a previously found pixel if (neighbor == previous || neighbor == start) { // We found a dead end. found = false; break; } // If we reached until here, we have // found a neighboring black pixel. found = true; break; } if (found) { // Navigate to neighbor pixel previous = current; current = unchecked (current + windowOffset[direction]); // Add to the contour prevPosition += positionOffset[direction]; contour.Add(prevPosition); // Continue counter-clockwise search // from the most promising direction direction = nextDirection[direction]; } } while (found); #endregion } return(contour); }