Maybe you could try something like this. First, this code creates a hash containing an entry for each unique color in an image. Then the colors are sorted by Luma value and broken into 17 groups of colors with similar Luma. Then, an average RGB triple is calculated for each group, weighted by the pixel count of each color in the input image. This produces a coarse gradient of 17 colors with ascending luma. A linear interpolation is then performed between these reference colors to get a gradient of 256 colors.

I was lazy about two things in this code: The grouping of 17 colors is proportional to unique color count, rather than evenly distributing Luma differences. Also, a polynomial interpolation might be better than a linear one, although the linear result looks ok to me.

Here is the gradient generated from the jpeg you linked:

https://image.ibb.co/gMY085/grid.png

I hope this helps.

use strict; use GD; # GetReferenceColors returns a coarse gradient of colors typical # at several Luma levels sub GetReferenceColors { my ($img, $count) = @_; # build %indexes hash where the keys are the indexes of each uniqu +e color # and the values are the number of pixels counted for the color in +dex my ($width, $height) = $img->getBounds; my %indexes; for my $y (0..$height-1) { for my $x (0..$width-1) { my $idx = $img->getPixel($x, $y); ++$indexes{$idx}; } } # Build @colors array with one entry for each color # contains the color's RGB triple, its Luma (Y value) and pixel co +unt my @colors; for my $idx (keys %indexes) { my @rgb = $img->rgb($idx); my $y = $rgb[0]*0.299 + $rgb[1]*0.587 + $rgb[2]*0.114; my $pixel_count = $indexes{$idx}; push(@colors, { rgb => [@rgb], y => $y, count => $pixel_count +}); } # Sort @colors by ascending Luma value @colors = sort { $a->{y} <=> $b->{y} } @colors; # split @colors into $count groups, which overlap by one entry # calculate each group's average RGB value, weighted by pixel coun +t # add each group's average [r,g,b] triple to @ref_colors. my @ref_colors; my $step = @colors / $count; for my $i (0..$count - 1) { my $start = int($i * $step); my $end = int(($i + 1) * $step); my $wsum = 0; my @csum = (0, 0, 0); for my $j ($start .. $end) { my $color = $colors[$j]; my $weight = $color->{count}; $wsum += $weight; for my $ci (0..2) { $csum[$ci] += $color->{rgb}->[$ci] * $weight; } } for my $ci (0..2) { $csum[$ci] = int($csum[$ci] / $wsum + 0.5); } push(@ref_colors, \@csum ); } return \@ref_colors; } # InterpolateColors interpolates between two [r,g,b] triples # by a weight factor between 0 and 1 sub InterpolateColors { my ($ca, $cb, $pb) = @_; my @rgb; for my $i (0..2) { push(@rgb, int($ca->[$i] * (1 - $pb) + $cb->[$i] * $pb + 0.5)) +; } return \@rgb; } # Builds an interpolated set of colors based on an image's # most commonly occurring colors at a series of brightness levels sub InterpolatePalette { my ($img, $count) = @_; # Build a 256-entry @gradient by linearly interpolating between # a set of 17 colors returned by GetReferenceColors my @gradient; my $ref_colors = GetReferenceColors($img, 17); for my $i (1..@$ref_colors-1) { my $c0 = $ref_colors->[$i-1]; my $c1 = $ref_colors->[$i]; for my $j (0..15) { my $p = $j/16; push(@gradient, InterpolateColors($c0, $c1, $p)); } } return \@gradient; } # Read the input image from a file my $file = $ARGV[0] // '07_AH_Esfahan Gold 65-ab.jpg'; my $img = GD::Image->newFromJpeg($file); # Calculate an interpolated gradient from the image's dominant colors my $r = InterpolatePalette($img); # Create a new image for displaying the color gradient on a grid my $len = 20; my $width = 16*$len+1; my $grid = new GD::Image($width, $width, 1); # Draw the grid my $background = $grid->colorResolve(0, 0, 0); $grid->filledRectangle(0, 0, $width, $width, $background); my $loc = 0; for my $color (@$r) { my $x = ($loc & 15) * $len; my $y = ($loc >> 4) * $len; ++$loc; my $color = $grid->colorResolve(@$color); $grid->filledRectangle($x+1, $y+1, $x+$len-1, $y+$len-1, $color); } # Save the result open(my $fh, '>:raw', 'grid.png') or die $!; print $fh $grid->png;

In reply to Re: A data selection problem(in3D). by coicles
in thread A data selection problem(in3D). by BrowserUk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.