public Bitmap WhiteBalance(Bitmap image) { float percentage = 99.3f; var rHistogram = new Histogram <byte>(); var gHistogram = new Histogram <byte>(); var bHistogram = new Histogram <byte>(); var clonedImage = (Bitmap)image.Clone(); Rectangle rect = new Rectangle(0, 0, image.Width, image.Height); System.Drawing.Imaging.BitmapData bitmapData = clonedImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, image.PixelFormat); IntPtr ptr = bitmapData.Scan0; int bytes = Math.Abs(bitmapData.Stride) * clonedImage.Height; byte[] rgbValues = new byte[bytes]; System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); for (int i = 0; i < rgbValues.Length - 2; i += 3) { bHistogram.AddElement(rgbValues[i]); gHistogram.AddElement(rgbValues[i + 1]); rHistogram.AddElement(rgbValues[i + 2]); } (var rMin, var rMax) = HistogramStatistics.FindBoundariesOfXPercentage <byte>(rHistogram, percentage); (var gMin, var gMax) = HistogramStatistics.FindBoundariesOfXPercentage <byte>(gHistogram, percentage); (var bMin, var bMax) = HistogramStatistics.FindBoundariesOfXPercentage <byte>(bHistogram, percentage); var rA = 255 / (rMax - rMin); var rB = 0 - rA * rMin; var gA = 255 / (gMax - gMin); var gB = 0 - gA * gMin; var bA = (255) / (bMax - bMin); var bB = 0 - bA * bMin; int val = 0; for (int i = 0; i < rgbValues.Length - 2; i += 3) { val = rA * rgbValues[i + 2] + rB; val = val > 255 ? 255 : val < 0 ? 0 : val; rgbValues[i + 2] = (byte)val; val = gA * rgbValues[i + 1] + gB; val = val > 255 ? 255 : val < 0 ? 0 : val; rgbValues[i + 1] = (byte)val; val = bA * rgbValues[i] + bB; val = val > 255 ? 255 : val < 0 ? 0 : val; rgbValues[i] = (byte)val; } System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); clonedImage.UnlockBits(bitmapData); return(clonedImage); }