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