I want get 1 pixel (x=3, y=3)
and change its RGB values (R from 100
to 101
, G from 99
to 100
, B from 193
to 194
).
use strict;
use Image::Magick;
my $p = new Image::Magick;
$p->Read( 'myfile.jpg' );
my $pix = $p->GetPixel(
width => 1,
height => 1,
x => 3,
y => 3,
map => 'RGB',
normalize => 0
);
# in $pix RGB value now?
How do I add 1
for all RGB components?
Can I split decimal RGB to 3 values (r,g,b) and increment separately, and then merge three R,G,B values to one RGB? :) How do I do that?
$pix = .... something code here...
# make changes
$p->SetPixel(
x => 3,
y => 3,
channel => 'RGB',
color => [ $pix ]
);
$p->Write ('my_new_file.jpg');
This was a bit tricky to figure out, but here we go. I'll show you what I did to get to the result, not just how it works.
I'm using a small image that has your starting color (100, 99, 193)
.
At the top of my program I will always have this code.
use strict;
use warnings;
use Data::Printer;
use Image::Magick;
my $p = new Image::Magick;
$p->Read('33141038.jpg');
my @pixel = $p->GetPixel(
x => 1,
y => 1,
map => 'RGB',
normalize => 1,
);
I checked the documentation at imagemagick.org.. It is linked in Image::Magick on CPAN. There I searched GetPixel
. That yields two helpful things. One is the explanation, the other one an example that shows that an array @pixel
is returned, and not a scalar like you tried.
Here we reduce the intensity of the red component at (1,1) by half:
@pixels = $image->GetPixel(x=>1,y=>1);
Ok. Let's use that. I've already got the @pixel
in my code above. Note that I also turned on the normalize
option. You can leave that out as it's on by default.
p @pixel;
# [
# [0] 0.392156862745098,
# [1] 0.388235294117647,
# [2] 0.756862745098039
# ]
So those are floats. After some googling I found this answer, which deals with something similar. It looks like a fraction of 255
. Let's multiply. We can modify things in @pixel
by assigning to $_
in the postfix foreach
. That's neat.
$_ *= 255 foreach @pixel;
p @pixel;
# [
# [0] 100,
# [1] 99,
# [2] 193
# ]
That's what we wanted. Easy enough. Let's add one each.
$_ = ( $_ * 255 ) + 1 foreach @pixel;
p @pixel;
# [
# [0] 101,
# [1] 100,
# [2] 194
# ]
Still good. But how do we get that back in? The docs have something to say about SetPixel
in the Manipulate section.
color=>array of float values
[...]
set a single pixel. By default normalized pixel values are expected.
So apparently we need to go back to the float. No problem.
$_ = ( ( $_ * 255 ) + 1 ) / 255 foreach @pixel;
p @pixel;
# [
# [0] 0.396078431372549,
# [1] 0.392156862745098,
# [2] 0.76078431372549
# ]
Nice. We can of course also make the math a bit shorter. The result is the same.
$_ = $_ + 1 / 255 foreach @pixel;
Now let's write it back to the image.
$p->SetPixel(
x => 1,
y => 1,
color => \@pixel, # need the array ref here
);
$p->Write('my_new_file.jpg');
In the screenshot, I changed it to add 20
instead of 1
so it's more visible.
After cleaning up the code looks like this.
use strict;
use warnings;
use Data::Printer;
use Image::Magick;
my $p = new Image::Magick;
$p->Read('33141038.jpg');
my @pixel = $p->GetPixel(
x => 1,
y => 1,
);
# increase RGB by 1 each
$_ = $_ + 1 / 255 foerach @pixel;
$p->SetPixel(
x => 1,
y => 1,
color => \@pixel,
);
$p->Write('my_new_file.jpg');
I've removed the map
and channel
arguments from GetPixel
and SetPixel
as RGB
is the default. Same for the normalize
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With