-
Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
I must confess, I suck at UI design. I need to design a form like Nero, and I'm totally lost. :(
How do you make a form like Nero ? (with user-selectable semitransparent color)
For the buttons, I have found a code in PSC (winner of last month). But it is taking too much time to load on older systems.
any idea how to do this ?
Quote:
Originally Posted by Nero
Quote:
Originally Posted by Windows Media Player
-
Re: Fast code to change Hue/Saturation of a image [UI like Nero]
I have found 2 fast codes for changing hue/saturation of my custom skin.
Advanced Graphics Routines 3.3 : Superfast but it relies on a C++ dll. (The author didn't give full source of the dll. I haven't checked if the dll source has the Hue changing source or not.)
vbAccelerator NeoCaption Component v2.0 : Good code, but somtimes my system simply restarts when I run the demo.
Anyone knows of any other fast code to change Hue/Saturation of an image ?
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
AFAIK, the fastest way to change an image in VB is to use DIB sections.
It's awkward to explain, so I'll just link you to places that do it well.
The explanation from DemonSpectre is pretty good.
The examples from vbaccelerator are very useful - and at least one of them shows the kind of thing you want.
edit: I've moved this to G&G as requested.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Thanks.
Yes, I've thought about GetDIBits. (I was hoping for something more faster. :p)
I'll give your links a try and post again.
Edit: Thanks for moving the thread.
Btw, as it is now in G&G, Jacobe, no Dx please. :D
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Using DMA is the fastest way in VB without using DX or OpenGL.
-
1 Attachment(s)
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Here's a class that I've been working on for a while.
It's designed to manipulate pixels on a picturebox as fast as possible.
I haven't had time to add a Hue function to it yet, but you can probably find some examples if you search the forums.
Here's how you use it:
VB Code:
Dim DMA as clsDMA
Set DMA = New clsDMA
DMA.Init MyPicturebox
'Here you can mainpulate pixels using the various functions from the class.
MyPicturebox.Refresh
DMA.Destruct
-
1 Attachment(s)
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Thank you everyone ! :thumb:
I'm using cyborg's DMA class.
I've added a picturebox to show possible colors and added scrolbars to change H/S/B.
But,
1. The color of the skin (scrollbar position) doesn't match with the 'color viewer' picturebox.
2. Can't use Brightness.
3. What is the Max value of S and L ?
4. What would be the initial value of the scrollbars ?
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by cyborg
It's designed to manipulate pixels on a picturebox as fast as possible.
Just giving tips on how to improve it as there are a lot of things that slow things down a fair bit:- Use one dimensional array. Multidimensional arrays in VB6 are slow.
- Avoid creating extra functions for simple tasks, especially in a class module: BoundValue is unnecessary.
- Precalculate multiplications that do not change and that are used multiple times (StartX * 3, X * 3...)
- In Cls function: instead of using CopyMemory for line per line, first copy the first line, then copy the two top lines that you have, then copy four lines etc. until the remaining line count is smaller than the rows you are about to copy. This increases the clearing speed of larger images a lot.
- Consider having no error check on simple functions such as SetPixel; or provide an alternative function.
- Getting and setting the whole image data at once could be useful.
- You could have two SafeArrays pointing to the same image: the byte array and the long array. Use faster choice (the long array) when possible.
If you get rid of multidimensionality (which is the #1 thing slowing things down), you can do Y and X for loops like this:
VB Code:
' method one: when you don't need to get user input Y
For Y = 0 To UBound(Array) Step Width
For X = 0 To Width - 1
Pos = X + Y
' ...
Next X
Next Y
' method two: when you get Y position as user input
YX = StartY * Width
For Y = StartY To EndY
For X = StartX To EndX
Pos = X + YX
' ...
Next X
YX = YX + Width
Next Y
This minimizes the amount of calculation you need in loops. The bigger the image, the bigger the speed gain.
:)
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Thanks for that Merri, that's very helpful.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by Merri
In Cls function: instead of using CopyMemory for line per line, first copy the first line, then copy the two top lines that you have, then copy four lines etc. until the remaining line count is smaller than the rows you are about to copy. This increases the clearing speed of larger images a lot.
And first check if RGB are all zero, in which case you can do the whole thing in one hit using ZeroMemory(). Or provide separate Blank and Fill methods.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by penagate
And first check if RGB are all zero, in which case you can do the whole thing in one hit using ZeroMemory(). Or provide separate Blank and Fill methods.
This code crashes the program:
VB Code:
ZeroMemory Pic(LBound(Pic)), UBound(Pic) - LBound(Pic)
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by cyborg
Here's a class that I've been working on for a while.
It's designed to manipulate pixels on a picturebox as fast as possible.
I haven't had time to add a Hue function to it yet, but you can probably find some examples if you search the forums.
Here's how you use it:
VB Code:
Dim DMA as clsDMA
Set DMA = New clsDMA
DMA.Init MyPicturebox
'Here you can mainpulate pixels using the various functions from the class.
MyPicturebox.Refresh
DMA.Destruct
I've been trying it out but maybe I'm doing something wrong. I want to change the brightness of a grayscale image and instead, it gets converted to a coloured image. Here's what I've done with a picturebox and a scrollbar:
VB Code:
'Picture1.Picture has a grayscale image
'loaded at design time
Dim DMA As clsDMA
Private Sub Form_Activate()
Set DMA = New clsDMA
DMA.Init Picture1
HScroll1.Min = 0
HScroll1.Max = 200
HScroll1.Value = 100
HScroll1.LargeChange = 20
HScroll1.SmallChange = 1
End Sub
Private Sub Form_Unload(Cancel As Integer)
DMA.Destruct
End
End Sub
Private Sub HScroll1_Change()
DMA.Brightness HScroll1.Value * 0.01
Picture1.Refresh
End Sub
Private Sub HScroll1_Scroll()
DMA.Brightness HScroll1.Value * 0.01
Picture1.Refresh
End Sub
-
1 Attachment(s)
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by krtxmrtz
I've been trying it out but maybe I'm doing something wrong. I want to change the brightness of a grayscale image and instead, it gets converted to a coloured image....
For example, for a scrollbar value of 1, the parameter passed to the brighness function is 0.01 and this is the result:
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
There seems to be a bug in the brightness filter then. I'll have a look at it after work.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by cyborg
There seems to be a bug in the brightness filter then. I'll have a look at it after work.
Thank you, Merri directed me to your post suggesting I try to learn something about the SAFEARRAY technique, but on the other hand I badly need some code to change the brightness and contrast of a large (15000 x 3000 pixels) grayscale image in a picturebox. (Actually, this picturebox is invisible and part of it is BitBlt'd to a smaller visible picturebox when 2 scrollbars are clicked/dragged on).
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Thank you everyone for your help.
I started this thread, but right now I don't have time to work on it. :cry:
I'll start working on it as soon as I found some time. :(
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
iPrank: Too bad you don't have time. I've been working on a Hue/Sat/val function, but it's a bit buggy and slow. I'll post here when it's working correctly.
krtxmrtz: I don't really understand the SA-technique to a 100% yet, so most of that code I got from Electroman's DMA examples.
I've been reworking the image effects and I'm going to create another class that handles image arrays and effects alone and let the DMA code be in a seperate class.
I think this will make things easier to handle images and also to load images.
If you really need that brightness function right now, I can post the new code so you can try if it's working better. Otherwhise I'll do the image class first.
Do you know a good way of altering the contrast?
-
1 Attachment(s)
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
I figured out how to create a contrast function...
Here's what I've got so far.
Some of the functions in clsDMA might not work anymore since I haven't cleaned up the source since I reworked it.
It's pretty slow if you run it from the IDE. Compile it first and then run it.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
try this - it works and is fast
update - commented out, in cmdGo_Clidk() .. 'MyPicturebox.Picture = LoadPicture(App.Path & "\back.jpg")
Code:
Option Explicit
Private Declare Function LockWindowUpdate Lib "user32" (ByVal hwndLock As Long) As Long
Private Type RGBQUAD
Blue As Byte
Green As Byte
Red As Byte
alpha As Byte
End Type
Private Type HSVTYPE
h_hue As Single
s_saturation As Single
v_value As Single
End Type
Private Type Bitmap
bmType As Long
bmWidth As Long
bmHeight As Long
bmWidthBytes As Long
bmPlanes As Integer
bmBitsPixel As Integer
bmBits As Long
End Type
Private Type SAFEARRAY1D
cDims As Integer
fFeatures As Integer
cbElements As Long
cLocks As Long
pvData As Long
cElements As Long
lLbound As Long
End Type
Dim mPicOriginal() As Byte
Dim mPicO_Copied As Boolean
Dim mBMP As Bitmap
Private Declare Function VarPtrArray Lib "msvbvm50.dll" Alias "VarPtr" (Ptr() As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Sub cmdGo_Click()
LockWindowUpdate MyPicturebox.hWnd
'MyPicturebox.Picture = LoadPicture(App.Path & "\back.jpg")
Dim X As Long
Dim Y As Long
'''''''''
Dim ImageDMA() As Byte
Dim HSVT As HSVTYPE
Dim RGBQ As RGBQUAD
Dim lSA As SAFEARRAY1D
Dim targetHSV_Hue As Single
Dim targetHSV_Sat As Single
Dim targetHSV_Val As Single
Dim TopLeft As Long
Dim AddRight As Long
Dim X_Plus_2 As Long
targetHSV_Sat = hsSat.Value / Abs(hsSat.Max - hsSat.Min)
targetHSV_Val = hsL.Value / Abs(hsL.Max - hsL.Min)
targetHSV_Hue = 1530 * (hsHue.Value / Abs(hsHue.Max - hsHue.Min))
Hook_Array MyPicturebox.Picture, ImageDMA, lSA, AddRight
If mBMP.bmBits <> 0 Then
If Not mPicO_Copied Then
Y = mBMP.bmWidthBytes * mBMP.bmHeight - 1
ReDim mPicOriginal(Y)
For X = 0 To Y
mPicOriginal(X) = ImageDMA(X)
Next
mPicO_Copied = True
End If
End If
TopLeft = mBMP.bmWidthBytes * (mBMP.bmHeight - 1)
For Y = 0 To TopLeft Step mBMP.bmWidthBytes
For X = Y To Y + AddRight Step lSA.cbElements
X_Plus_2 = X + 2
If mPicOriginal(X) <> 255 _
And mPicOriginal(X_Plus_2) <> 255 Then
RGBQ.Blue = mPicOriginal(X)
RGBQUAD_From_HSV RGBQ, _
targetHSV_Hue, _
targetHSV_Sat, _
targetHSV_Val * RGBQ.Blue
ImageDMA(X) = RGBQ.Blue
ImageDMA(X + 1) = RGBQ.Green
ImageDMA(X_Plus_2) = RGBQ.Red
End If
'=============================
Next X
Next Y
Unhook_Array ImageDMA
MyPicturebox.Refresh
LockWindowUpdate 0
End Sub
Private Sub DrawHuePalate()
Dim X As Long
Dim lColor As Long
For X = 0 To 360
lColor = HSBToRGB(HSBToLong(X, 200, 240))
Picture1.PSet (X, 1), lColor
Picture1.PSet (X, 2), lColor
Picture1.PSet (X, 3), lColor
'Picture1.PSet (x, 4), lColor
Picture1.PSet (X, 4), lColor
Picture1.PSet (X, 5), lColor
Picture1.PSet (X, 6), lColor
Picture1.PSet (X, 7), lColor
Picture1.PSet (X, 8), lColor
Picture1.PSet (X, 9), lColor
Picture1.PSet (X, 10), lColor
Next
End Sub
Private Sub Form_Load()
MyPicturebox.Picture = LoadPicture(App.Path & "\back.jpg")
DrawHuePalate
End Sub
Private Sub hsHue_Change()
Label1.Caption = hsHue.Value
cmdGo_Click
End Sub
Private Sub hsHue_Scroll()
hsHue_Change
End Sub
Private Sub hsL_Change()
Label3.Caption = hsL.Value
' DMA.Brightness hsL.Value
cmdGo_Click
End Sub
Private Sub hsL_Scroll()
hsL_Change
End Sub
Private Sub hsSat_Change()
Label2.Caption = hsSat.Value
cmdGo_Click
End Sub
Private Sub hsSat_Scroll()
hsSat_Change
End Sub
Private Sub RGBQUAD_From_HSV(RGB1 As RGBQUAD, hue_0_To_1530 As Single, ByVal saturation_0_To_1 As Single, value_0_To_255 As Single)
Dim hue_and_sat As Single
Dim value1 As Single
Dim maxim As Single
Dim diff1 As Single
Dim subt As Single
If value_0_To_255 > 0 Then
value1 = value_0_To_255 + 0.5
If saturation_0_To_1 > 0 Then
maxim = hue_0_To_1530 - 1530& * Int(hue_0_To_1530 / 1530&)
diff1 = saturation_0_To_1 * value_0_To_255
subt = value1 - diff1
diff1 = diff1 / 255
If maxim <= 510 Then
RGB1.Blue = Int(subt)
If maxim <= 255 Then
hue_and_sat = maxim * diff1
RGB1.Red = Int(value1)
RGB1.Green = Int(subt + hue_and_sat)
Else
hue_and_sat = (maxim - 255) * diff1
RGB1.Green = Int(value1)
RGB1.Red = Int(value1 - hue_and_sat)
End If
ElseIf maxim <= 1020 Then
RGB1.Red = Int(subt)
If maxim <= 765 Then
hue_and_sat = (maxim - 510) * diff1
RGB1.Green = Int(value1)
RGB1.Blue = Int(subt + hue_and_sat)
Else
hue_and_sat = (maxim - 765) * diff1
RGB1.Blue = Int(value1)
RGB1.Green = Int(value1 - hue_and_sat)
End If
Else
RGB1.Green = Int(subt)
If maxim <= 1275 Then
hue_and_sat = (maxim - 1020) * diff1
RGB1.Blue = Int(value1)
RGB1.Red = Int(subt + hue_and_sat)
Else
hue_and_sat = (maxim - 1275) * diff1
RGB1.Red = Int(value1)
RGB1.Blue = Int(value1 - hue_and_sat)
End If
End If
Else 'saturation_0_To_1 <= 0
RGB1.Red = Int(value1)
RGB1.Green = Int(value1)
RGB1.Blue = Int(value1)
End If
Else 'value_0_To_255 <= 0
RGB1.Red = 0
RGB1.Green = 0
RGB1.Blue = 0
End If
End Sub
Private Sub Hook_Array(ByVal picDisp As StdPicture, pImg() As Byte, pSA As SAFEARRAY1D, pRetAddRight As Long)
GetObjectAPI picDisp, Len(mBMP), mBMP
pSA.cDims = 1
pSA.cbElements = mBMP.bmBitsPixel / 8
pSA.cElements = mBMP.bmHeight * mBMP.bmWidthBytes
pSA.pvData = mBMP.bmBits
CopyMemory ByVal VarPtrArray(pImg), VarPtr(pSA), 4
pRetAddRight = pSA.cbElements * (mBMP.bmWidth - 1)
End Sub
Private Sub Unhook_Array(pImg() As Byte)
CopyMemory ByVal VarPtrArray(pImg), 0&, 4
End Sub
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
You forgot to add the HSBToLong function in that code
Also, what min and max values should hsHue, hsSat and hsL have?
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by cyborg
krtxmrtz: I don't really understand the SA-technique to a 100% yet, so most of that code I got from Electroman's DMA examples.
I've downloaded and tried out Electroman's code, which is very nice, but unfortunately it only works when the screen colour configuration is set to 24 bit.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by krtxmrtz
I've download and tried out Electroman's code, which is very nice, but unfortunately it only works when the screen colour configuration is set to 24 bit.
Yeah, that's a shame. If I could understand it better, I would add support for different bit-depths. That would also be good in photoshop-like programs, so the user can make 32/24/16/8/1-bit images.
If you (or anyone else) finds out how, please tell me!
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Where is the code? One thing that comes to my mind: it doesn't matter what format a DIB image is in, because Windows takes care of converting it to the screen settings. Thus you could always use 32-bit DIB, Windows makes sure it is displayed in a lower bitdepth when it is displayed somewhere.
As for 8-bit images, they're handled pretty much differently as you need to assign and handle pallette. Maybe 1-bit images have a pallette as well, I've never worked with them.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by Merri
Where is the code? One thing that comes to my mind: it doesn't matter what format a DIB image is in, because Windows takes care of converting it to the screen settings. Thus you could always use 32-bit DIB, Windows makes sure it is displayed in a lower bitdepth when it is displayed somewhere.
As for 8-bit images, they're handled pretty much differently as you need to assign and handle pallette. Maybe 1-bit images have a pallette as well, I've never worked with them.
I was referring to Electroman's second example here
Now, what's the difference between DMA and using DIBs? I have examined some code related to both methods but they all use a lot of API calls that I don't really understand for the most part.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
DMA (Direct Memory Access) allows you to use an array to access data anywhere in the memory. This data can be in whatever format. Basically you change array header of an existing array to point into whereever you wish in the memory to gain access there and to be able to manipulate the data. You can use this to gain faster, immediate and direct access to whatever you wish.
DIB (Device Independent Bitmap) is the format graphics are stored in memory by Windows. Basically exactly the same the BMP format is, BMPs are like a dump from memory to harddisk in to a file. The only way to handle a DIB created by API is via DMA or by using existing APIs to copy data from there, but this later method is slower.
Now, both arrays and DIBs have their own header. Arrays in VB6 use SAFEARRAY as a header and DIBs have a generic BITMAP header.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by Merri
Maybe 1-bit images have a pallette as well, I've never worked with them.
1-bit images are monochrome. The pixels are either white or black. You could use a pallette if you'd like to use different colors than black/white.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by Merri
...The only way to handle a DIB created by API is via DMA or by using existing APIs to copy data from there, but this later method is slower...
I see, so if speed is really an issue then I should go the DMA way... but this seems way too complicated, if I have to write code allowing for all the possible screen configurations!
I wonder if anything could be gained in terms of speed by using DIBs in a c++ dll... not that I'd know how to do it anyway, as I've no experience with DIBs.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by krtxmrtz
I wonder if anything could be gained in terms of speed by using DIBs in a c++ dll... not that I'd know how to do it anyway, as I've no experience with DIBs.
I'm no expert but I think that when using DIBs, you use an external array which you copy from the DIB using API.
Then you copy it to the place where the DIB is stored in the memory using API.
So the reading and writing speed of the DIB could probably not be improved by using a C++ DLL.
Although the altering of the array could be done in C++ (which I did in a previous project). This is faster than VB, especially when doing things like alpha-blending, which uses pretty heavy calculations.
If you need any help with that, I can probably find that previous project and show you some of the code.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by krtxmrtz
but this seems way too complicated, if I have to write code allowing for all the possible screen configurations!
As far as I know, you don't have to. Windows takes care of screen configurations. As long as you make sure the DIB is 32-bit, there are no problems. What format do you use to load the image? JPEG ought to open as 32-bit. It might be Windows/VB loads all images 32-bit to make them easier to handle (you don't get paletted pixels when you SetPixel on an image that was a GIF). So you only need to handle 32-bit.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
Quote:
Originally Posted by Merri
As far as I know, you don't have to. Windows takes care of screen configurations. As long as you make sure the DIB is 32-bit, there are no problems. What format do you use to load the image? JPEG ought to open as 32-bit. It might be Windows/VB loads all images 32-bit to make them easier to handle (you don't get paletted pixels when you SetPixel on an image that was a GIF). So you only need to handle 32-bit.
As I've mentioned in posts #22 & #25 above, I was expecting to use Electroman's code to take a look at the insights of DMA applied to bitmap handling, but his code didn't work for certain screen settings, e.g. 16-bit colour. Maybe the demo was not intended to be all that much comprehensive and some code was missing to take care of the screen resolution!?
As I'm new to all this I'd need a tutorial or a fully working demo to start learning from.
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
I've just come across a thread where DirectX is recommended as a very fast way for handling graphics. Could this be an alternative to DMA or DIB graphics?
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
I don't know wheather it is possible in DirectX or not, but I guess Dx will do it more faster.
All my apps are either business apps or system utilities. I'll never use DirextX just to change skin of these apps. :(
-
Re: Fast code to change Hue/Saturation of an image [UI like Nero/WMP]
DX is fast as it provides a lot of predone assembly optimized graphics handling routines, I guess hue and saturation are included. The drawback is that DirectX becomes an absolute requirement if you use the functions it provides. I'm not sure but it might be business desktops don't have it; atleast don't have a recent version.
In the other hand, properly optimized VB6 code is very well fast enough. Can't beat assembler, but optimized pure C/C++ implementations are only marginally faster in most cases.
I haven't got myself interested enough in to fixing the DMA & DIB class module, because I already have my own routines that I customize for each case I need them. And surprisinly enough, I often use 8-bit paletted images.