Click here to Skip to main content
6,295,667 members and growing! (15,292 online)
Email Password   helpLost your password?
Languages » VB.NET » General     Intermediate

Hue Saturation Lightness Filter

By Miran.Uhan

VB.NET class implementing image Hue/Saturation/Lightning adjustment.
VB 7.x, VB 8.0, Windows, .NET 2.0, GDI+, VS2005, Dev
Posted:6 Jun 2007
Views:16,487
Bookmarked:23 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
3 votes for this article.
Popularity: 1.99 Rating: 4.17 out of 5
1 vote, 33.3%
1

2

3
1 vote, 33.3%
4
1 vote, 33.3%
5

Screenshot - HSL_Filter_Form_100.jpg

Introduction

Visual Basic .NET class implements image filter which can change hue, saturation and/or lightness of the image. Small demo project is provided.

Background

I was playing with image filters described in article "A C# image enhancement filters library" and transferring code from C to VB.NET. Then I extend my library with filters described in "Image Processing for Dummies with C# and GDI+ Part 1 - Per Pixel Filters". Since none of above articles describes hue/saturation/lightness (HSL) filter, I decided to write my own class.

Filter class basics

All the filters share same interface IFilter, defining single function accepting image as input and returning filtered image on exit.

Public Interface IFilter

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

End Interface

Class BasicFilter is implementing IFilter interface and is used as basic class for all filters.

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 />
   ''' "img" />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

Most of the filters have the same ExecuteFilter function, which at the moment only handles certain image formats.

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

Since I like to be in control and understand what's going on, I don't use color matrix to transform image, but rather read/modify/write pixels, which was proved to be as fast as using color matrix. I'm using similar frame in my filters to access pixels.

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

Implementing HSL filter

Basic idea was to convert RGB values to HSL values, change HSL values according to user settings and then convert HSL values back to RGB values. HSL color space is well described at Wikipedia where you can also find link to C code for conversion at EasyRGB. Converting C code to VB.NET was trivial and filter was working just fine.

For testing the filters I'm using jpeg image 256 pixels square and I'm running filters from console application, also measuring filtering time. Execution time was slightly longer than with other filters, but not so critical. Until filter was used on image size 2288x1712 pixels. Execution time was more than 16 seconds.

With paper, pencil and some basic math I found that lot of calculations in EasyRGB code are not necessary. Using full range for HSL instead of range [0..1) also saved some time. Biggest time saving was achieved by putting code that was in separate function to main loop. It is interesting that when I tried to do part of calculations with integer arithmetic execution time increased, it seems type conversions took quite some time.

Final execution time is approximately 1.5 seconds, which is barely 10% of original execution time.

Using the code

Code is fairly simple. Filter accepts parameters as follows.

  • Hue is a value between 0 and 360, actualy any value will be accepted and then transformed into proper range.
  • Saturation and Lightness have allowed values between -100 and +100 (in percent).
  • BackgroundColor and Interpolation parameters have no meaning within this filter.

'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)

Points of Interest

Implementing this filter is a good example of optimizing the code for speed. I learned a lot about colors and accessing image data.

History

2007-06-08 Saturation and lightness scale changed. Demo project added.

2007-06-05 Version 1.00

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Miran.Uhan


Member

Occupation: Engineer
Location: Slovenia Slovenia

Other popular VB.NET articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 4 of 4 (Total in Forum: 4) (Refresh)FirstPrevNext
GeneralNice PinmemberAndrewVos6:13 12 Jun '07  
GeneralBroken Download Link PinmemberGraGra_3315:53 6 Jun '07  
GeneralRe: Broken Download Link PinmemberMiran.Uhan0:49 8 Jun '07  
GeneralRe: Broken Download Link PinmemberGraGra_331:24 13 Jun '07  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 6 Jun 2007
Editor:
Copyright 2007 by Miran.Uhan
Everything else Copyright © CodeProject, 1999-2009
Web16 | Advertise on the Code Project