Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Using Imager getpixel

by LloydRice (Beadle)
on Dec 30, 2011 at 09:24 UTC ( [id://945617]=perlquestion: print w/replies, xml ) Need Help??

LloydRice has asked for the wisdom of the Perl Monks concerning the following question:

I have a question about the Imager package. This is ActiveState v5.12.4 with Win7Pro on a 64-bit Gateway SX-2841. I would like to access the pixel values from a BMP image.
c:>type gp1.pl use Imager; my $image_source = "\\c\\perl\\graphics\\" . shift . ".bmp"; my $image = Imager->new; $image->read(file=>$image_source) or die "Cannot load $image: ", $image->errstr; $width = $image->getwidth(); $height = $image->getheight(); print "Image dimensions: height = $height, width = $width\n"; $x = 10; for $y ( 10 .. 15 ) { $color = $image->getpixel( x=>$x, y=>$y, type=>'8bit' ); ( $r, $g, $b, $a ) = $color->rgba(); print " shade = $r, $g, $b\n"; } c:>gp1 d2044 Image dimensions: height = 348, width = 349 shade = 238, 238, 238 shade = 255, 255, 255 shade = 255, 255, 255 shade = 238, 238, 238 shade = 238, 238, 238 shade = 238, 238, 238 c:>
So far, so good. It is said that I can also use the getpixel invocation directly as the method reference to run rgba().
c:>type gp2.pl use Imager; my $image_source = "\\c\\perl\\graphics\\" . shift . ".bmp"; my $image = Imager->new; $image->read(file=>$image_source) or die "Cannot load $image: ", $image->errstr; $width = $image->getwidth(); $height = $image->getheight(); print "Image dimensions: height = $height, width = $width\n"; $x = 10; for $y ( 10 .. 15 ) { ( $r, $g, $b, $a ) = $image->getpixel( x=>$x, y=>$y, type=>'8bit' )->rgba(); print " shade = $r, $g, $b\n"; } c:>gp2 d2044 Image dimensions: height = 348, width = 349 shade = 238, 238, 238 shade = 255, 255, 255 shade = 255, 255, 255 shade = 238, 238, 238 shade = 238, 238, 238 shade = 238, 238, 238
Very good. But now it seems like a lot of work to call getpixel separately for each pixel. The 'draw' tutorial says that I can pass a reference to a list of pixel addresses to getpixel(). I should get back a list of references to a color method. I tried it this way.
c:>type gp3.pl use Imager; my $image_source = "\\c\\perl\\graphics\\" . shift . ".bmp"; my $image = Imager->new; $image->read(file=>$image_source) or die "Cannot load $image: ", $image->errstr; $width = $image->getwidth(); $height = $image->getheight(); print "Image dimensions: height = $height, width = $width\n"; $x = 10; $y = [ 10 .. 15 ]; @colors = $image->getpixel( x=>$x, y=>$y, type=>'8bit' ); for $color ( @colors ) { ( $r, $g, $b, $a ) = $color->rgba(); print " shade = $r, $g, $b\n"; } c:>gp3 d2044 Image dimensions: height = 348, width = 349 Can't call method "rgba" on an undefined value at gp3.pl line 15.
No luck. It seems that the elements of @colors are undefined. I presume something is wrong with the getpixel() call. OK. So maybe if one axis is a reference, then both have to be.
c:>type gp4.pl use Imager; my $image_source = "\\c\\perl\\graphics\\" . shift . ".bmp"; my $image = Imager->new; $image->read(file=>$image_source) or die "Cannot load $image: ", $image->errstr; $width = $image->getwidth(); $height = $image->getheight(); print "Image dimensions: height = $height, width = $width\n"; $x = [ 10 ]; $y = [ 10 .. 15 ]; @colors = $image->getpixel( x=>$x, y=>$y, type=>'8bit' ); for $color ( @colors ) { ( $r, $g, $b, $a ) = $color->rgba(); print " shade = $r, $g, $b\n"; } c:>gp4 d2044 Image dimensions: height = 348, width = 349 Can't call method "rgba" on an undefined value at gp4.pl line 15.
Still doesn't work. What am I missing?

Replies are listed 'Best First'.
Re: Using Imager getpixel
by Khen1950fx (Canon) on Dec 30, 2011 at 11:04 UTC
    Two minor problems: First, the default is 8bit, so you don't need that. Second, you forgot to declare some of your variables, esp. $color, hence, the undefined value. I corrected that and did this, using your first script:
    #!/usr/bin/perl use strict; use warnings; use Imager; my $image_source = shift @ARGV; my $image = Imager->new; $image->read( file => $image_source ) or die "Cannot load $image: ", $image->errstr; my $width = $image->getwidth(); my $height = $image->getheight(); print "Image dimensions: height = $height, width = $width\n"; my $x = 10; foreach my $y ( 10 .. 15 ) { my $color = $image->getpixel( x => $x, y => $y ); my ( $r, $g, $b, $a ) = $color->rgba(); print " shade = $r, $g, $b\n"; }
      OK. I agree that '8bit' was the default, so it was redundant, but not wrong, to include it. But declaring $color does not seem to have been the answer for my third or fourth attempt. There does seem to be some sort of dependency between the use of scalar vs. reference on one or both axes. But this still does not clear up the mystery. In the following, I have kept the startup portion of the code exactly as shown above by Khen1950fx, so I will not repeat it here. May we just concentrate on the getpixel call? First, I have located a portion of the image with distinct values in four adjacent pixels.
      for my $x ( 14, 15 ) { for my $y ( 14, 15 ) { my @color = $image->getpixel( x => $x, y => $y ); my ( $r, $g, $b, $a ) = $color[0]->rgba(); print " shade( $x, $y ) = $r, $g, $b\n"; } }
      This version produces the output:
      Image dimensions: height = 348, width = 349 shade( 14, 14 ) = 255, 255, 255 shade( 14, 15 ) = 221, 221, 221 shade( 15, 14 ) = 170, 170, 170 shade( 15, 15 ) = 51, 51, 51
      So far, so good. But now if we replace both axes by referenced lists, we get something I did not expect:
      my @color = $image->getpixel( x => [ 14, 15 ], y => [ 14, 15 ] ); for my $clr ( @color ) { my ( $r, $g, $b, $a ) = $clr->rgba(); print " shade = $r, $g, $b\n"; }
      We get, not the full square of scanned pixels, as I expected, but rather just the diagonal. This would explain why both axes must have identical reference lists. If they differ, the result is undefined.
      Image dimensions: height = 348, width = 349 shade = 255, 255, 255 shade = 51, 51, 51
      No. That's still not quite it. Actually, the requirement is that both referenced lists do need to be the same length, but the reference is only to pixel pairs, respectively, not the full square (or rectangle), as I assumed it might work. For example, this works:
      my @color = $image->getpixel( x => [ 13, 15, 17, 17, 20 ], y => [ 17, 14, 18, 19, 15 ] ); for my $clr ( @color ) { my ( $r, $g, $b, $a ) = $clr->rgba(); print " shade = $r, $g, $b\n"; }
      The output is:
      Image dimensions: height = 348, width = 349 shade = 204, 204, 204 shade = 170, 170, 170 shade = 136, 136, 136 shade = 187, 187, 187 shade = 153, 153, 153
      And I ran the first code fragment above with the pixel address values such as to display the entire rectangle covered by this last example and the pixel values are exactly those reference pairwise here. In other words, if I had duplicated the pixel addresses for the final printout, I would have:
      shade( 13, 17 ) = 204, 204, 204 shade( 15, 14 ) = 170, 170, 170 shade( 17, 18 ) = 136, 136, 136 shade( 17, 19 ) = 187, 187, 187 shade( 20, 15 ) = 153, 153, 153
      Any time the pixel reference lists are of unequal length, you get an undefined result. Makes sense, now. My only complaint then (Tony?), would be that this is not very clear in the 'draw' documentation.

        I'll improve it, both the handling of supplying a scalar and ref in x, y and diagnostics for different array lengths.

        If you can work row-by-row instead of column-by-column, you might want to consider using getscanline() or getsamples() instead of getpixel().

Re: Using Imager getpixel
by BrowserUk (Patriarch) on Dec 30, 2011 at 09:38 UTC
    So maybe if one axis is a reference, then both have to be....

    How about making both arrays the same size:

    $y = [ 10 .. 15 ]; $x = [ (10) x $#$y ]; ...

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (3)
As of 2025-07-09 06:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.