![]() |
Languages »
VB.NET »
General
Intermediate
Hue Saturation Lightness FilterBy Miran.UhanVB.NET class implementing image Hue/Saturation/Lightning adjustment. |
VB 7.x, VB 8.0, Windows, .NET 2.0, GDI+, VS2005, Dev
|
||||||||
|
Advanced Search |
|
|
|
||||||||||||||||

Visual Basic .NET class implements image filter which can change hue, saturation and/or lightness of the image. Small demo project is provided.
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.
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
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.
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)
Implementing this filter is a good example of optimizing the code for speed. I learned a lot about colors and accessing image data.
2007-06-08 Saturation and lightness scale changed. Demo project added.
2007-06-05 Version 1.00
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
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 |