65.9K
CodeProject 正在变化。 阅读更多。
Home

色相饱和度亮度滤镜

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (11投票s)

2007年6月6日

CPOL

3分钟阅读

viewsIcon

80403

downloadIcon

5243

一个 VB.NET 类,用于实现图像的色相/饱和度/亮度调整。

Screenshot - HSL_Filter_Form_100.jpg

引言

这个 Visual Basic .NET 类实现了一个图像滤镜,可以改变图像的色相、饱和度和/或亮度。提供了一个小型演示项目。

背景

我一直在研究 "一个 C# 图像增强滤镜库" 这篇文章中描述的图像滤镜,并将代码从 C 转换为 VB.NET。 然后,我使用 "使用 C# 和 GDI+ 的傻瓜图像处理第 1 部分 - 逐像素滤镜" 中描述的滤镜扩展了我的库。 由于以上文章都没有描述色相/饱和度/亮度 (HSL) 滤镜,所以我决定编写自己的类。

滤镜类基础

所有滤镜共享相同的接口 IFilter,定义一个接受图像作为输入并在退出时返回经过滤的图像的函数。

Public Interface IFilter

Function ExecuteFilter( _
         ByVal inputImage As System.Drawing.Image) As System.Drawing.Image

End Interface

BasicFilter 实现了 IFilter 接口,并用作所有滤镜的基类。

