| Customize Help

Converting to grayscale



Converting color images to grayscale can be useful since many processing and analysis modules operate on grayscale images. For example, a picture of a license plate can be taken in color, but before it can be used in an Automatic Number Plate Recognition (ANPR) application written with the MIL String Reader module, it must be converted to grayscale.

To convert color images to grayscale, you can either use MimConvert() to extract the luminance, or McolProject() to perform a principal component projection. To enhance image quality and improve subsequent operations, you can also process your images by, for example, performing binary thresholding.

Various conditions, such as different cameras and illuminants, can cause color from identical images to appear dissimilar. If this occurs, you can call McolTransform() to perform a relative color calibration before converting color images to grayscale. Relative color calibration ensures all colors are consistent according to a specified reference color. For more information, see the Relative color calibration section earlier in this chapter.

MimConvert() is available with MIL-Lite. McolProject() and McolTransform() require the full version of MIL.

Extracting the luminance

You can use MimConvert() to convert color images to grayscale by extracting the luminance (intensity) from an RGB image (M_RGB_TO_L), or copying the luminance component of an image into a 3-band RGB buffer (M_L_TO_RGB), to create a monochromatic (gray) RGB buffer. For the YUV color space, you can use M_RGB_TO_Y to extract the Y-component from an RGB image.

You can also use MimConvert() to convert from RGB to HSL, or vice versa (M_RGB_TO_HSL and M_HSL_TO_RGB, respectively). This can be useful if you want to perform color analysis in a color space other than the one in which your color data is stored.

To convert between RGB and HSL color spaces, MimConvert() uses the following algorithm:

#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))

// Input and output between 0 and 1.

void RGBToHSL(float R, float G, float B, float* H, float* S, float* L)
   {
   float MinVal, MaxVal, Delta;

   // Min and max values.
   MaxVal = max(R, max(G, B));
   MinVal = min(R, min(G, B));

   Delta = MaxVal - MinVal;

   // Compute the luminance.
   *L = 0.5f * (MaxVal + MinVal);

   if (Delta == 0.0f)
      {
      *S = *H = 0.0f;
      }
   else
      {
      // Compute the saturation.
      if (*L <= 0.5f)
         {
         *S = Delta / (MaxVal + MinVal);
         }
      else
         {
         *S = Delta / (2.0f - MaxVal - MinVal);
         }

      // Compute the hue.
      if (MaxVal == R)
         {
         *H = 60.0f * ((G - B) / Delta);
         }
      else if (MaxVal == G)
         {
         *H = 60.0f * (2.0f + ((B - R) / Delta));
         }
      else
         {
         *H = 60.0f * (4.0f + ((R - G) / Delta));
         }

      if (*H < 0.0f)
         {
         *H += 360.0f;
         }
      }

   // Remap the angle between 0 and 1.
   
   *H = *H / 360.0f;
   }

float HueToRGB(float Temp1, float Temp2, float Hue)
   {
   if (Hue > 360.0f)
      {
      Hue = Hue - 360.0f;
      }
   else if (Hue < 0.0f)
      {
      Hue = Hue + 360.0f;
      }

   if (Hue < 60.0f)
      {
      return (Temp1 + (Temp2 - Temp1) * Hue / 60.0f);
      }
   else if (Hue < 180.0f)
      {
      return Temp2;
      }
   else if (Hue < 240.0f)
      {
      return (Temp1 + (Temp2 - Temp1) * (240.0f - Hue) / 60.0f);
      }

   return Temp1;
   }

// Input and output between 0 and 1.

void HSLToRGB(float H, float S, float L, float* R, float* G, float* B)
   {
   float Temp1, Temp2;

   // Remap the angle between 0 and 360.
   H = H * 360.0f;

   // Achromatic case.
   if (S == 0.0f)
      {
      *R = *G = *B = L;
      }
   else
      {
      if (L <= 0.5f)
         {
         Temp2 = L * (1.0f + S);
         }
      else
         {
         Temp2 = L + S - (L * S);
         }

      Temp1 = 2.0f * L - Temp2;

      *R = HueToRGB(Temp1, Temp2, H + 120.0f);
      *G = HueToRGB(Temp1, Temp2, H);
      *B = HueToRGB(Temp1, Temp2, H - 120.0f);
      }
   }

