Solved

Image Magic: Image Report #2

Posted on 2006-07-13
13
260 Views
Last Modified: 2006-11-18
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
Comment
Question by:stakor
  • 5
  • 3
  • 3
  • +1
13 Comments
 
LVL 19

Expert Comment

by:Kim Ryan
ID: 17105183
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
 

Author Comment

by:stakor
ID: 17105249
I get the error:
syntax error line 22, near "$blue)"
0
 
LVL 19

Expert Comment

by:Kim Ryan
ID: 17105302
oops, missed the opening bracket

$hex_val = sprintf ("%02X%02X%02X ", $red,$green,$blue);
0
 

Author Comment

by:stakor
ID: 17106980
I didn't see it either, or I would just have included it. Thanks.
0
 

Author Comment

by:stakor
ID: 17107015
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
 
LVL 19

Expert Comment

by:Kim Ryan
ID: 17107303
Are you sure your input image is palin RGB (no alpha channel?)
0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 

Author Comment

by:stakor
ID: 17107729
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
 
LVL 39

Accepted Solution

by:
Adam314 earned 401 total points
ID: 17108791
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
 

Author Comment

by:stakor
ID: 17109068
It's going to be a few hours before I can test it. Thanks for the responce.
0
 
LVL 17

Expert Comment

by:mjcoyne
ID: 17111367
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
 
LVL 39

Expert Comment

by:Adam314
ID: 17111839
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
 
LVL 17

Expert Comment

by:mjcoyne
ID: 17112993
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
 
LVL 17

Expert Comment

by:mjcoyne
ID: 17113006
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

A year or so back I was asked to have a play with MongoDB; within half an hour I had downloaded (http://www.mongodb.org/downloads),  installed and started the daemon, and had a console window open. After an hour or two of playing at the command …
There are many situations when we need to display the data in sorted order. For example: Student details by name or by rank or by total marks etc. If you are working on data driven based projects then you will use sorting techniques very frequently.…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now