Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 308
  • Last Modified:

Image Magic: Image Report #2

I am using the code below to create a report of the rgb values for each pixel in an image. I record ech pixel in a row, the seperate each row. The I wish the results to be in html compatible hex (00-FF i.e. RGB = 1133FF) The code below almost does it. There is a color shift that occurs in the results though. It's almost like a sepia 2 tone gets generated. (Result looks like a black and white photo, with a yellow tint) Some of the really deep blacks get recoreded at "white" (bright yellow) I imagine there is a tweak that might help?

Any Ideas?

------------

 #!/usr/local/bin/perl

use Image::Magick;
my($image, $x);

$image = Image::Magick->new;
$x = $image->Read('file.jpg');
warn "$x" if "$x";

$cols=$image->get('columns');
$rows=$image->get('rows');

for($row=1; $row<=$rows; $row++){
     print "begin_row\n";
     for($i=1; $i<=$cols; $i++){
          printf "%x%x%x ", $image->get("pixel[$i,$row]");
     }
     print "\nend_row\n";
}
0
stakor
Asked:
stakor
  • 5
  • 3
  • 3
  • +1
1 Solution
 
Kim RyanIT ConsultantCommented:
get pixel  will return a string such as "255,0,128,0". I think you just need to weed out the commas, and also add leading zeros to the hex representation

for($i=1; $i<=$cols; $i++){
         ($red,$green,$blue) = split /,/, $image->get("pixel[$i,$row]");
          $hex_val = sprintf "%02X%02X%02X ", $red,$green,$blue);
          print "$hex_val";
}
0
 
stakorAuthor Commented:
I get the error:
syntax error line 22, near "$blue)"
0
 
Kim RyanIT ConsultantCommented:
oops, missed the opening bracket

$hex_val = sprintf ("%02X%02X%02X ", $red,$green,$blue);
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
stakorAuthor Commented:
I didn't see it either, or I would just have included it. Thanks.
0
 
stakorAuthor Commented:
Ok, when I run it now, I don't see the sepia thing going on. (This is good) But the blacks are now technicolor. Instead of juist being white, they are now white, bright red, bright blue, bright green, and bright yellow. Any idea what might be causing the color shift?
0
 
Kim RyanIT ConsultantCommented:
Are you sure your input image is palin RGB (no alpha channel?)
0
 
stakorAuthor Commented:
It's a random .jpg I grabed out of my web cache... I don't think jpegs have alpha channels. I can open it up with photoshop to see if I can see anything.
0
 
Adam314Commented:
Found 2 problems....rows/columns start at 0, not 1.  So the first row and colum was begin removed (not a big deal).... and get pixel returns at 16 bit number for each color, but HTML requires an 8 bit number, so the number from get pixel needs to be divided by 256.



#!/usr/local/bin/perl

use Image::Magick;
my($image, $x);

$image = Image::Magick->new;
$x = $image->Read('test1.gif');
warn "$x" if "$x";

$cols=$image->get('columns');
$rows=$image->get('rows');

for($row=0; $row<$rows; $row++){
     print "begin_row\n";
     for($col=0; $col<$cols; $col++){
          @pixels=split(/,/,$image->get("pixel[$col,$row]"));
          for($i=0;$i<4;$i++){
                $pixels[$i]=$pixels[$i]/256;
          }
          printf "%02X%02X%02X ",$pixels[0], $pixels[1], $pixels[2];
     }
     print "\nend_row\n";
}
0
 
stakorAuthor Commented:
It's going to be a few hours before I can test it. Thanks for the responce.
0
 
mjcoyneCommented:
I arrived at the same conclusions as Adam314 (that ImageMagick returns 16-bit RGBA values, and that rows and columns start at 0).  My solution is a bit different:

#!/usr/bin/perl -w
use strict;
use Image::Magick;

my($image, $x, $row, $col);

$image = Image::Magick->new;
$x = $image->Read('Untitled-5.jpg');
warn "$x" if "$x";

my $num_rows=$image->get('rows');
my $num_cols=$image->get('columns');

for($row=0; $row<=$num_rows; $row++) {
    print "begin_row\n";
    for($col=0; $col<=$num_cols; $col++) {
        my ($r, $g, $b) = map { $_/257 } split /,/, $image->get("pixel[$col,$row]");
        printf "%X%X%X", $r, $g, $b;
    }
     print "\nend_row\n";
}

