【C#/WPF】调节图像的对比度(Contrast)
关于对比度:
调节对比度直观感受是,高对比度的图像明暗关系更明显,色彩更鲜艳;低对比度的图像表面像是蒙上一层灰,色彩不鲜艳。
需求:
制作一个面板,一个滑动条,拖动滑动条可以修改目标图片的对比度。
资料参考:
界面滑动条两端的值是-30~30,默认处于中间位置0。已知目标图像的Bitmap数据。
- 修改Bitmap的对比度。
- 将修改之后的Bitmap重新赋值给界面Image控件显示。
/// <summary> /// 调节对比度 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Contrast_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { // 滑动条是值是-30~30 // originalBitmap是目标图像的Bitmap int threshold = (int)e.NewValue; Bitmap newBitmap = BitmapHelper.Contrast(originalBitmap, threshold); // 重新给Image控件赋值新图像 image.Source = SystemUtils.ConvertBitmapToBitmapImage(newBitmap); }
下面调节图像对比度的工具方法:
/// <summary> /// 代码来自:https://softwarebydefault.com/2013/04/20/image-contrast/ /// </summary> public static class BitmapHelper { /// <summary> /// 调节图像的对比度 /// </summary> /// <param name="sourceBitmap"></param> /// <param name="threshold">阈值,通过该参数控制调节</param> /// <returns></returns> public static Bitmap Contrast(this Bitmap sourceBitmap, int threshold) { BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height]; Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length); sourceBitmap.UnlockBits(sourceData); double contrastLevel = Math.Pow((100.0 + threshold) / 100.0, 2); double blue = 0; double green = 0; double red = 0; for (int k = 0; k + 4 < pixelBuffer.Length; k += 4) { blue = ((((pixelBuffer[k] / 255.0) - 0.5) * contrastLevel) + 0.5) * 255.0; green = ((((pixelBuffer[k + 1] / 255.0) - 0.5) * contrastLevel) + 0.5) * 255.0; red = ((((pixelBuffer[k + 2] / 255.0) - 0.5) * contrastLevel) + 0.5) * 255.0; if (blue > 255) { blue = 255; } else if (blue < 0) { blue = 0; } if (green > 255) { green = 255; } else if (green < 0) { green = 0; } if (red > 255) { red = 255; } else if (red < 0) { red = 0; } pixelBuffer[k] = (byte)blue; pixelBuffer[k + 1] = (byte)green; pixelBuffer[k + 2] = (byte)red; } Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height); BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); Marshal.Copy(pixelBuffer, 0, resultData.Scan0, pixelBuffer.Length); resultBitmap.UnlockBits(resultData); return resultBitmap; } }
下面是将Bitmap转换为BitmapImage的工具方法,以供WPF的Image控件使用图像:
public static class SystemUtils
{ /// <summary> /// 转换类型:Bitmap --> BitmapImage /// <summary> /// <returns></returns> public static BitmapImage ConvertBitmapToBitmapImage(Bitmap bitmap) { using (MemoryStream stream = new MemoryStream()) { bitmap.Save(stream, ImageFormat.Png); stream.Position = 0; BitmapImage bi = new BitmapImage(); bi.BeginInit(); // According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed." // Force the bitmap to load right now so we can dispose the stream. bi.CacheOption = BitmapCacheOption.OnLoad; bi.StreamSource = stream; bi.EndInit(); bi.Freeze(); return bi; } } }
测试效果如下:
另外,关于图像的HSL(色相、饱和度、明度)的调节,可参考在下的另一篇博文:
参考资料: