[Webinar] Streamline your web hosting managementRegister Today

  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1243
  • Last Modified:

How to get gray scale pixel values from "Microsoft Windows Bitmap Image"?


  I have been playing around with ImageMagick (hopefully you are familiar) and ran across a problem getting pixel values from bitmaps. The images I am using are Microsoft Windows Bitmap Images (24-bit bitmaps). The images are in black and white. However, when I use:

#!/usr/bin/perl -w
use Image::Magick;
$im = new Image::Magick;


($red, $green, $blue, $opacity) = split /,/, $im->Get("pixel[$x,$y]");
if($red==0 && $green==0 && $blue==0) {
    print "Color is black\n";
} elsif($red==255 && $green==255 && $blue==255) {
    print "Color is white\n";
} else {
    print "Color is $red,$green,$blue\n";

I get pixel values in RGB format. I want Gray scale format.

How do I get the pixels values in (ideally, 8-bit) gray scale format?

I would rather like it if you could suggest a less cumbersome and MUCH FASTER image module other than ImageMagick

I really just need to open a greyscale bitmap, read the pixel values into an array, and do point operations. However, I get pixel values in RGB, when I am expecting 8-bit Gray scale. Not really sure what to do.
1 Solution
greyscale value is sometimes estimated as 0.299R + 0.587G + 0.114B
sapbucketAuthor Commented:
Yes, I used:

Y = 0.3*R + 0.59*G + 0.11*B

However, after this conversion I am left with an array of gray scale values - which is great for processing - but now how do I save the image to file?

Do I need to convert back to RGB?

This is what I tried: (from http://www.imagemagick.org/www/perl.html#seta )

binmode STDOUT;
$filename = "c:\\image.bmp";
open(IMAGE, ">$filename");
$image->Write(file=>\*IMAGE, filename=>$filename);

 And the above is supposed to write the image buffer to a specified filename and image format (in this case bitmap).

But, I get the following error with the above line:
$image->Write(file=>\*IMAGE, filename=>$filename);

It says:
perl.exe - Application Error
The instruction at "0x7c369c37" referenced memory at "0x00000010". The memory could not be "read".

and crashes the application.

I'm sorta lost as what to do. This all seems so cumbersome and anti-PERL in how difficult it is to figure out.

Any more suggestions?

   use Image::Magick;
    $image = Image::Magick->new;
    $image->Draw(primitive=>'rectangle', points=>'1,1 49,49', method=>'Floodfill', fill=>'green');
    $image->Draw(primitive=>'rectangle', points=>'50,50 99,99', method=>'Floodfill', fill=>'yellow');
    $image->Draw(primitive=>'rectangle', points=>'1,50 49,99', method=>'Floodfill', fill=>'blue');
    $image->Set('type' => 'Grayscale');

Also see the Fx method: http://www.imagemagick.org/www/perl.html#misc 
with more details at: http://www.imagemagick.org/www/ImageMagick.html#details-fx
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

sapbucketAuthor Commented:
Kandura and others,

  This looks like I am almost there. However, when you use the Draw() function you are not setting individual pixels. In your above example you are using method 'Floodfill.' Is there a method that is efficient at single points?

   I am getting the impression that Image::Magick is not what I want. Image::Magick is more like Photoshop then an efficient image processor.

   I only need the following functionality, and while I am sure Image::Magick can handle it, I am sure there must be an PERL module that is more appropriate:
   1. Open a .bmp.
   2. Get it's height and width information as integers
   3. Get the pixel values from the bitmap and store in array
   4. Process the pixel values in the array (use height and width for ROW / COL operations)
   5. use the processed pixel values to create a bitmap image in memory
   6. save the bitmap image to the harddrive.

    This seems like a simple enough process that MANY people must have done already.
    Can anyone suggest a better way than Image::Magick?
    Can anyone suggest how this can be done using Image::Magick?

    I am open to using other image formats besides bmp.

    Many many thanks!

Image::Pbm ?
Check out GD module.

Look at:
width and height: getBounds,
Read Pixel Color:  getPixel,
Write Pixel        : setPixel,

You can also mix and match, by reading from Image::Magic and writing using GD.
or vice-versa. Profiling the code will tell you which way it's more efficient.
sapbucketAuthor Commented:

  you got it! That was what I needed. I really used Image::XPM, which uses Image::PBM.

  Image::XPM gave me all the functionality I needed. Wouldn't of ever found it without you suggesting Image::PBM.


sapbucketAuthor Commented:
If anyone ever encounters this problem let it be known that XPM is not a good Windows solution.

XPM is a popular X Window image file format for storing color icons. It isn't really suited for Windows. The problem for me is that I have to convert XPM to bitmap to view my images and that creates a lot of system overhead. If I were on a X window machine I would not have to do this. Besides that, if you do not have to care about system frequency, it is fine.

Good luck trying to find a Windows XP XPM viewer that works.

sapbucketAuthor Commented:

  I found the best way to deal with Windows Bitmaps using PERL. I am most pleased with the result.

  Here is a test script:

#!/usr/bin/perl -w
# filename: testWin32GuiDIBitmap.pl

### Declarations ###
use Win32::GUI::DIBitmap;
use Time::HiRes qw(usleep ualarm gettimeofday tv_interval);

### Process Profiler ###
($seconds1, $microseconds1) = gettimeofday;

### Core ###
$dib = newFromFile Win32::GUI::DIBitmap ($filename);
for($h=0;$h<$height;$h++) {
    for($w=0;$w<$width;$w++) {
        $hexp = sprintf("%X", $p);
        my $r=reverse((chop $hexp).(chop $hexp));
        $r=255-hex($r); # invert the image to test image processing
print "width: $w, height $h\n";

### Process Profiler ###
($seconds2, $microseconds2) = gettimeofday;
$sec=$eum / 1000000;
print "seconds elapsed: $es, microseconds: $eum ($sec of a second)\n";

You will need to install the necessary modules:


Good luck! :)

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now