[Last Call] Learn about multicloud storage options and how to improve your company's cloud strategy. Register Now


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

Posted on 2004-10-25
Medium Priority
Last Modified: 2008-01-09

  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.
Question by:sapbucket
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
LVL 84

Expert Comment

ID: 12408218
greyscale value is sometimes estimated as 0.299R + 0.587G + 0.114B

Author Comment

ID: 12409029
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?

LVL 18

Expert Comment

ID: 12409829
   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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.


Author Comment

ID: 12415736
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!

LVL 84

Accepted Solution

ozo earned 2000 total points
ID: 12416602
Image::Pbm ?

Expert Comment

ID: 12419795
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.

Author Comment

ID: 12449932

  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.



Author Comment

ID: 12542054
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.


Author Comment

ID: 12563405

  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

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In the distant past (last year) I hacked together a little toy that would allow a couple of Manager types to query, preview, and extract data from a number of MongoDB instances, to their tool of choice: Excel (http://dilbert.com/strips/comic/2007-08…
Checking the Alert Log in AWS RDS Oracle can be a pain through their user interface.  I made a script to download the Alert Log, look for errors, and email me the trace files.  In this article I'll describe what I did and share my script.
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…
Six Sigma Control Plans

656 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