Example #1
0
        /// <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();
        }
        /// <summary>
        /// Processes the filter on the passed <paramref name="srcData"/>
        /// resulting into <paramref name="dstData"/>.
        /// </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)
        {
            // processing start and stop X,Y positions
            const int startX = 1;
            const int startY = 1;
            int       stopX  = startX + srcData.Width - 2;
            int       stopY  = startY + srcData.Height - 2;

            const double toAngle = 180.0 / Math.PI;
            float        leftPixel = 0, rightPixel = 0;

            #region canny
            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);

            Rectangle  rect     = new Rectangle(0, 0, blur.Width, blur.Height);
            BitmapData blurData =
                blur.LockBits(rect, ImageLockMode.ReadWrite, blur.PixelFormat);

            int dstStride = dstData.Stride;
            int srcStride = blurData.Stride;

            int dstOffset = dstStride - rect.Width + 2;
            int srcOffset = srcStride - rect.Width + 2;

            // orientation array
            byte[,] orients = new byte[dstData.Width, dstData.Height];
            // gradients array
            //int[,] gxArray = new int[dstData.Width, dstData.Height];
            //int[,] gyArray = new int[dstData.Width, dstData.Height];
            float[,] gradients = new float[dstData.Width, dstData.Height];
            float maxGradient = float.NegativeInfinity;

            // do the job
            byte *src = (byte *)blurData.Scan0.ToPointer();
            // allign pointer
            src += srcStride * startY + startX;

            // 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 *)dstData.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
                    {
                        *dst = (byte)(gradients[x, y] / maxGradient * 255);
                    }
                }
                dst += dstOffset;
            }

            // STEP 4 - hysteresis
            dst = (byte *)dstData.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;
                            }
                        }
                    }

                    #region color orientations
                    if (value == 255 && orientColored)
                    {
                        byte tmp = orients[x, y];
                        switch (tmp)
                        {
                        case 0:
                            value = 255;
                            break;

                        case 45:
                            value = 45;
                            break;

                        case 90:
                            value = 90;
                            break;

                        case 135:
                            value = 135;
                            break;
                        }
                    }
                    #endregion color orientations
                    *dst = value;
                }
                dst += dstOffset;
            }
            #endregion canny

            //#region Adapt line thickness
            //if (Diameter > 1)
            //{
            //    dst = (byte*)dstData.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++)
            //        {
            //            if (*dst != 0)
            //            {
            //                Drawing8Bpp.DrawThickPoint(
            //                    dstData, *dst, new Point( x, y), Diameter);
            //            }
            //        }
            //        dst += dstOffset;
            //    }
            //}
            //#endregion Adapt line thickness

            blur.UnlockBits(blurData);
            blur.Dispose();
        }