/// <summary> /// Extracts the color segments of the original bitmap as pixel-connected regions. /// </summary> protected override unsafe void Process(BitmapData srcData, BitmapData dstData) { int pixelSize = Image.GetPixelFormatSize(srcData.PixelFormat) / 8; int w = srcData.Width; int h = srcData.Height; int s = srcData.Stride; int offset = s - w * pixelSize; //if (Diameter != 0) { byte *src = (byte *)srcData.Scan0.ToPointer(); // for each line for (int y = 0; y < h; y++) { // for each pixel for (int x = 0; x < w; x++, src += pixelSize) { if (pixelSize == 1 && (*src != 0)) { Drawing8Bpp.DrawThickPoint( dstData, *src, new Point(x, y), Diameter); } else if (src[RGBA.R] != 0 || src[RGBA.G] != 0 || src[RGBA.B] != 0) // color { Color col = Color.FromArgb( src[RGBA.R], src[RGBA.G], src[RGBA.B]); Drawing24Or32Bpp.DrawThickPoint( dstData, col, new Point(x, y), Diameter); } } src += offset; } } }
/// <summary> /// Draws the <see cref="BorderRectangle"/> into the passed /// <paramref name="data"/>. /// </summary> /// <param name="data">Source bitmap data to draw on.</param> /// <param name="lineRectStrength">The pixel strength of the contour's /// rectangle border.</param> public void DrawBorderRect(BitmapData data, int lineRectStrength) { Drawing8Bpp.DrawLine( data, Index, new Point(LeftX, UpY), new Point(LeftX, BottomY), lineRectStrength); Drawing8Bpp.DrawLine( data, Index, new Point(LeftX, BottomY), new Point(RightX, BottomY), lineRectStrength); Drawing8Bpp.DrawLine( data, Index, new Point(RightX, BottomY), new Point(RightX, UpY), lineRectStrength); Drawing8Bpp.DrawLine( data, Index, new Point(RightX, UpY), new Point(LeftX, UpY), lineRectStrength); }
/// <summary> /// Processes the filter on the passed <paramref name="srcData"/>. /// </summary> /// <param name="srcData">The source bitmap data.</param> /// <param name="dstData">The destination bitmap data.</param> protected override unsafe void Process(BitmapData srcData, BitmapData dstData) { Bitmap blur = BitmapConverter.BitmapDataToBitmap(srcData); // do grayscaling the image if (blur.PixelFormat != PixelFormat.Format8bppIndexed) { // STEP 0 - do grayscaling the image blur = TPGrayscale.CommonAlgorithms.BT709.Apply(blur); } // STEP 1 - blur image blur = gaussianFilter.Apply(blur); rect = new Rectangle(0, 0, blur.Width, blur.Height); BitmapData blurData = blur.LockBits(rect, ImageLockMode.ReadWrite, blur.PixelFormat); data = dstData; // 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; const double toAngle = 180.0 / Math.PI; float leftPixel = 0, rightPixel = 0; dstStride = data.Stride; int srcStride = blurData.Stride; int dstOffset = dstStride - rect.Width + 2; int srcOffset = srcStride - rect.Width + 2; // orientation array orients = new byte[data.Width, data.Height]; // gradients array //int[,] gxArray = new int[dstData.Width, dstData.Height]; //int[,] gyArray = new int[dstData.Width, dstData.Height]; float[,] gradients = new float[data.Width, data.Height]; float maxGradient = float.NegativeInfinity; // do the job byte *src = (byte *)blurData.Scan0.ToPointer(); // allign pointer src += srcStride * startY + startX; #region canny // STEP 2 - calculate magnitude and edge orientation // for each line for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, src++) { // pixel's value and gradients int gx = src[-srcStride + 1] + src[srcStride + 1] - src[-srcStride - 1] - src[srcStride - 1] + 2 * (src[1] - src[-1]); int gy = src[-srcStride - 1] + src[-srcStride + 1] - src[srcStride - 1] - src[srcStride + 1] + 2 * (src[-srcStride] - src[srcStride]); //gxArray[x, y] = Math.Abs(gx); //gyArray[x, y] = Math.Abs(gy); // get gradient value gradients[x, y] = (float)Math.Sqrt(gx * gx + gy * gy); if (gradients[x, y] > maxGradient) { maxGradient = gradients[x, y]; } // --- get orientation double 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 - Math.Atan(-div) * toAngle; } // handle angles of the 1st and 3rd quads else { orientation = 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[x, y] = (byte)orientation; } src += srcOffset; } // STEP 3 - suppress non maximums byte *dst = (byte *)data.Scan0.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++) { // get two adjacent pixels switch (orients[x, y]) { 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 { byte b = (byte)(gradients[x, y] / maxGradient * 255); * dst = b; } } dst += dstOffset; } // STEP 4 - hysteresis dst = (byte *)data.Scan0.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++) { byte value = 255; if (*dst < HighThreshold) { if (*dst < LowThreshold) { // non edge value = 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)) { value = 0; } } } *dst = value; } dst += dstOffset; } #endregion canny #region contour tracing // STEP 5 - contour tracing dstOffset = dstStride - rect.Width; dst = (byte *)data.Scan0.ToPointer(); // allign pointer // dst += dstStride * (startY + 2) + startX + 2; byte index = 1, id = 1; Contours = new List <Contour>(rect.Width * rect.Height); Contour c; // for each line for (int y = 0; y < rect.Height; y++) { // for each pixel for (int x = 0; x < rect.Width; x++, dst++) { // is an edge pixel? if (*dst == 255) // && index != 255) { c = new Contour(id, index); Point coord1 = new Point(x, y); c.UpdateBorderRect(coord1); while (GetAndDrawCountour(ref coord1, c)) { } coord1 = new Point(x, y); while (GetAndDrawCountour(ref coord1, c)) { } GetBorderLine(c); Contours.Add(c); index++; id++; } if (index == 255) { index = 1; } } dst += dstOffset; } // sorts upwards by the contour's border rectangle size Contours.Sort(); if (OnlyBorderLine) { Drawing8Bpp.ReplacePixels(data, 0, 0); foreach (Contour t in Contours) { t.DrawBorderLine(data); } } if (DrawBorderRectangle) { foreach (var contour in Contours) { contour.DrawBorderRect(data, LineRectStrength); } } #endregion contour tracing blur.UnlockBits(blurData); blur.Dispose(); }