Public MustInherit Class BasicFilter _
       Implements IFilter

   ''' <summary />
   ''' Background color. Default is a transparent background.
   ''' </summary />
   Private _bgColor As Color = Color.FromArgb(0, 0, 0, 0)
   ''' <summary />
   ''' Interpolation mode. Default is highest quality.
   ''' </summary />
   Private _interpolation As InterpolationMode = _
            InterpolationMode.HighQualityBicubic

   ''' <summary />
   ''' Get or set background color.
   ''' </summary />
   Public Property BackgroundColor() As Color
      Get
         Return _bgColor
      End Get
      Set(ByVal value As Color)
         _bgColor = value
      End Set
   End Property
 
   ''' <summary />
   ''' Get or set resize interpolation mode.
   ''' </summary />
   Public Property Interpolation() As InterpolationMode
      Get
         Return _interpolation
      End Get
      Set(ByVal value As InterpolationMode)
         _interpolation = value
      End Set
   End Property
 
   ''' <summary />
   ''' Execute filter function and return new filtered image.
   ''' </summary />
   ''' Image to be filtered.
   ''' <returns />New filtered image.</returns />
   Public MustOverride Function ExecuteFilter( _
            ByVal img As System.Drawing.Image) _
            As System.Drawing.Image Implements IFilter.ExecuteFilter

End Class

大多数滤镜都具有相同的 ExecuteFilter 函数,该函数目前仅处理某些图像格式。

Public Overrides Function ExecuteFilter( _
         ByVal img As System.Drawing.Image) _
         As System.Drawing.Image
   Select Case img.PixelFormat
      Case PixelFormat.Format16bppGrayScale
         Return img
      Case PixelFormat.Format24bppRgb, _
               PixelFormat.Format32bppArgb, PixelFormat.Format32bppRgb
         Return ExecuteRgb8(img)
      Case PixelFormat.Format48bppRgb
         Return img
      Case Else
         Return img
   End Select
End Function

由于我喜欢掌控一切并了解发生了什么,因此我不使用颜色矩阵来转换图像,而是读取/修改/写入像素,这证明与使用颜色矩阵一样快。 我在我的滤镜中使用类似的框架来访问像素。

Private Function ExecuteXXX(ByVal img As System.Drawing.Image) As System.Drawing.Image
   'Create new image for result.
   Dim result As Bitmap = New Bitmap(img)
   result.SetResolution(img.HorizontalResolution, img.VerticalResolution)
   Dim bmpData As BitmapData = result.LockBits( _
                  New Rectangle(0, 0, result.Width, result.Height), _
                  ImageLockMode.ReadWrite, img.PixelFormat)
   Dim pixelBytes As Integer = _
            System.Drawing.Image.GetPixelFormatSize(img.PixelFormat) \ 8
   'Get the address of the first line.
   Dim ptr As IntPtr = bmpData.Scan0
   Dim size As Integer = bmpData.Stride * result.Height
   Dim pixels(size - 1) As Byte
   Dim index As Integer
   'Copy the RGB values into the array.
   System.Runtime.InteropServices.Marshal.Copy(ptr, pixels, 0, size)
   'Main loop.
   For row As Integer = 0 To result.Height - 1
      For col As Integer = 0 To result.Width - 1
         index = (row * bmpData.Stride) + (col * pixelBytes)

         R = pixels(index + 2)
         G = pixels(index + 1)
         B = pixels(index + 0)

         'Do filtering.
         '...
 
      Next
   Next
   'Copy the RGB values back to the bitmap
   System.Runtime.InteropServices.Marshal.Copy(pixels, 0, ptr, size)
   'Unlock the bits.
   result.UnlockBits(bmpData)
   Return result
End Function

实现 HSL 滤镜

基本思路是将 RGB 值转换为 HSL 值,根据用户设置更改 HSL 值,然后将 HSL 值转换回 RGB 值。 HSL 颜色空间在 Wikipedia 中有详细描述,您还可以在 EasyRGB 找到 C 代码的转换链接。 将 C 代码转换为 VB.NET 非常简单,并且滤镜运行良好。

为了测试滤镜,我使用了一个 256 像素的正方形 JPEG 图像,并且我从控制台应用程序运行滤镜,同时测量过滤时间。 执行时间比其他滤镜稍长,但不是很关键。 直到在 2288x1712 像素的图像上使用滤镜。 执行时间超过 16 秒。

通过纸、笔和一些基本的数学运算,我发现 EasyRGB 代码中的许多计算是不必要的。 使用 HSL 的完整范围而不是范围 [0..1] 也节省了一些时间。 通过将单独函数中的代码放入主循环中,实现了最大的时间节省。 有趣的是,当我尝试使用整数算术进行部分计算时,执行时间反而增加了。 看来类型转换花费了相当多的时间。

最终执行时间约为 1.5 秒,仅为原始执行时间的 10%。

使用代码

代码非常简单。 滤镜接受的参数如下:

  • Hue 是一个介于 0 和 360 之间的值; 实际上,任何值都将被接受,然后转换为适当的范围。
  • SaturationLightness 允许的值介于 -100 和 +100 之间(以百分比表示)。
  • BackgroundColorInterpolation 参数在此滤镜中没有意义。
'Define compression for saved image.
Dim myEncoderParameters As EncoderParameters = New EncoderParameters(1)
myEncoderParameters.Param(0) = _
         New EncoderParameter(Encoder.Quality, CType(90L, Int32))
'Load image.
Dim imgOriginal As Image = _
         Image.FromFile("C:\Documents and Settings\Test.jpg")
'Define filter and parameters.
Dim imgFilter As HSLFilter = New HSLFilter()
imgFilter.Hue = 50
imgFilter.Saturation = 0
imgFilter.Lightness = 0
'Execute filter.
Dim imgFiltered As Image = imgFilter.ExecuteFilter(imgOriginal)
'Save filtered image as jpeg.
imgFiltered.Save("C:\Documents and Settings\Test_HSL.jpg", _
         Library.Image.Functions.GetEncoderInfo(ImageFormat.Jpeg), _
         myEncoderParameters)

关注点

实现此滤镜是优化代码以提高速度的一个很好的例子。 我学到了很多关于颜色和访问图像数据的知识。

历史

  • 2007-06-08:饱和度和亮度比例已更改。 添加了演示项目。
  • 2007-06-05:1.00 版。
© . All rights reserved.