For more technical information, refer to Computer Graphics: Principles and Practice in C, James D. Foley et al., Addison-Wesley Publishing Company, United States, 1995.

Principal component projection

You can convert a color image to grayscale using McolProject() with M_PRINCIPAL_COMPONENT_PROJECTION which, unlike MimConvert(), does not simply extract a single component of the color space. Instead, it uses the distribution of the image's color data to calculate the best grayscale conversion possible, minimizing the loss of information. This results in a grayscale image that can better differentiate the color in the original source image.

As the example above illustrates, extracting just the luminance, as is done with MimConvert(), can cause different colors to look the same in grayscale, which can make analysis problematic in certain cases. However, with M_PRINCIPAL_COMPONENT_PROJECTION, MIL performs a principal component analysis (PCA) to calculate the color image's strongest vector, referred to as the first principal component, which represents the greatest degree of color variation within the color space. Each color pixel is then projected to a point on this vector, resulting in a grayscale image that conveys more information than a luminance extraction.

If the first principal component vector is the same as the luminance vector (black-to-white), the principal component projection will be very similar to extracting the luminance band. This can happen if, for example, the greatest variation in color in the image is roughly from black to white. In this case, it can still be advantageous to use the first principal component, since this vector was calculated from the data distribution itself and is optimally oriented (black-to-white/white-to-black) for the projection calculation.

Using a principal component projection for converting to grayscale

For converting to grayscale, McolProject() calculates the first principal component vector using the entire source image or specific areas of the source image. Typically using the entire source image is sufficient.

To identify specific areas in the source image with which to calculate the first principal component, you must specify another image, referred to as a data identification image. In this image, you must set the corresponding pixels to M_SOURCE_LABEL. By specifying the exact colors (pixels) in the source image to use, you can increase the difference between grayscale values in some cases.

When using a principal component projection to convert to grayscale, colors are automatically projected between the brightest (white) and darkest (black) side of the grayscale palette. If this is performed properly, the resulting status of McolProject() is M_SUCCESS. If MIL cannot confidently determine which pixels to project to the bright side of the grayscale palette and which to project to the dark side, the direction of the projection is chosen arbitrarily and the resulting status is M_UNSTABLE_POLARITY. When this occurs, you can use the data identification image to identify the corresponding pixels in the source that you want to project to the bright side of the grayscale palette and which to project to the dark side, using McolProject() with M_BRIGHT_LABEL and M_DARK_LABEL.

By default, MIL projects the result according to the dynamic range (minimum and maximum pixel values) established from all the pixels in the source image, even if you have set specific source pixels to M_SOURCE_LABEL. If necessary, you can use M_MASK_CONTRAST_ENHANCEMENT to improve the conversion to grayscale by performing the projection according to the dynamic range established from only the specified source image pixels. The result is similar to increasing the contrast.

When using M_MASK_CONTRAST_ENHANCEMENT, MIL saturates the projected unidentified source image colors that are outside the dynamic range of the identified source image pixels' color (M_SOURCE_LABEL); that is, MIL maps those colors to either the minimum or maximum allowable grayscale value. In this case, the projection result can contain sections that have lost a certain degree of contrast information.

This example illustrates how, given the dynamic range MIL establishes from the identified source image pixels, MIL projects to 0 any unidentified pixel value below 100, and projects to 255 any value above 200.

Dynamic range of the identified source image pixels: 100 to 130

Projected unidentified pixel values

Resulting grayscale pixel values

5

100

10

100

20

100

40

100

195

200

200

200

220

200

240

200

When using McolProject(), you can also specify a destination mask. The mask determines where to write the result of the projection operation and does not affect calculations. Results are only written to unmasked destination pixels. Do not confuse this mask with the data identification image containing M_SOURCE_LABEL, which is used to identify the source image pixels to use for the calculation.

McolProject() can either produce the resulting grayscale image, or the transformation matrix to convert the image to grayscale. You can use this matrix with MimConvert() to perform an optimal color-to-grayscale transformation of any 3-band color image. Only use this matrix to convert images that have a similar color distribution, otherwise unpredictable results can occur.