(Question) Smooth histogram coloring failure

  • 3 Replies
  • 148 Views

0 Members and 1 Guest are viewing this topic.

Offline Smolt

  • *
  • Fractal Freshman
  • *
  • Posts: 2
« on: July 28, 2019, 11:03:01 PM »
Hello,

I am trying to implement a simple fractal render in Rust.
I decided to use the histogram coloring as described in the Wikipedia page of the Mandelbrot Set. https://en.wikipedia.org/wiki/Mandelbrot_set#Histogram_coloring.

It works well but of course I get banding.
My issue is that I don't understand how to implement smooth coloring using this method.
To me with this method we intrinsically lose information by using the histogram, and I don't see how to obtain this bigger dynamic we require for smoothing.

My question(s) would be : is this feasible (I guess so), and are there any useful resources on this subject ?

Thank you very much,
Smolt

Here is my implementation :

Code: [Select]
fn histogram <T> (img: Image, frac: Fractale<T>)
    where T: Fn(num_complex::Complex<f32>, num_complex::Complex<f32>
                ) -> num_complex::Complex<f32>
    {
    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf: image::RgbImage = image::ImageBuffer::new(img.imgx, img.imgy);

    /* 1st pass
     * Calculate iteration counts for each pixel
     */
    let scalex = (frac.rangex.1 - frac.rangex.0) / img.imgx as f32;
    let scaley = (frac.rangey.1 - frac.rangey.0) / img.imgy as f32;
    let mut itcount = vec![vec![0u32; img.imgy as usize]; img.imgx as usize];

    for x in 0..img.imgx {
        for y in 0.. img.imgy {
            let cx = x as f32 * scalex + frac.rangex.0;
            let cy = y as f32 * scaley + frac.rangey.0;
            let c = num_complex::Complex::new(cx, cy);
            let mut z = num_complex::Complex::new(0.0, 0.0);

            let mut i = 0;
            while i < frac.max_iter-1 && z.norm() <= 2.0 {
                z = (frac.equation)(z,c);
                i += 1;
            }
            itcount[x as usize][y as usize] = i;
        }
    }
    /* 2nd pass
     * Create an array histo of size n = max iteration count
     * Iterate over itcount and build the histogram
     */
    let mut histo = vec![0u32; frac.max_iter as usize];

    for x in 0..img.imgx {
        for y in 0.. img.imgy {
            let i = itcount[x as usize][y as usize];
            histo[i as usize] += 1;
        }
    }
    /* 3rd pass
     * Count the number of iterations */
    let mut total: u32 = 0;
    for i in 0..frac.max_iter {
        total += histo[i as usize];
    }
    /* 4th pass
     * All values in itcounts are indexed each itcount i is normalized
     */
    let mut hue = vec![vec![0f32; img.imgy as usize]; img.imgx as usize];
    for x in 0..img.imgx {
        for y in 0..img.imgy {
            let iteration = itcount[x as usize][y as usize];
            for i in 0..iteration {
                hue[x as usize][y as usize] += histo[i as usize] as f32 / total as f32;
            }
        }
    }
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        /* Print image */
        let image::Rgb(data) = *pixel;
        *pixel = image::Rgb(palette(hue[x as usize][y as usize], 1.0, 1.0, 1.0));
    }
    imgbuf.save("fractal.png").unwrap();
}

Offline marcm200

  • *
  • Fractal Frogurt
  • ******
  • Posts: 434
« Reply #1 on: July 29, 2019, 09:02:42 AM »
I implemented this also a while ago, maybe this helps:

https://fractalforums.org/programming/11/is-this-what-a-histogram-coloring-of-the-mandelbrot-set-should-look-like/2896/msg15279#msg15279

The key here being: You're not doing a histogram on the iteration count itself but on
Code: [Select]
ceil(10*(iterationcount + smooth iteration part as calculated as if no histogram were involved))
That way you can use one digit after the decimal point as well and get the smooth part in.
.

Offline Smolt

  • *
  • Fractal Freshman
  • *
  • Posts: 2
« Reply #2 on: July 30, 2019, 01:15:40 AM »
Thank you, that's an interesting approach.. I'll look into it and report back !

Offline Duncan C

  • *
  • Fractal Freshman
  • *
  • Posts: 7
« Reply #3 on: August 23, 2019, 03:47:41 AM »
Histogram-based coloring lets you assign colors to regions that occupy roughly the same number of pixels. This avoids the problem that the outer bands tend to be big, and as you get close to the set, you might only have a handful of pixels at a given iteration value. By using a histogram of the plot to allocate the amount of color change between iteration counts, you avoid images where the colors change too much in too small a space in high-iteration-count areas and getting visually cluttered images.

Histogram-based coloring won't eliminate banding however. A band of pixels with the same iteration count is a band with the same iteration count. If those bands are big, they will be visible. In very high iteration count areas deep in the set you will start to get smooth-looking colors using integer iteration counts and histogram-based colors, just because there are so few pixels with any given iteration count.

To get smooth transitions and no banding, you need to use fractional iteration counts. If memory serves that is documented in "The Science of Fractal Images."

What I do with my program FractalWorks is to use histogram-based coloring to assign colors for each iteration value, and then optionally compute a fractional iteration count value, and use the fraction to interpolate the color value between histogram-based color values for each iteration count. The result is colors that smoothly transition from one color to the next and colors that change roughly the same amount per pixel distance.

I'm attaching an image that uses histogram colors but integer iteration values, and then a second version of the same plot but using fractional iteration values to smooth the histogram-based colors.

Note that the color scheme is the same in both images, but in the smoothed version, the color transitions are "feathered" between iteration values.

Also note that even in the image with integer iteration values, the areas near the Mandelbrot have smooth color transitions anyway. That's because the iteration count changes from pixel to pixel.

I'm also attaching an image of a mini-brot from seahorse valley, plotted with a 2-color blue to white histogram color table and integer iteration counts. If you look closely you can still see color bands in the outer blue areas, but in the lighter colored areas closer to the set you can't see any banding at all.


xx
"Time Span"

Started by cricke49 on Fractal Image Gallery

0 Replies
312 Views
Last post August 02, 2018, 07:05:21 AM
by cricke49
xx
How to implement Smooth Histogram Rendering?

Started by Iluso on Programming

6 Replies
251 Views
Last post January 18, 2019, 10:31:30 PM
by FractalDave
question
Is this what a histogram coloring of the Mandelbrot set should look like?

Started by jdb2 on Programming

17 Replies
516 Views
Last post August 24, 2019, 01:35:13 AM
by Duncan C
clip
Smooth 1D coloring

Started by Spyke on Image Threads

17 Replies
444 Views
Last post April 20, 2019, 12:49:06 AM
by Spyke
xx
Smooth 1D coloring

Started by Spyke on Fractal Mathematics And New Theories

9 Replies
500 Views
Last post June 11, 2019, 06:09:48 PM
by Spyke