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.