Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Re: Cannot Set Image Pixel to a Random Colour using GD

by Anonymous Monk
on Dec 24, 2022 at 16:33 UTC ( [id://11149059]=note: print w/replies, xml ) Need Help??


in reply to Cannot Set Image Pixel to a Random Colour using GD

I assume your intent is to open and save "true colour" RGB, 8 bits per channel images, as opposed to paletted images. "Learning curve" or not, you'll get nowhere before you understand the difference, so as not to try to use methods designed for paletted images on "true colour" images.

trueColor is class method; GD documentation is clear about that. However, it also says that, by default, "true colour" GD object is created if PNG already was "true colour". It's not what I observe. Instead of calling class method before opening anything, I'd suggest providing an explicit flag to constructor, as in example below.

Using Imager just to desaturate triplets of values, while at the same time using GD to manipulate an image is so wrong on all sides, that I simply chose to use another distribution for the purpose. The Convert::Color and Colouring::In are what searching the CPAN reveals (the latter even provides the desaturate method); but you can continue to use Imager, of course. If it's all just for exercise, it may (or may not) be beneficial to write RGB to HSV (and back) conversions yourself. If it's not just an exercise, I'd strongly advise not to get and set pixels one by one in high level language.

Note that getPixel returns large integer in case of "true color", which is just packed BGR triplet. The "convert" is ImageMagick's executable supposed to be in the PATH. + Actually calling reverse twice isn't required to only mess with saturation alone.

use strict; use warnings; use feature 'say'; use open IO => ':raw'; use GD; use Convert::Color; sub desaturate { local $" = ','; my @HSV = Convert::Color-> new( "rgb8:@_" )-> as_hsv-> hsv; $HSV[ 1 ] *= 0.7; return Convert::Color-> new( "hsv:@HSV" )-> as_rgb8-> rgb8 } my $gd = GD::Image-> newFromPngData( scalar qx/convert rose: png:-/, 1 + ); for my $y ( 0 .. $gd-> height - 1 ) { for my $x ( 0 .. $gd-> width - 1 ) { my $packed_rgb = $gd-> getPixel( $x, $y ); my @RGB = reverse unpack 'C3', pack 'L', $packed_rgb; $packed_rgb = unpack 'L', pack 'C3x', reverse desaturate( @RGB + ); $gd-> setPixel( $x, $y, $packed_rgb ) } } open my $fh, '>', 'desaturated_rose.png' or die; binmode $fh; print $fh $gd-> png; close $fh;

Replies are listed 'Best First'.
Re^2: Cannot Set Image Pixel to a Random Colour using GD
by ozboomer (Friar) on Dec 25, 2022 at 10:35 UTC

    As I said, I'm admittedly pretty vague on GD... so I was just having a go with the tools I know about.

    Convert::Color was something I'd not come across in my explorations... so that's been added to the toolkit. I'm pretty new at manipulating graphics (beyond simply getting size information and calling ffmpeg and similar CLI tools from within my code)... so I'm feeling my way a lot..

    Further down the track, I'm trying to see if I can automatically 'tidy-up' some 100s (or 1000s) of smaller images so they all 'look' the same.. without going to the hassle of trying to learn about 'computer vision', OpenCV and such unless I really have to... particularly when I can conceive of a simpler way, even if it's slower or 'inelegant'(!).

    I've modified the suggested code a bit so it works on my system (and I can understand it a bit more easily):-

    use strict; use warnings; # unused ... use feature 'say'; # unnecessary? ... use open IO => ':raw'; use GD; use Convert::Color; # Handy.. Didn't know of this module my $saturation_factor = 0.9; # Will ultimately be coming from elsewhe +re # ---- sub desaturate { local $" = ','; my @HSV = Convert::Color-> new( "rgb8:@_" )-> as_hsv-> hsv; $HSV[ 1 ] *= $saturation_factor; return Convert::Color-> new( "hsv:@HSV" )-> as_rgb8-> rgb8 } # ---- # this is as clear as mud in a beer bottle to me... # my $gd = GD::Image-> newFromPngData( scalar qx/convert rose: png:-/, + 1 ); my $gd = GD::Image->newFromPng("ruddy.png", 1) || die("cant on loading + file\n"); # 1 = truecolour # my ($max_X, $max_Y) = $gd->getBounds(); # My version my $max_X = $gd->width; # TMTOWTDI my $max_Y = $gd->height; #for my $y ( 0 .. $gd->height - 1 ) { # Construct causes 'unknown + method' errors ()... # for my $x ( 0 .. $gd->width - 1 ) { for my $y ( 0 .. $max_Y - 1 ) { for my $x ( 0 .. $max_X - 1 ) { my $packed_rgb = $gd-> getPixel( $x, $y ); my @RGB = reverse unpack 'C3', pack 'L', $packed_rgb; $packed_rgb = unpack 'L', pack 'C3x', reverse desaturate( @RGB + ); $gd-> setPixel( $x, $y, $packed_rgb ) } } open my $fh, '>', 'new.png' or die; binmode $fh; print $fh $gd->png; close $fh;

    Initially, I'm thinking about looking at (relative) luminance as a measure that I can try and match between images... so this code is only a step in the whole process.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11149059]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (6)
As of 2024-04-16 08:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found