【C#/WPF】调节图像的HSL(色相Hue、饱和度Saturation、明亮度Lightness)
先说概念:
HSL是一种描述颜色的方式,其他颜色描述方式还有大家熟悉的RGB值。HSL三个字母分别表示图像的Hue色相、Saturation饱和度、Lightness明亮度。
需求:
制作一个面板,包含三个滑动条,拖动滑动条可以修改目标图片的HSL值。即模仿PS中类似的功能,如下图:
方案一:遍历所有像素点,修改每个点的HSL值。
参考:https://stackoverflow.com/questions/10332363/getting-hue-from-every-pixel-in-an-image
for (int j = ; j < bitmap.Height; j++)
{
for (int i = ; i < bitmap.Width; i++)
{
System.Drawing.Color color = bitmap.GetPixel(i, j);
// todo something
}
}
经测试遍历像素点修改效率极低,卡得难以忍受。还是找第三方库吧。
方案二:使用三方库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 --> Bitmap
public 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循环遍历所有像素点高效很多!
2017.7.17更新:
项目有了新的需求,还要做调节图像的对比度(Contrast),就顺便把之前落下的GIF补上。同时因为做对比度时没有再使用这个ImageMagick插件,所以打算新开一篇博文 http://www.cnblogs.com/guxin/p/csharp-wpf-adjust-image-contrast.html
调节色相(Hue)的动图:
调节饱和度(Saturation)的动图:
调节明度(Lightness)的动图:
另外,关于调节图像的对比度(Contrast),可参考在下的另一篇博文:
【C#/WPF】调节图像的HSL(色相Hue、饱和度Saturation、明亮度Lightness)的更多相关文章
- 【C#/WPF】调节图像的HSL(色相、饱和度、明亮度)
原文:[C#/WPF]调节图像的HSL(色相.饱和度.明亮度) 先说概念: HSL是一种描述颜色的方式(其他颜色描述方式还有大家熟悉的RGB值).HSL三个字母分别表示图像的Hue色相.Saturat ...
- 【C#/WPF】调节图像的对比度(Contrast)
关于对比度: 调节对比度直观感受是,高对比度的图像明暗关系更明显,色彩更鲜艳:低对比度的图像表面像是蒙上一层灰,色彩不鲜艳. 需求: 制作一个面板,一个滑动条,拖动滑动条可以修改目标图片的对比度. 资 ...
- 图像处理术语解释:灰度、色相、饱和度、亮度、明度、阿尔法通道、HSL、HSV、RGBA、ARGB和PRGBA以及Premultiplied Alpha(Alpha预乘)等基础概念详解
☞ ░ 前往老猿Python博文目录 ░ 一.引言 由于老猿以前没接触过图像处理,在阅读moviepy代码时,对类的有些处理方法代码看不懂是什么含义,为此花了4天时间查阅了大量资料,并加以自己的理解和 ...
- 借助Photoshop,Illustrator等设计软件进行WPF图形图像的绘制
原文:借助Photoshop,Illustrator等设计软件进行WPF图形图像的绘制 本文所示例子是借助第三方设计软件,制作复杂的矢量图形,转成与XAML酷似的SVG,再转换成xaml而实现的. 这 ...
- UnityShader:HSV(色相,饱和度,亮度)转换
http://blog.csdn.net/costfine/article/details/46930473 发现其实美术调整颜色的时候大部分都是调整的HSV,因为可以方便的分别调整色相(hue).饱 ...
- WPF图形图像相关类
BitmapMetadata类: 继承自抽象类ImageMetadata,包含图像的原数据信息,如相机型号.图像修改程序名称.拍照日期.拍照地点等.ImageSoure类包含ImageMetadata ...
- 【C#/WPF】图像数据格式转换时,透明度丢失的问题
问题:工作中涉及到图像的数据类型转换,经常转着转着发现,到了哪一步图像的透明度丢失了! 例如,Bitmap转BitmapImage的经典代码如下: public static BitmapImage ...
- WPF将RGB转为HSL的工具类
class HSLColor { private int _alpha = 255; public int _hue = 0; public d ...
- 精通D3.js笔记
DOM常用属性 innerHTML: 元素标签内部的文本. innerText outerHTML outerText nodeName: 节点名称 parentNode: 父节点 nextSibli ...
随机推荐
- mysql中内存的使用与分配
mysql的内存分配,是调优的重中之重,所以必须搞清楚内存是怎么分配的 mysql> show global variables like '%buffer%'; +-------------- ...
- 锋利的jQuery(第二版)源码下载地址
书上给的http://cssrain.sinaapp.com无法访问 问作者邮箱要的: 第1版源码:百度云盘下载:http://pan.baidu.com/share/link?shareid=104 ...
- HDUOJ--1865 1string
1sting Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- tensorflow的警告
W c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\platform\cpu_featur ...
- 一种时间复杂度为O(n)的排序方法(转载)
原文地址:http://my.oschina.net/u/158457/blog/28536 排序的方法很特别,有点类似插入排序的味道 先看下代码 public class Sort { privat ...
- Shell中重定向<<EOF注意事项
作者:iamlaosong 我们常常在shell脚本程序中用<<EOF重定向输入.将我们输入的命令字符串作为一个运行程序的输入,这样,我们就不须要在那个程序环境中手工输入命令,以便自己主动 ...
- 利用WGET下载文件,并保存到指定目录
wget是Linux上一个非常不错的下载指令,也算是Linux工作者常用的指令之一 而这个指令我想在各大系统都预设有提供,包括了Ubuntu.Fedora等,而一般来说,要使用wget下载档案,只需要 ...
- spring mvc 依赖包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop&l ...
- mysql-5.7.20 版本的 mysql-group-replication 可用性测试报告
一.喜迎 mysql-5.7.20 事实上mysql-group-replication 功能是在mysql-5.7.17这个版本上引入的,它实现了mysql各个结点间数据强一致性, 这个也成为了我 ...
- Python学习笔记11:标准库之文件管理(os包,shutil包)
1 os包 os包包含各种各样的函数,以实现操作系统的很多功能.这个包很庞杂.os包的一些命令就是用于文件管理. 我们这里列出最经常使用的: mkdir(path) 创建新文件夹.path为一个字符串 ...