Bilateral filter implementation - edge preserving smoothing and noise reduction that uses chromatic and spatial factors.

Bilateral filter conducts "selective" Gaussian smoothing of areas of same color (domains) which removes noise and contrast artifacts while preserving sharp edges.

Two major parameters SpatialFactor and ColorFactor define the result of the filter. By changing these parameters you may achieve either only noise reduction with little change to the image or get nice looking effect to the entire image.

Although the filter can use parallel processing large KernelSize values (greater than 25) on high resolution images may decrease speed of processing. Also on high resolution images small KernelSize values (less than 9) may not provide noticeable results.

More details on the algorithm can be found by following this link.

The filter accepts 8 bpp grayscale images and 24/32 bpp color images for processing.

Sample usage:

// create filter BilateralSmoothing filter = new BilateralSmoothing( ); filter.KernelSize = 7; filter.SpatialFactor = 10; filter.ColorFactor = 60; filter.ColorPower = 0.5; // apply the filter filter.ApplyInPlace( image );

Initial image:

Result image:

Inheritance: BaseUsingCopyPartialFilter
Example #1
1
        // ==========================================================================================================
        // Functions compatible with lists:
        // ==========================================================================================================
        // Note, that each function needs to keep the image in RGB, otherwise drawing fill fail
        // =========================================================
        private void NoiseReduction_Funct(ref Bitmap frame, int par_int, double par_d, int par_R, int par_G, int par_B)
        {
            frame = Grayscale.CommonAlgorithms.RMY.Apply(frame);	// Make gray
            switch (par_int)
            {
                case 1:
                    BilateralSmoothing Bil_filter = new BilateralSmoothing();
                    Bil_filter.KernelSize =7;
                    Bil_filter.SpatialFactor = 10;
                    Bil_filter.ColorFactor = 30;
                    Bil_filter.ColorPower = 0.5;
                    Bil_filter.ApplyInPlace(frame);
                    break;

                case 2:
                    Median M_filter = new Median();
                    M_filter.ApplyInPlace(frame);
                    break;

                case 3:
                    Mean Meanfilter = new Mean();
                    // apply the MirrFilter
                    Meanfilter.ApplyInPlace(frame);
                    break;

                default:
                    Median Median_filter = new Median();
                    Median_filter.ApplyInPlace(frame);
                    break;
            }
            GrayscaleToRGB RGBfilter = new GrayscaleToRGB();	// back to color format
            frame = RGBfilter.Apply(frame);
        }
 private Bitmap smoothing(Bitmap image)
 {
     // create filter
     BilateralSmoothing filter = new BilateralSmoothing();
     filter.KernelSize = 7;
     filter.SpatialFactor = 10;
     filter.ColorFactor = 60;
     filter.ColorPower = 0.5;
     // apply the filter
     filter.ApplyInPlace(image);
     return image;
 }
        public static Bitmap Bilateral(Bitmap image, Rectangle region, int kernelSize, int spatialFactor, int colorFactor)
        {
            BilateralSmoothing filter = new BilateralSmoothing
            {
                KernelSize = kernelSize,
                SpatialFactor = spatialFactor,
                ColorFactor = colorFactor,
                EnableParallelProcessing = true
            };

            Bitmap bitmap = new Bitmap(image);
            filter.ApplyInPlace(bitmap, region);
            return bitmap;
        }
 public void EdgePreservingSmooth()
 {
     BilateralSmoothing filter = new BilateralSmoothing();
     filter.KernelSize = 7;
     filter.SpatialFactor = 10;
     filter.ColorFactor = 60;
     filter.ColorPower = 0.5;
     filter.ApplyInPlace(Image);
 }
        public Bitmap Detect(Bitmap bitmap)
        {
            Bitmap grayscaleBitmap = Grayscale.CommonAlgorithms.BT709.Apply(bitmap);

            IFilter smoothingFilter = null;
            switch (_smoothMode)
            {
                case "None": smoothingFilter = null; break;
                case "Mean": smoothingFilter = new Mean(); break;
                case "Median": smoothingFilter = new Median(); break;
                case "Conservative": smoothingFilter = new ConservativeSmoothing(); break;
                case "Adaptive": smoothingFilter = new AdaptiveSmoothing(); break;
                case "Bilateral": smoothingFilter = new BilateralSmoothing(); break;
            }
            Bitmap smoothBitmap = smoothingFilter != null ? smoothingFilter.Apply(grayscaleBitmap) : grayscaleBitmap;

            IFilter edgeFilter = null;
            switch (_edgeMode)
            {
                case "Homogenity": edgeFilter = new HomogenityEdgeDetector(); break;
                case "Difference": edgeFilter = new DifferenceEdgeDetector(); break;
                case "Sobel": edgeFilter = new SobelEdgeDetector(); break;
                case "Canny": edgeFilter = new CannyEdgeDetector(); break;
            }
            Bitmap edgeBitmap = edgeFilter != null ? edgeFilter.Apply(smoothBitmap) : smoothBitmap;

            IFilter threshholdFilter = new Threshold(_threshold);
            Bitmap thresholdBitmap = _threshold == 0 ? edgeBitmap : threshholdFilter.Apply(edgeBitmap);

            BlobCounter blobCounter = new BlobCounter();
            blobCounter.FilterBlobs = true;
            blobCounter.MinHeight = _minHeight;
            blobCounter.MinWidth = _minWidth;
            blobCounter.ProcessImage(thresholdBitmap);
            Blob[] blobs = blobCounter.GetObjectsInformation();

            Bitmap outputBitmap = new Bitmap(thresholdBitmap.Width, thresholdBitmap.Height, PixelFormat.Format24bppRgb);
            Graphics bitmapGraphics = Graphics.FromImage(outputBitmap);
            Bitmap inputBitmap = null;
            switch (_drawMode)
            {
                case "Original": inputBitmap = bitmap; break;
                case "Grayscale": inputBitmap = grayscaleBitmap; break;
                case "Smooth": inputBitmap = smoothBitmap; break;
                case "Edge": inputBitmap = edgeBitmap; break;
                case "Threshold": inputBitmap = thresholdBitmap; break;
            }
            if (inputBitmap != null)
                bitmapGraphics.DrawImage(inputBitmap, 0, 0);

            Pen nonConvexPen = new Pen(Color.Red, 2);
            Pen nonRectPen = new Pen(Color.Orange, 2);
            Pen cardPen = new Pen(Color.Blue, 2);

            SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
            List<IntPoint> cardPositions = new List<IntPoint>();

            for (int i = 0; i < blobs.Length; i++)
            {
                List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
                List<IntPoint> corners;

                if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
                {
                    PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);

                    if ((subType == PolygonSubType.Parallelogram || subType == PolygonSubType.Rectangle) && corners.Count == 4)
                    {
                        // Check if its sideways, if so rearrange the corners so it's vertical.
                        RearrangeCorners(corners);

                        // Prevent detecting the same card twice by comparing distance against other detected cards.
                        bool sameCard = false;
                        foreach (IntPoint point in cardPositions)
                        {
                            if (corners[0].DistanceTo(point) < _minDistance)
                            {
                                sameCard = true;
                                break;
                            }
                        }
                        if (sameCard)
                            continue;

                        // Hack to prevent it from detecting smaller sections of the card instead of the whole card.
                        if (GetArea(corners) < _minArea)
                            continue;

                        cardPositions.Add(corners[0]);

                        bitmapGraphics.DrawPolygon(cardPen, ToPointsArray(corners));
                    }
                    else
                    {
                        foreach (IntPoint point in edgePoints.Take(300))
                        {
                            bitmapGraphics.DrawEllipse(nonRectPen, point.X, point.Y, 1, 1);
                        }
                    }
                }
                else
                {
                    foreach (IntPoint point in edgePoints.Take(300))
                    {
                        bitmapGraphics.DrawEllipse(nonConvexPen, point.X, point.Y, 1, 1);
                    }
                }
            }

            bitmapGraphics.Dispose();
            nonConvexPen.Dispose();
            nonRectPen.Dispose();
            cardPen.Dispose();

            return outputBitmap;
        }