[comp.windows.x] Converting color images to monochrome - can I do it any faster ?

rao@enuxha.eas.asu.edu (Arun Rao) (10/21/89)

	My image processing application requires the user to select
	an arbitrary rectangular section from the screen to be
	processed further. Since the processing depends only upon
	brightness levels, I would like to display the selected portion
	as a gray-scale image regardless of what it looks like on
	the screen.

	Here's the code fragment I use to convert color pixel values
	to equivalent gray-scale values:

  	width = image->width;
        height = image->height;


        /* Get default Colormap */
        cmap = DefaultColormap(dpy, screen);


        for (i = 0; i < height; i++)
                for (j = 0; j < width; j++)
                {
                        /* This is the most portable way of doing it,
                           but slow as hell */
                        /* Get pixel values from the image and fill XColor's */
                        xcolor.pixel = XGetPixel(image, j, i);

			/* Get RGB values corresponding to pixel value */
                        XQueryColor(dpy, cmap, &xcolor);

                        /* RGB to gray-scale formula (from Adrian Nye's book)*/
                        intensity = (int)((0.30 * xcolor.red)
                                   +(0.59 * xcolor.green)
                                   +(0.11 * xcolor.blue));

			/* Put (equal) gray level values in RGB */
                        xcolor.red = (unsigned short)intensity;
                        xcolor.green = (unsigned short)intensity;
                        xcolor.blue = (unsigned short)intensity;

			/* Get pixel values corresponding to
			   gray-level */
                        XAllocColor(dpy, cmap, &xcolor);

			/* Put pixel back in image */
                        XPutPixel(image, j, i, xcolor.pixel);
                }


	The above is very portable, but is horrendously slow, even
	for small images. Is there a better way of doing this without
	resorting to machine dependent bit-fiddling ?
	
	The machine is an Ardent Titan running SysV and X11R3 and I've
	tested the program in addition on an HP 9000 server.

	Thanks in advance.


	-Arun
-- 
Arun Rao
ARPANET: rao@enuxha.eas.asu.edu BITNET: agaxr@asuacvax, agazr@asuacad
950 S. Terrace Road, #B324, Tempe, AZ 85281
Phone: (602) 968-1852 (Home) (602) 965-3452 (Office)

martin@dip.eecs.umich.edu (Martin R. Friedmann) (10/22/89)

In article <324@enuxha.eas.asu.edu> rao@enuxha.eas.asu.edu (Arun Rao) writes:

	   Here's the code fragment I use to convert color pixel values
	   to equivalent gray-scale values:

	   for (i = 0; i < height; i++)
		   for (j = 0; j < width; j++)
		   {
			/* This is the most portable way of doing it,
			   but slow as hell */

->>  Not the most portable way, just the most brain dead.  I guess that
->>  makes it portable huh?  Braindead == portable?   Nah... 
->>  ah!!  Braindead == (portable & short & understandable)

			/* Get pixel values from the image and fill XColor's */
			/* Get RGB values corresponding to pixel value */

			/* RGB to gray-scale formula (from Adrian Nye's book)*/
			/* Put (equal) gray level values in RGB */

			/* Get pixel values corresponding to
			   gray-level */

			/* Put pixel back in image */
		   }


	   The machine is an Ardent Titan running SysV and X11R3 and I've
	   tested the program in addition on an HP 9000 server.

	   Thanks in advance.

I know you run on a titan, that helps, but this code sucks!

You want this code to run faster???  Then take as much out of the nested
for loop as possible!  Converting from colors to grey scale (not monochrome)
will leave lots of duplicate pixels on the screen.  Look at your code!
for each pixel you allocate a color???   Wrong.  First figure out which
colors you need.  Then allocate them...  And By all means use XGetImage!
You make soo many less calls to Xlib.

Malloc an array width * height * sizeof(Pixel); then XGetImage into that array
(set the image.data = malloc....)  use the Nye's formula on each pixel in the
array (use one for loop, not two) (remember which intensities you need to
allocate for later) Figure out which values you need from 0-255, pack those in
the colormap.  Make a transfer function (This pixel(now intensity) value gets
this colormap cell) allocate the colormap cells all at once (XAllocColorCells)
use Fill the colorcells with the packed intensity values from your image.
XStoreColors to store them all at once.  Then use XPutImage to put the Image
back.

I'm afraid that all of this won't be of much help to you.

Marty.
--

Marty.