|
' Matrix Operations for Image Processing
' Converted from C to VB.NET By Headkaze (headkaze [at] gmail.com)
' Thanks to Paul Haeberli
' http://www.sgi.com/misc/grafica/matrix/
Option Explicit On
Option Strict On
Imports System.Drawing.Imaging
Module ColourProcessing
Const RLUM As Single = 0.3086
Const GLUM As Single = 0.6094
Const BLUM As Single = 0.082
' MultiplyMatrix - multiply two matricies
Public Sub MultiplyMatrix(ByRef a As ColorMatrix, ByRef b As ColorMatrix, ByRef c As ColorMatrix)
Dim x, y As Integer
Dim temp As New ColorMatrix
For y = 0 To 4
For x = 0 To 4
temp(y, x) = b(y, 0) * a(0, x) _
+ b(y, 1) * a(1, x) _
+ b(y, 2) * a(2, x) _
+ b(y, 3) * a(3, x) _
+ b(y, 4) * a(4, x)
Next
Next
For y = 0 To 4
For x = 0 To 4
c(y, x) = temp(y, x)
Next
Next
End Sub
' CreateIdentityMatrix - make an identity matrix
Public Sub CreateIdentityMatrix(ByRef matrix As ColorMatrix)
matrix = New ColorMatrix(New Single()() _
{New Single() {1, 0, 0, 0, 0}, _
New Single() {0, 1, 0, 0, 0}, _
New Single() {0, 0, 1, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
End Sub
' Transform3dPointMatrix - transform a 3D point using a matrix
Public Sub Transform3dPointMatrix(ByRef matrix As ColorMatrix, ByVal x As Single, ByVal y As Single, ByVal z As Single, ByRef tx As Single, ByRef ty As Single, ByRef tz As Single)
tx = x * matrix(0, 0) + y * matrix(1, 0) + z * matrix(2, 0) + matrix(3, 0)
ty = x * matrix(0, 1) + y * matrix(1, 1) + z * matrix(2, 1) + matrix(3, 1)
tz = x * matrix(0, 2) + y * matrix(1, 2) + z * matrix(2, 2) + matrix(3, 2)
End Sub
' ColourScaleMatrix - make a color scale matrix
Public Sub ColourScaleMatrix(ByRef mat As ColorMatrix, ByVal rscale As Single, ByVal gscale As Single, ByVal bscale As Single)
Dim nmat As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {rscale, 0, 0, 0, 0}, _
New Single() {0, gscale, 0, 0, 0}, _
New Single() {0, 0, bscale, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
MultiplyMatrix(nmat, mat, mat)
End Sub
' LuminanceMatrix - make a luminance matrix
Public Sub LuminanceMatrix(ByRef mat As ColorMatrix)
Dim rwgt, gwgt, bwgt As Single
rwgt = RLUM
gwgt = GLUM
bwgt = BLUM
Dim mmat As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {rwgt, rwgt, rwgt, 0, 0}, _
New Single() {gwgt, gwgt, gwgt, 0, 0}, _
New Single() {bwgt, bwgt, bwgt, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
MultiplyMatrix(mmat, mat, mat)
End Sub
' SaturateMatrix - make a saturation matrix
Public Sub SaturateMatrix(ByRef mat As ColorMatrix, ByVal sat As Single)
Dim a, b, c, d, e, f, g, h, i As Single
Dim rwgt, gwgt, bwgt As Single
rwgt = RLUM
gwgt = GLUM
bwgt = BLUM
a = CSng((1.0# - sat) * rwgt + sat)
b = CSng((1.0# - sat) * rwgt)
c = CSng((1.0# - sat) * rwgt)
d = CSng((1.0# - sat) * gwgt)
e = CSng((1.0# - sat) * gwgt + sat)
f = CSng((1.0# - sat) * gwgt)
g = CSng((1.0# - sat) * bwgt)
h = CSng((1.0# - sat) * bwgt)
i = CSng((1.0# - sat) * bwgt + sat)
Dim mmat As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {a, b, c, 0, 0}, _
New Single() {d, e, f, 0, 0}, _
New Single() {g, h, i, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
MultiplyMatrix(mmat, mat, mat)
End Sub
' OffsetMatrix - offset r, g, and b
Public Sub OffsetMatrix(ByRef mat As ColorMatrix, ByVal roffset As Single, ByVal goffset As Single, ByVal boffset As Single)
Dim mmat As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {1, 0, 0, 0, 0}, _
New Single() {0, 1, 0, 0, 0}, _
New Single() {0, 0, 1, 0, 0}, _
New Single() {roffset, goffset, boffset, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
MultiplyMatrix(mmat, mat, mat)
End Sub
' XRotateMatrix - rotate about the x (red) axis
Public Sub XRotateMatrix(ByRef mat As ColorMatrix, ByVal rs As Single, ByVal rc As Single)
Dim mmat As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {1, 0, 0, 0, 0}, _
New Single() {0, rc, rs, 0, 0}, _
New Single() {0, -rs, rc, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
MultiplyMatrix(mmat, mat, mat)
End Sub
' YRotateMatrix - rotate about the y (green) axis
Public Sub YRotateMatrix(ByRef mat As ColorMatrix, ByVal rs As Single, ByVal rc As Single)
Dim mmat As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {rc, 0, -rs, 0, 0}, _
New Single() {0, 1, 0, 0, 0}, _
New Single() {rs, 0, rc, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
MultiplyMatrix(mmat, mat, mat)
End Sub
' ZRotateMatrix - rotate about the z (blue) axis
Public Sub ZRotateMatrix(ByRef mat As ColorMatrix, ByVal rs As Single, ByVal rc As Single)
Dim mmat As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {rc, rs, 0, 0, 0}, _
New Single() {-rs, rc, 0, 0, 0}, _
New Single() {0, 0, 1, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
MultiplyMatrix(mmat, mat, mat)
End Sub
' ZShearMatrix - shear z using x and y.
Public Sub ZShearMatrix(ByRef mat As ColorMatrix, ByVal dx As Single, ByVal dy As Single)
Dim mmat As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {1, 0, dx, 0, 0}, _
New Single() {0, 1, dy, 0, 0}, _
New Single() {0, 0, 1, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
MultiplyMatrix(mmat, mat, mat)
End Sub
' HueRotateMatrix - rotate the hue, while maintaining luminance.
Public Sub HueRotateMatrix(ByRef mat As ColorMatrix, ByVal rot As Single)
Dim mmat As ColorMatrix
Dim mag As Single
Dim lx, ly, lz As Single
Dim xrs, xrc As Single
Dim yrs, yrc As Single
Dim zrs, zrc As Single
Dim zsx, zsy As Single
CreateIdentityMatrix(mmat)
' rotate the grey vector into positive Z
mag = CSng(Math.Sqrt(2.0))
xrs = CSng(1.0# / mag)
xrc = CSng(1.0# / mag)
XRotateMatrix(mmat, xrs, xrc)
mag = CSng(Math.Sqrt(3.0#))
yrs = CSng(-1.0# / mag)
yrc = CSng(Math.Sqrt(2.0#) / mag)
YRotateMatrix(mmat, yrs, yrc)
' shear the space to make the luminance plane horizontal
Transform3dPointMatrix(mmat, RLUM, GLUM, BLUM, lx, ly, lz)
zsx = lx / lz
zsy = ly / lz
ZShearMatrix(mmat, zsx, zsy)
' rotate the hue
zrs = CSng(Math.Sin(rot * Math.PI / 180.0#))
zrc = CSng(Math.Cos(rot * Math.PI / 180.0#))
ZRotateMatrix(mmat, zrs, zrc)
' unshear the space to put the luminance plane back
ZShearMatrix(mmat, -zsx, -zsy)
' rotate the grey vector back into place
YRotateMatrix(mmat, -yrs, yrc)
XRotateMatrix(mmat, -xrs, xrc)
MultiplyMatrix(mmat, mat, mat)
End Sub
Public Function DrawImageWithMatrix(ByVal img As Image, ByVal cm As ColorMatrix) As Boolean
Try
Dim bmp As New Bitmap(img) ' create a copy of the source image
Dim imgattr As New ImageAttributes
Dim rc As New Rectangle(0, 0, img.Width, img.Height)
Dim g As Graphics = Graphics.FromImage(img)
' associate the ColorMatrix object with an ImageAttributes object
imgattr.SetColorMatrix(cm)
' draw the copy of the source image back over the original image,
'applying the ColorMatrix
g.DrawImage(bmp, rc, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgattr)
g.Dispose()
Return True
Catch
Return False
End Try
End Function
End Module
|
|
|
|
|
What are the range of values that can be passed into for the HueRotateMatrix Value parameter? -180 to 180? -1 to 1? 0 to 360?
|
|
|
|
|
HueRotateMatrix() takes 0 to 360 (0 being normal)
SaturateMatrix() takes 0 to 2 (1 being normal)
ColourScaleMatrix() (Brightness) takes 0 to 255 (I think, havn't tried it yet)
Check this link for more information
http://www.sgi.com/misc/grafica/matrix/[^]
|
|
|
|
|
Sub OffsetMatrix change:
Dim mmat as ColorMatrix = _
New ColorMatrix(New Single()() _
{New Single() {1.0, 0.0, 0.0, 0.0, 0.0}, _
New Single() {0.0, 1.0, 0.0, 0.0, 0.0}, _
New Single() {0.0, 0.0, 1.0, 0.0, 0.0}, _
New Single() {0.0, 0.0, 0.0, 1.0, 0.0}, _
New Single() {roffset, goffset, boffset, 0.0, 1.0}})
|
|
|
|
|
Public Function Translucent(ByVal img As Image) As Boolean
Dim cm As New Imaging.ColorMatrix(New Single()() { _
New Single() {1.0F, 0.0F, 0.0F, 0.0F, 0.0F}, _
New Single() {0.0F, 1.0F, 0.0F, 0.0F, 0.0F}, _
New Single() {0.0F, 0.0F, 1.0F, 0.0F, 0.0F}, _
New Single() {0.0F, 0.0F, 0.0F, 0.0F, 0.0F}, _
New Single() {0.0F, 0.0F, 0.0F, 0.4F, 1.0F}})
Return draw_adjusted_image(img, cm)
End Function
Thanks,
Michaelas10;)
|
|
|
|
|
Hay There,
This article looks to have what i need. I copied the code to get started and now i get an error Type expected
My code looks like:
Imports System.Drawing.Imaging
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<system.diagnostics.debuggerstepthrough()> Private Sub InitializeComponent()
components = New System.ComponentModel.Container
Me.Text = "Form1"
End Sub
#End Region
Public Function translate(ByVal img As Image, ByVal red As Single, _
ByVal green As Single, ByVal blue As Single, _
Optional ByVal alpha As Single = 0) As Boolean
Dim sr, sg, sb, sa As Single
' noramlize the color components to 1
sr = red / 255
sg = green / 255
sb = blue / 255
sa = alpha / 255
' create the color matrix
Dim cm As New ColorMatrix(New Single()() _
{New Single() {1, 0, 0, 0, 0}, _
New Single() {0, 1, 0, 0, 0}, _
New Single() {0, 0, 1, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {sr, sg, sb, sa, 1}})
' apply the matrix to the image
Return draw_adjusted_image(img, cm)
End Function
End Class
VB.NET tells me that the the type expected error is under ColorMatrix
Can anyone tell me what i'am doing wrong?
|
|
|
|
|
Hi BigBertB,
you're missing the path to ColorMatrix. Either use an imports-statement (Imports System.Drawing.Drawing2D) at the top of your class or precede the full path when declaring your cm-variable.
BTW - in cases like this, hit F2 (Object Browser) and locate an object. Use the "Find Symbol"-command to search for the object you don't know the path to (either by Edit/Find and Replace/Find Symbol or using the commandbar's button on the RHS)
Cheers,
Olaf
|
|
|
|
|
Imports System.Drawing.Imaging.ColorMatrix
|
|
|
|
|
Michael,
This is a great (if not the better!) article for color adjustment. Thank You a lot for share it with us.
Best ragards
Khe ps
Merry Christmas
|
|
|
|
|
Good article, I understand what's going on, but how on earth do you impliment it. I've been playing with it for about an hour and I still can't get it to display the image with the new Colormatrix...
|
|
|
|
|
Michael,
Thank you for the excellent article.
I've noticed a little issue with the way you define your negative matrix. With your definition of the matrix pure black colors (0,0,0,x) will not be inverted. Some other strange color "artifacts" could be produced as well.
I believe that a better negative could be produced by subtracting current color components from 255 (from 1 in the matrix world). To achieve this you should scale components by -1 and then translate them by 1. Following matrix should do the trick:
{-1, 0, 0, 0, 0}
{ 0, -1, 0, 0, 0}
{ 0, 0, -1, 0, 0}
{ 0, 0, 0, 1, 0}
{ 1, 1, 1, 0, 1}
Thank you.
|
|
|
|
|
Yeah, I came up with the same matrix you did. It does produce a better looking negative image.
|
|
|
|
|
With the original definition all the values where out by 1, so when a color should have been 255 it was 0. For some reason when the values in the last row are 0 the results from the matrix are rolled over (eg 256 becomes 0) but when the values in the last row are no zero the results are clamped (eg 256 becomes 255). I'm not sure if this is a bug or feature but the original example shouldn't work at all because the colors all come out to be negative so should really be clamped at zero.
|
|
|
|
|
Hi
i have tried this code. its working okay. i have a question. when i change the color of picture by giving red, green, blue color values. it displays the new picture on the picturebox. but when i minimize the form and then maximize it, the picture is no more there.
how can i save the changed picture because i need to store this new changed picture in database.
thanks a lot in advance.
bye
|
|
|
|
|
It really depends on how you are using the code. It sounds like you are updating an image using the image property of a picturebox. I would suggest loading the image from disk into an image object and then making modifications to that object. You can then resave the image to disk, display the results in a picturebox, etc. Otherwise, I would suggest reading up on the paint related events and properties of a picturebox control.
-Michael Combs
|
|
|
|
|
hey Michael
sorry, actually i m new to VB.NET. i have worked much on Java. now i m switching to VB.NET just to change taste
anyway, can u write a small code to save this picture.
i hope u will not mind it
thanks a lot in advance
|
|
|
|
|
The Bitmap class inherits from Image, and Image has a Save method. That should be enough.
Basic example:
<br />
Public Sub SaveImage(ByVal img As System.Drawing.Image, ByVal filename As String)<br />
img.Save(filename)<br />
End Sub<br />
|
|
|
|
|
Is there way, using matrix functions, to compute the average R, G and B values for a image. I have 10s or 1000s of images that I need to calculate avg RGB for and looping through each pixel is very slow.
|
|
|
|
|
Not as a whole. You can change each individual pixel to the average of r, g and b
|
|
|
|
|
Have you looked into the lockbits function? This is very fast. If you're using getpixel you will notice a huge speed improvement.
|
|
|
|
|
Hi,
I had try the code n it works fine. However, is there a way to manipulate the pixel/images ( as in change a 24 bit image to 8 bit image or select all the even number of pixel bit...etc) in Vb.net and how??
|
|
|
|
|
|
I would also be interested in this.
I tried to find some articles about this topic, but without usable results ;(
|
|
|
|
|
Option Explicit On
Option Strict On
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices
Public Class Colourise
' Provide public access to the picture's byte data.
Public ImageBytes() As Byte
Public RowSizeBytes As Integer
Public Const PixelDataSize As Integer = 32
' Save a reference to the bitmap.
Public Sub New(ByVal bm As Bitmap)
m_Bitmap = bm
End Sub
' A reference to the Bitmap.
Private m_Bitmap As Bitmap
' Bitmap data.
Private m_BitmapData As BitmapData
' Lock the bitmap's data.
Private Sub LockBitmap()
' Lock the bitmap data.
Dim bounds As Rectangle = New Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height)
m_BitmapData = m_Bitmap.LockBits(bounds, Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppArgb)
RowSizeBytes = m_BitmapData.Stride
' Allocate room for the data.
Dim total_size As Integer = m_BitmapData.Stride * m_BitmapData.Height
ReDim ImageBytes(total_size)
' Copy the data into the ImageBytes array.
Marshal.Copy(m_BitmapData.Scan0, ImageBytes, 0, total_size)
End Sub
' Copy the data back into the Bitmap
' and release resources.
Private Sub UnlockBitmap()
' Copy the data back into the bitmap.
Dim total_size As Integer = m_BitmapData.Stride * m_BitmapData.Height
Marshal.Copy(ImageBytes, 0, m_BitmapData.Scan0, total_size)
' Unlock the bitmap.
m_Bitmap.UnlockBits(m_BitmapData)
' Release resources.
ImageBytes = Nothing
m_BitmapData = Nothing
End Sub
Private Sub RGBToHLS(ByVal r As Long, ByVal g As Long, ByVal b As Long, ByRef h As Single, ByRef s As Single, ByRef l As Single)
Dim Max As Single
Dim Min As Single
Dim delta As Single
Dim rR As Single, rG As Single, rB As Single
rR = CSng(r / 255) : rG = CSng(g / 255) : rB = CSng(b / 255)
'{Given: rgb each in [0,1].
' Desired: h in [0,360] and s in [0,1], except if s=0, then h=UNDEFINED.}
Max = Maximum(rR, rG, rB)
Min = Minimum(rR, rG, rB)
l = (Max + Min) / 2 '{This is the lightness}
'{Next calculate saturation}
If Max = Min Then
'begin {Acrhomatic case}
s = 0
h = 0
'end {Acrhomatic case}
Else
'begin {Chromatic case}
'{First calculate the saturation.}
If l <= 0.5 Then
s = (Max - Min) / (Max + Min)
Else
s = (Max - Min) / (2 - Max - Min)
End If
'{Next calculate the hue.}
delta = Max - Min
If rR = Max Then
h = (rG - rB) / delta '{Resulting color is between yellow and magenta}
ElseIf rG = Max Then
h = 2 + (rB - rR) / delta '{Resulting color is between cyan and yellow}
ElseIf rB = Max Then
h = 4 + (rR - rG) / delta '{Resulting color is between magenta and cyan}
End If
'Debug.Print h
'h = h * 60
'If h < 0# Then
' h = h + 360 '{Make degrees be nonnegative}
'End If
'end {Chromatic Case}
End If
'end {RGB_to_HLS}
End Sub
Private Sub HLSToRGB(ByVal h As Single, ByVal s As Single, ByVal l As Single, ByRef r As Long, ByRef g As Long, ByRef b As Long)
Dim rR As Single, rG As Single, rB As Single
Dim Min As Single, Max As Single
If s = 0 Then
' Achromatic case:
rR = l : rG = l : rB = l
Else
' Chromatic case:
' delta = Max-Min
If l <= 0.5 Then
's = (Max - Min) / (Max + Min)
' Get Min value:
Min = l * (1 - s)
Else
's = (Max - Min) / (2 - Max - Min)
' Get Min value:
Min = l - s * (1 - l)
End If
' Get the Max value:
Max = 2 * l - Min
' Now depending on sector we can evaluate the h,l,s:
If (h < 1) Then
rR = Max
If (h < 0) Then
rG = Min
rB = rG - h * (Max - Min)
Else
rB = Min
rG = h * (Max - Min) + rB
End If
ElseIf (h < 3) Then
rG = Max
If (h < 2) Then
rB = Min
rR = rB - (h - 2) * (Max - Min)
Else
rR = Min
rB = (h - 2) * (Max - Min) + rR
End If
Else
rB = Max
If (h < 4) Then
rR = Min
rG = rR - (h - 4) * (Max - Min)
Else
rG = Min
rR = (h - 4) * (Max - Min) + rG
End If
End If
End If
r = CLng(rR * 255) : g = CLng(rG * 255) : b = CLng(rB * 255)
End Sub
Private Function Maximum(ByVal rR As Single, ByVal rG As Single, ByVal rB As Single) As Single
If (rR > rG) Then
If (rR > rB) Then
Maximum = rR
Else
Maximum = rB
End If
Else
If (rB > rG) Then
Maximum = rB
Else
Maximum = rG
End If
End If
End Function
Private Function Minimum(ByVal rR As Single, ByVal rG As Single, ByVal rB As Single) As Single
If (rR < rG) Then
If (rR < rB) Then
Minimum = rR
Else
Minimum = rB
End If
Else
If (rB < rG) Then
Minimum = rB
Else
Minimum = rG
End If
End If
End Function
Public Sub ColouriseBitmap(ByVal lHue As Long, ByVal lSaturation As Long)
' Perform colourisation
Dim x As Long
Dim y As Long
Dim xEnd As Long
Dim yEnd As Integer
Dim Jump As Integer
Dim h As Single
Dim s As Single
Dim l As Single
Dim lR As Long
Dim lG As Long
Dim lB As Long
Dim hDN As Single
Dim sDN As Single
' Calculate denormalized Hue, Saturation & Intensity:
hDN = CSng(((lHue * 6.0#) / 255.0#) - 1.0#)
sDN = CSng(lSaturation / 255.0#)
' Lock the bitmap.
LockBitmap()
xEnd = RowSizeBytes
yEnd = m_Bitmap.Height
Jump = PixelDataSize \ 8
For x = 0 To xEnd - 1 Step Jump
For y = 0 To yEnd - 1
' Obtain the luminance:
RGBToHLS(ImageBytes(CInt(x + 2 + (y * xEnd))), ImageBytes(CInt(x + 1 + (y * xEnd))), ImageBytes(CInt(x + (y * xEnd))), h, s, l)
' Now get the new colour using the input hue and saturation
HLSToRGB(hDN, sDN, l, lR, lG, lB)
ImageBytes(CInt(x + 2 + (y * xEnd))) = CByte(lR)
ImageBytes(CInt(x + 1 + (y * xEnd))) = CByte(lG)
ImageBytes(CInt(x + (y * xEnd))) = CByte(lB)
Next y
Next x
UnlockBitmap()
End Sub
Public Sub RotateHue(ByVal incHue As Single)
' Saturation only applies to grey scale images. Otherwise saturation
' is taken from the colour.
Dim x As Long, y As Long
Dim xEnd As Long, yEnd As Long
Dim lB As Long, lG As Long, lR As Long
Dim h As Single, s As Single, l As Single
Dim Jump As Integer
Dim hDN As Single
' Lock the bitmap.
LockBitmap()
xEnd = RowSizeBytes
yEnd = m_Bitmap.Height
Jump = PixelDataSize \ 8
For x = 0 To xEnd - 1 Step Jump
For y = 0 To yEnd - 1
RGBToHLS(ImageBytes(CInt(x + 2 + (y * xEnd))), ImageBytes(CInt(x + 1 + (y * xEnd))), ImageBytes(CInt(x + (y * xEnd))), h, s, l)
h = h + incHue
If (h > 5) Then h = h - 6
If (h < -1) Then h = h + 6
HLSToRGB(h, s, l, lR, lG, lB)
ImageBytes(CInt(x + 2 + (y * xEnd))) = CByte(lR)
ImageBytes(CInt(x + 1 + (y * xEnd))) = CByte(lG)
ImageBytes(CInt(x + (y * xEnd))) = CByte(lB)
Next y
Next x
UnlockBitmap()
End Sub
End Class
|
|
|
|
|
Maybe I'm missing something here, but the colormatrix method described here only works as a 'display transformation', the actual data in the bitmap is not modified but just applied when rendering the image to screen. This means (if I am correct) that for real image processing you still need to modify image data pixel by pixel, and that in that case you cannot use the colormatrix ... That's what I did using unmanaged pointers because setPixel and GetPixel are soooo slooow, maybe I will post an article about it.
Regarding color, again a very shortsighted implementation of MS:
-the only color data that can be stored in 8-bit integers per color channel are gamma-corrected values; you need about 12-13 bits for linear light values. This means basically image processing is performed on non-linear values (R*G*B*), with no provisions to perform it on linear values (RGB), e.g. needed when doing tranformations from one color space to another.
-the NTSC luminosity you are speaking of is just one possibility, as there are literally thousands of RGB spaces out there, and only a very small chance your image is using the NTSC primaries, which are quite old and certainly not representative of a modern computer monitor. sRGB primaries are probably much more suitable (ITU Rec. 709). To compute lightness L* from that you have to perform quite a number of operations: sR*G*B* -> sRGB -> CIE XYZ -> CIE L*a*b*. Again, very little is foreseen for such operations in GDI+, at least that I know of. Is this correct?
If both my assumptions are correct, although your article is well written, the GDI+ implementation seems flawed in my eyes for real (physics based or vision based) image processing. It seems MS wasn't concerned with the basics, it just had to look good (and go fast, although thats a joke using managed datatypes).
Yves Vander Haeghen
|
|
|
|
|