Pregunta

I am using Aforge.Net to do some image processing and I'm having trouble understanding the Grayscale filter. Specifically the three mandatory red/green/blue coefficient constructor parameters.

To my understanding (from doing image segmentation research eight years ago) grayscaling is an operation that shouldn't take any parameters. You take an image, and you extract the luminescence channel, that's all.

So what are these parameters, and how do I simply extract luminescence?

Update: I should clarify what I'm trying to do. I am trying to automate a process which I can do manually in GIMP. In GIMP I can apply a threshold to any image and it operates on the luminescence histogram to produce a binary image, however in Aforge the Threshold filter works only on grayscale images. So how would I replicate my manual process?

¿Fue útil?

Solución

GIMP desaturate dialog box

When you convert to grayscale like this (see screenshot) in GIMP, it is calling this on each pixel:

gint luminosity = GIMP_RGB_LUMINANCE (s[RED], s[GREEN], s[BLUE]) + 0.5;

And a look at the source of gimprgb.c shows it is indeed using these values:

#define GIMP_RGB_LUMINANCE_RED    (0.2126)
#define GIMP_RGB_LUMINANCE_GREEN  (0.7152)
#define GIMP_RGB_LUMINANCE_BLUE   (0.0722)

I compared the output image from GIMP to one produced by AForge using these params:

var filter = new AForge.Imaging.Filters.Grayscale(0.2126, 0.7152, 0.0722);

and they appear identical.

UPDATE:

It appears that with the Threshold tool though, GIMP is taking a shortcut and simply taking the max of R,G or B. From threshold.c:

if (tr->color)
            {
              value = MAX (s[RED], s[GREEN]);
              value = MAX (value, s[BLUE]);

              value = (value >= tr->low_threshold &&
                       value <= tr->high_threshold ) ? 255 : 0;
            }
          else
            {
              value = (s[GRAY] >= tr->low_threshold &&
                       s[GRAY] <= tr->high_threshold) ? 255 : 0;
            }

So that is probably why you are getting different results.

UPDATE 2:

The various "convert to grayscale" methods included in .Net and elsewhere seem to all take averages or use some variation on the brightness or luminosity numbers mentioned above. I think reproducing the max value version used by GIMP Threshold will have to be done by hand. I adapted some of the fast (though unsafe) code found here to produce this:

public static Bitmap ColorToGrayscaleWithMax(Bitmap original)
{
    unsafe
    {
        Bitmap newBitmap = new Bitmap(original.Width, original.Height, PixelFormat.Format8bppIndexed);

        BitmapData originalData = original.LockBits(
            new Rectangle(0, 0, original.Width, original.Height),
            ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

        BitmapData newData = newBitmap.LockBits(
            new Rectangle(0, 0, original.Width, original.Height),
            ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

        //Set bytes per pixel
        int colorBytesPerPixel = 3;
        int grayBytesPerPixel = 1;

        for (int y = 0; y < original.Height; y++)
        {
            //get the data from the original image
            byte* oRow = (byte*)originalData.Scan0 + (y * originalData.Stride);

            //get the data from the new image
            byte* nRow = (byte*)newData.Scan0 + (y * newData.Stride);

            for (int x = 0; x < original.Width; x++)
            {
                //create the grayscale pixel by finding the max color
                byte grayScale = Math.Max(oRow[x * colorBytesPerPixel], oRow[x * colorBytesPerPixel + 1]);
                grayScale = Math.Max(grayScale, oRow[x * colorBytesPerPixel + 2]);

                //set the new image's pixel to the grayscale version
                nRow[x * grayBytesPerPixel] = grayScale; //B
            }
        }

        //unlock the bitmaps, finish
        newBitmap.UnlockBits(newData);
        original.UnlockBits(originalData);

        return newBitmap;
    }
}

And then you can use it as such:

var colorImage = AForge.Imaging.Image.FromFile(@"c:\temp\images\colorImage.png");
var preThresholdImage = ColorToGrayscaleWithMax(colorImage);
var filter = new AForge.Imaging.Filters.Threshold(100);
Bitmap bwImage = filter.Apply(preThresholdImage);
bwImage.Save(@"c:\temp\images\bwImage.png");

I ran it on a couple of images and compared with the ones produced manually with GIMP and they finally appeared identical.

Otros consejos

The RGB to grayscale conversion needs weighted sum on RGB channels. And the measure of color luminescence includes an non-linear transform called gamma correction. It is also a weighted sum, but on R^gamma, G^gamma, and B^gamma respectively. More formulas are described here.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top