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.
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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 )

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: 
with more details at:
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

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 ?

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
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:

### 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! :)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.