【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 = 0; j < bitmap.Height; j++)
 {
     for (int i = 0; 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),可參考在下的另一篇博文:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM