【C#/WPF】调节图像的HSL(色相、饱和度、明亮度)

2017-05-29 19:54:27来源:CSDN作者:qq_18995513人点击

先说概念:
HSL是一种描述颜色的方式(其他颜色描述方式还有大家熟悉的RGB值)。HSL三个字母分别表示图像的Hue色相、Saturation饱和度、Lightness明亮度。

需求:
制作一个面板,包含三个滑动条,拖动滑动条可以修改目标图片的HSL值。即模仿PS中类似的功能,如下图:

这里写图片描述


方案一:遍历所有像素点,修改每个点的HSL值。

参考:https://stackoverflow.com/questions/10332363/getting-hue-from-every-pixel-in-an-image

前台界面:一个Image控件显示目标图片,一个Button按钮点击一下降低一点图片亮度。

<StackPanel Orientation="Vertical">    <Image x:Name="img" Width="800" Height="300" Stretch="Uniform" Source="C:/Users/Administrator/Documents/Visual Studio 2015/Projects/WpfApplication1/WpfApplication1/Resources/Images/1.png"/>    <Button Click="Button_Click" Width="100" Height="40" Content="调暗" FontSize="22"/></StackPanel>

后台代码:

// 亮度降低private void Button_Click(object sender, RoutedEventArgs e){    // 获得图源的Bitmap    Bitmap bitmap = UtilSet.ImageSourceToBitmap(img.Source); // img是前台Image控件    // 遍历Bitmap中的每个像素点,像素点执行操作    for (int j = 0; j < bitmap.Height; j++)    {        for (int i = 0; i < bitmap.Width; i++)        {            System.Drawing.Color oldColor = bitmap.GetPixel(i, j);            System.Drawing.Color newColor = HSLHelper.ModifyBrightness(oldColor, 1.05);            bitmap.SetPixel(i, j, newColor);        }    }    ImageSource newSource =  UtilSet.ConvertBitmapToImageSource(bitmap);    img.Source = newSource;    MessageBox.Show("完成");}// 工具方法:ImageSource --> Bitmappublic static System.Drawing.Bitmap ImageSourceToBitmap(ImageSource imageSource){    BitmapSource m = (BitmapSource)imageSource;    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(m.PixelWidth, m.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);    System.Drawing.Imaging.BitmapData data = bmp.LockBits(    new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);    m.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); bmp.UnlockBits(data);    return bmp;}

经测试,该方法可以修改图片的Lightness明亮度,但是遍历像素点修改效率极低,卡得难以忍受。还是找第三方库吧。


方案二:使用三方库MagickImage.Net

众所周知MagickImage是一个及其强大又多功能的图像处理库,而且有多个平台下对应的版本(如Java、PHP)。

步骤:

1、 在Visual Studio的NuGet中搜索、下载、安装MagickImage。选最上面最高下载量这个。

这里写图片描述

2、随便打开一个类,输入ImageMagick.MagickImage并导包后,按下F12查看该类有哪些方法能实现我们的需求。在该类中按Ctrl + F搜索hue,即可看到该类的确提供了修改图像HSL的方法!
这里写图片描述
(文件很长,中间省略。。。)
这里写图片描述

3、观察上图这个Modelate()方法的传参,是结构体ImageMagick.Percentage,该结构体的描述跟图片像素无关。看下图,该Percentage构造函数中传参的是一个数字,可知该Modelate()方法修改的HSL值是原图的HSL值的一个百分比!
这里写图片描述

4、再观察被操作的图像ImageMagick.MagickImage这个类,该类提供了toBitmap()和toBitmapSource()方法,前者Bitmap是通用的图像类型,后者BitmapSource是WPF使用的图像类型,说明该类连图像类型转换的功能都准备好了,前置条件一切OK!

5、了解所需函数的使用方法后,开始做Demo。界面如下,一个Image控件显示图片,三个Slider滑动条分别调节Hue色相、Saturation饱和度、Lightness明亮度。

<DockPanel Width="400" Height="150" VerticalAlignment="Top" Margin="0,20,0,0">    <Grid>        <Grid.RowDefinitions>            <RowDefinition Height="1*"/>            <RowDefinition Height="1*"/>            <RowDefinition Height="1*"/>        </Grid.RowDefinitions>        <Grid.ColumnDefinitions>            <ColumnDefinition Width="1*"/>            <ColumnDefinition Width="3*"/>        </Grid.ColumnDefinitions>        <Label Content="色相" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="18" />        <Slider x:Name="slider0" Value="{Binding SliderValue0}" Minimum="0" Maximum="200" VerticalAlignment="Center" Grid.Row="0" Grid.Column="1"/>        <Label Content="饱和度" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="18" />        <Slider x:Name="slider1" Value="{Binding SliderValue1}" Minimum="0" Maximum="200" VerticalAlignment="Center" Grid.Row="1" Grid.Column="1"/>        <Label Content="明度" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="18" />        <Slider x:Name="slider2" Value="{Binding SliderValue2}" Minimum="0" Maximum="200" VerticalAlignment="Center" Grid.Row="2" Grid.Column="1"/>    </Grid></DockPanel>

界面如下图:

这里写图片描述

注意,因为Modelate()方法的传参要求是百分比,所以Slider滑动条的两头的值为0,200(表示0%和200%),默认位置在中间100(表示100%,即HSL未修改的状态)。

Controller层给这三个Slider滑动条添加滑动事件,下面只以修改Hue色相为例:

private ImageMagick.MagickImage originalMagickImage; // 图层图像修改前的状态// 先执行该方法!private void Init(){    // 滑动条的修改是在原图的基础上修改!    Bitmap bitmap = ImageSourceToBitmap(img.Source); // img是前台Image控件    originalMagickImage = new ImageMagick.MagickImage(bitmap);}/// <summary>/// 调节色相。在原图的基础上增加/减少百分比/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Hue_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e){    // 只调整图像的Hue色相值    ImageMagick.Percentage brightness = new ImageMagick.Percentage(100); // 100%表示不改变该属性    ImageMagick.Percentage saturation = new ImageMagick.Percentage(100);    ImageMagick.Percentage hue = new ImageMagick.Percentage(e.NewValue); // 滑动条范围值0%~200%    ImageMagick.MagickImage newImage = new ImageMagick.MagickImage(originalMagickImage); // 相当于深复制    newImage.Modulate(brightness, saturation, hue);    // 重新给Image控件赋值新图像    BitmapSource bitmapImage = newImage.ToBitmapSource();    img.Source = imageSource;}// 工具方法:ImageSource --> Bitmappublic System.Drawing.Bitmap ImageSourceToBitmap(ImageSource imageSource){    BitmapSource m = (BitmapSource)imageSource;    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(m.PixelWidth, m.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);    System.Drawing.Imaging.BitmapData data = bmp.LockBits(    new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);    m.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); bmp.UnlockBits(data);    return bmp;}

经测试,该方法效率很高!拖拽滑动条立马能看到HSL修改后的效果!显著比两个For循环遍历所有像素点高效很多!


待补充:之后再补一个GIF,看得更直观一点。

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台