Note that I'm dividing by 257, because it always results in integers, and thus avoids rounding errors.  I made an image in Photoshop, and ran several alternatives in the map block (note that ceil() and floor() require "use POSIX qw(ceil floor);" to be included in your code):

original image from Photoshop: 153, 51, 255 (9933FF)

map { $_/256 }, result: 153.59765625, 51.19921875, 255.99609375 (9933FF)
map { $_/257 }, result: 153, 51, 255 (9933FF)

map { sprintf ("%.0f", $_/256) }, result: 154, 51, 256 (9A33100)
map { sprintf ("%.0f", $_/257) }, result: 153, 51, 255 (9933FF)

map { int ($_/256) }, result: 153, 51, 255 (9933FF)
map { int ($_/257) }, result: 153, 51, 255 (9933FF)

map { ceil ($_/256) }, result: 154, 52, 256 (9A34100)
map { ceil ($_/257) }, result: 153, 51, 255 (9933FF)

map { floor ($_/256) }, result: 153, 51, 255 (9933FF)
map { floor ($_/257) }, result: 153, 51, 255 (9933FF)

Where dividing by 256 is usually correct (except using the sprintf() and ceil() methods), dividing by 257 is always correct (because it results in integers, thus no rounding errors).  Running the same test with an image that is 0, 255, 153 (00FF99), we get:

map { $_/256 }, result: 0, 255.99609375, 153.59765625 (0FF99)
map { $_/257 }, result: 0, 255, 153 (0FF99)

map { sprintf ("%.0f", $_/256) }, result: 0, 256, 154 (01009A)
map { sprintf ("%.0f", $_/257) }, result: 0, 255, 153 (0FF99)

map { int ($_/256) }, result: 0, 255, 153 (0FF99)
map { int ($_/257) }, result: 0, 255, 153 (0FF99)

map { ceil ($_/256) }, result: 0, 256, 154 (01009A)
map { ceil ($_/257) }, result: 0, 255, 153 (0FF99)

map { floor ($_/256) }, result: 0, 255, 153 (0FF99)
map { floor ($_/257) }, result: 0, 255, 153 (0FF99)

Again, dividing by 256 is usually right, but using 257 is always correct.  I would either divide by 257, or use int ($_/256) to avoid errors.
0
 
Adam314Commented:
I think the fractional portion will be ignored by the format style in the printf "%02x"...

I'm not sure how image magic is getting its 16-bit numbers, but dividing by 257, you could possibly be 1 bit off.

ex:
color is Red:  255,0,0
If Image magic reports this as 16-bit number (hex and decimal shown) with lower bits set: 65535 ($FFFF), 0 ($0000), 0 ($0000)
Dividing by 256: 255.996 ($FF), 0 ($00), 0 ($0)
Dividing by 257: 255 ($FF), 0 ($00), 0 ($00)

If Image magic reports this as a 16-bit number with lower bits clear: 65280 ($FF00), 0 ($0000), 0 ($0000)
Dividing by 256: 255 ($FF), 0 ($00), 0 ($00)
Dividing by 257: 254.007 ($FE), 0 ($00), 0 ($00)

I couldn't find anything about how it generates it's 16-bit numbers when the image contains only 8 bits.  Not knowing this, dividing by 257 could possibly *slightly* change the colors a little bit.  Since I think the formatting style used in the printf ignores the fractional part, I'd stick to dividing by 256... to be safe, you could take the int as pointed out by mjcoyne, but I don't think it's necessary.
0
 
mjcoyneCommented:
I don't know too much about this, but I think that 100% saturation in 8-bit color is 255 (decimal), while 100% saturation in 16-bit is 65535 (decimal).  Converting from one to the other thus requires a factor of 65535/255 = 257.  So, to go from 8-bit to 16-bit, one would multiply by 257, and to go from 16-bit to 8-bit, one would divide by 257.

It seems to me more accurate to do it this way and deal with the correct integers than to divide by another number (256) and round down, which is essentially what int() or printf does by ignoring the fraction.
0
 
mjcoyneCommented:
BTW, Adam314 is right on the printf format.  I had "printf "%X%X%X", $r, $g, $b;" and it should be "printf "%02X%02X%02X", $r, $g, $b;" so that there are two places for each hex digit (thus 255, 0, 0 gets reported as FF 00 00, rather than FF 0 0).
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 5
  • 3
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now