Otsu Threshold

This algorithm is used to automatically perform clustering-based image thresholding or, the reduction of a graylevel image to a binary image.

   



									public static void ApplyOtsuThreshold(ref Bitmap bmp)
{
	Grayscale(ref bmp);
	int otsuThreshold = GetOtsuThreshold(bmp) * 3;
	Threshold(ref bmp, (short)otsuThreshold);
}

private static void Grayscale(ref Bitmap bmp)
{
	BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

	unsafe
	{
		byte* ptr = (byte*)bmpData.Scan0.ToPointer();
		int stopAddress = (int)ptr + bmpData.Stride * bmpData.Height;

		while ((int)ptr != stopAddress)
		{
			*ptr = (byte)((ptr[2] * .299) + (ptr[1] * .587) + (ptr[0] * .114));
			ptr[1] = *ptr;
			ptr[2] = *ptr;

			ptr += 3;
		}
	}

	bmp.UnlockBits(bmpData);
}

private static void Threshold(ref Bitmap bmp, short thresholdValue)
{
	int MaxVal = 768;

	if (thresholdValue < 0) return;
	else if (thresholdValue > MaxVal) return;

	BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

	unsafe
	{
		int TotalRGB;

		byte* ptr = (byte*)bmpData.Scan0.ToPointer();
		int stopAddress = (int)ptr + bmpData.Stride * bmpData.Height;

		while ((int)ptr != stopAddress)
		{
			TotalRGB = ptr[0] + ptr[1] + ptr[2];

			if (TotalRGB <= thresholdValue)
			{
				ptr[2] = 0;
				ptr[1] = 0;
				ptr[0] = 0;
			}
			else
			{
				ptr[2] = 255;
				ptr[1] = 255;
				ptr[0] = 255;
			}

			ptr += 3;
		}
	}

	bmp.UnlockBits(bmpData);
}

private static float Px(int init, int end, int[] hist)
{
	int sum = 0;
	int i;

	for (i = init; i <= end; i++)
		sum += hist[i];

	return (float)sum;
}

private static float Mx(int init, int end, int[] hist)
{
	int sum = 0;
	int i;

	for (i = init; i <= end; i++)
		sum += i * hist[i];

	return (float)sum;
}

private static int FindMax(float[] vec, int n)
{
	float maxVec = 0;
	int idx = 0;
	int i;

	for (i = 1; i < n - 1; i++)
	{
		if (vec[i] > maxVec)
		{
			maxVec = vec[i];
			idx = i;
		}
	}

	return idx;
}

unsafe private static void GetHistogram(byte* p, int w, int h, int ws, int[] hist)
{
	hist.Initialize();

	for (int i = 0; i < h; i++)
	{
		for (int j = 0; j < w * 3; j += 3)
		{
			int index = i * ws + j;
			hist[p[index]]++;
		}
	}
}

private static int GetOtsuThreshold(Bitmap bmp)
{
	byte t = 0;
	float[] vet = new float[256];
	int[] hist = new int[256];
	vet.Initialize();

	float p1, p2, p12;
	int k;

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

	unsafe
	{
		byte* p = (byte*)(void*)bmData.Scan0.ToPointer();

		GetHistogram(p, bmp.Width, bmp.Height, bmData.Stride, hist);

		for (k = 1; k != 255; k++)
		{
			p1 = Px(0, k, hist);
			p2 = Px(k + 1, 255, hist);
			p12 = p1 * p2;
			if (p12 == 0)
				p12 = 1;
			float diff = (Mx(0, k, hist) * p2) - (Mx(k + 1, 255, hist) * p1);
			vet[k] = (float)diff * diff / p12;
		}
	}

	bmp.UnlockBits(bmData);
	t = (byte)FindMax(vet, 256);

	return t;
}
								


Example

									Bitmap b = (Bitmap)Image.FromFile("rose.jpg");
ApplyOtsuThreshold(ref b);