Simple posterization of an image.

The class implements simple posterization of an image by splitting each color plane into adjacent areas of the specified size. After the process is done, each color plane will contain maximum of 256/PosterizationInterval levels. For example, if grayscale image is posterized with posterization interval equal to 64, then result image will contain maximum of 4 tones. If color image is posterized with the same posterization interval, then it will contain maximum of 43=64 colors. See FillingType property to get information about the way how to control color used to fill posterization areas.

Posterization is a process in photograph development which converts normal photographs into an image consisting of distinct, but flat, areas of different tones or colors.

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

Sample usage:

// create filter SimplePosterization filter = new SimplePosterization( ); // process image filter.ApplyInPlace( sourceImage );

Initial image:

Result image:

Inheritance: BaseInPlacePartialFilter
        private Bitmap preProcessImage(Bitmap image, Grayscale gScale, SobelEdgeDetector sEgDetector, SimplePosterization posterization)
        {
            Bitmap temp = image;
            temp = gScale.Apply(temp);
            posterization.ApplyInPlace(temp);

            return temp;
        }
Exemple #2
0
        protected void ApplyFiltersTo(ref Bitmap b, ImageState s)
        {
            //TODO: if the image is unrotated, use a rectangle to limit the effect to the desired area

            string str = null;
            int i = 0;

            //If radiusunits is specified, use that code path.
            double units = s.settings.Get<double>("a.radiusunits",1000);

            i = GetRadius(s, "blur", "a.blur", units);
            if (i > 0) new GaussianBlur(1.4, i).ApplyInPlace(b);

            i = GetRadius(s, "sharpen", "a.sharpen", units);
            if (i > 0) new GaussianSharpen(1.4, Math.Min(11,i)).ApplyInPlace(b);

            i = GetRadius(s, "a.oilpainting", null, units);
            if (i > 0) new OilPainting(i).ApplyInPlace(b);

            if ("true".Equals(s.settings["a.removenoise"], StringComparison.OrdinalIgnoreCase)) {
                new ConservativeSmoothing(3).ApplyInPlace(b);
            } else {
                i = GetRadius(s, "a.removenoise", null, units);
                if (i > 0) new ConservativeSmoothing(i).ApplyInPlace(b);
            }

            //Sobel only supports 8bpp grayscale images.
            //true/false
            if ("true".Equals(s.settings["a.sobel"], StringComparison.OrdinalIgnoreCase)){
                Bitmap old = b;
                try{
                    b = Grayscale.CommonAlgorithms.Y.Apply(b);
                }finally{
                    if (old != s.sourceBitmap) old.Dispose();
                }

                new SobelEdgeDetector().ApplyInPlace(b);

                str = s.settings["a.threshold"]; //radius
                if (!string.IsNullOrEmpty(str) && int.TryParse(str, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out i) && i > 0)
                 new Threshold(i).ApplyInPlace(b);

            }
            //Canny Edge Detector only supports 8bpp grayscale images.
            //true/false
            if ("true".Equals(s.settings["a.canny"], StringComparison.OrdinalIgnoreCase)) {
                Bitmap old = b;
                try {
                    b = Grayscale.CommonAlgorithms.Y.Apply(b);
                } finally {
                    if (old != s.sourceBitmap) old.Dispose();
                }
                new CannyEdgeDetector().ApplyInPlace(b);

            }

            //true/false - duplicate with SimpleFilters?
            if ("true".Equals(s.settings["a.sepia"], StringComparison.OrdinalIgnoreCase))
                new Sepia().ApplyInPlace(b);

            //true/false
            if ("true".Equals(s.settings["a.equalize"], StringComparison.OrdinalIgnoreCase))
                new HistogramEqualization().ApplyInPlace(b);

            ///White balance adjustment
            var whiteAlg = s.settings.Get<HistogramThresholdAlgorithm>("a.balancewhite");
            var whiteVal = s.settings.Get<double>("a.balancethreshold");

            if (whiteAlg != null || whiteVal != null) {
                var bal = new AutoWhiteBalance(whiteAlg ?? HistogramThresholdAlgorithm.Area);
                if (whiteVal != null) bal.LowThreshold = bal.HighThreshold = whiteVal.Value / 100;
                bal.ApplyInPlace(b);
            }

            str = s.settings["a.posterize"]; //number of colors to merge
            if (!string.IsNullOrEmpty(str) && int.TryParse(str, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out i) && i > 0) {
                SimplePosterization sp = new SimplePosterization();
                if (i < 1) i = 1;
                if (i > 255) i = 255;
                sp.PosterizationInterval =(byte)i;
                sp.ApplyInPlace(b);
            }

            //Pixellate doesn't support 32-bit images, only 24-bit
            //str = s.settings["a.pixelate"]; //number of colors to merge
            //if (!string.IsNullOrEmpty(str) && int.TryParse(str, out i)){
            //     if (i < 2) i = 2;
            //    if (i > 32) i = 32;
            //    new Pixellate(i).ApplyInPlace(s.destBitmap);
            //}

            float contrast = s.settings.Get<float>("a.contrast", 0);
            float brightness = s.settings.Get<float>("a.brightness", 0);
            float saturation = s.settings.Get<float>("a.saturation", 0);

            if (contrast != 0 || brightness != 0 || saturation != 0){
                HSLLinear adjust = new HSLLinear();
                AdjustContrastBrightnessSaturation(adjust, contrast, brightness, saturation, "true".Equals(s.settings["a.truncate"]));
                adjust.ApplyInPlace(b);
            }
            //TODO - add grayscale?

            //For adding fax-like thresholding, use BradleyLocalThresholding

            //For trimming solid-color whitespace, use Shrink
        }
        /// <summary>
        /// Returns true if the average energy of the image is below the given threshold
        /// </summary>
        /// <param name="image"></param>
        /// <param name="threshold"></param>
        /// <returns></returns>
        private bool IsBlank(byte[] image, byte threshold)
        {
            var ms = new MemoryStream(image);

            using (var b = new Bitmap(ms))
            {
                using (var gray = Grayscale.CommonAlgorithms.BT709.Apply(b))
                {
                    new SobelEdgeDetector().ApplyInPlace(gray);
                    var p = new SimplePosterization(SimplePosterization.PosterizationFillingType.Average);
                    p.PosterizationInterval = 128;
                    p.ApplyInPlace(gray);
                    return gray.GetPixel(0, 0).R < threshold;
                }

            }
        }
 public ImagePreprocessor()
 {
     gScale = new Grayscale(0.2125, 0.7154, 0.0721);
     sobelDetector = new SobelEdgeDetector();
     posterization = new SimplePosterization();
 }