-
1 Attachment(s)
Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Anothe!
Greetings,
hope all are fine..
after many days researching/coding/trying/getting help form here i mange to do that on vb6 (long time ago)
now i am started to learning and using vb.net (2010)
But i failed to convert those code to work on vb.net. Rather than that, i hope/believe vb.net has better built in function to do the same effect with out so much API Calls...
i have attached the vb6 source code...
please some one check and help me out...
best regards
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Don't just attach some .zip and expect people to look thru it just to post help. You should try and tell us where you're getting stuck and post the code of the areas you're having troubles in. By attaching a .zip it seems as if you never even attempted.
(Inb4 FunkyDexter PMs me saying my post is aggressive).
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
Toph
Don't just attach some .zip and expect people to look thru it just to post help. You should try and tell us where you're getting stuck and post the code of the areas you're having troubles in. By attaching a .zip it seems as if you never even attempted.
(Inb4 FunkyDexter PMs me saying my post is aggressive).
thanks a lot for your reply sir..
sir, the a source project that has a module (for GDI+ api call) a form with 3 picture box and a play button with a timer ...
how you can understand if you don't see/run the project..
however thanks for your help though and i hope/believe here is good enough people to eager to help me out that will not refrain them just for a zip file...
best regards
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
I would love to assist you, but I have never had the VB6 runtime installed. Therefore I cannot run your project. What type of image transition would you like to do, could you possibly show a video of what you're attempting?
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
dday9
I would love to assist you, but I have never had the VB6 runtime installed. Therefore I cannot run your project. What type of image transition would you like to do, could you possibly show a video of what you're attempting?
tanks.. that could be a good idea..
let me try to record a video...
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
See if this project does what you want. It is a nice little control.
Image Transition Effect
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
<I would have posted a little sooner but got interrupted by work while working on the post. See a few more have responded.>
The code as written is doing some unnecessary work.
It only supports dealing with a 32-bit rgb image but it is breaking the maskcolor into three bytes, r,g and b and breaking the pixels from the mask image into mr, mg, mb, and then seeing if all three are equal.
If they are then it then copies the 32-bit pixel value from one image to another three times!
Code:
For Y = 0 To UBound(pixelsMask)
' Get mask color
maskColor = pixelsMask(Y)
mr = maskColor And &HFF&
mg = (maskColor And &HFF00&) \ &H100&
mb = (maskColor And &HFF0000) \ &H10000
' See if we need to change this pixel.
If mr = r Then
If mg = g Then
If mb = b Then
pixelsDst(Y) = pixelsSrc(Y) '<---- Copy the same pixel
pixelsDst(Y) = pixelsSrc(Y) '<---- to the same place
pixelsDst(Y) = pixelsSrc(Y) '<---- three times
End If
End If
End If
Next Y
I assume the code somewhere along the line was working with a byte array, rather then a long array, so had to copy the three bytes (), (+1), (+2), but that is no longer the case so you should only have that assignment once, rather than three times.
Also, since you're not working with bytes, then the splitting out the rgb values to separate variables for compare is also wasted.
Just compare the maskColor to the pixel color of the Mask image directly.
Code:
For Y = 0 To UBound(pixelsMask)
' Get mask color
' mr = maskColor And &HFF&
' mg = (maskColor And &HFF00&) \ &H100&
' mb = (maskColor And &HFF0000) \ &H10000
' See if we need to change this pixel.
' If mr = r Then
' If mg = g Then
' If mb = b Then
If pixelsMask(Y) = maskColor Then
pixelsDst(Y) = pixelsSrc(Y)
' pixelsDst(Y) = pixelsSrc(Y)
' pixelsDst(Y) = pixelsSrc(Y)
End If
' End If
' End If
Next Y
Doing that, in the IDE on my machine cut the transition of your example from around 2.5 seconds, to around .57 seconds, and outside the IDE as an executable takes about .11 seconds.
Perhaps you don't want it to be that efficient because the transitions is less of a transition, more of a flash. You will probably have to induce some speed throttling based on time feedback.
Anyway, there are a few posts out there for .Net where you copy the pixels of an image into an array and manipulate them fairly easily, so what you are currently doing should be easy to replicate.
I don't have time to track that part down but there are a number of other people that can help.
For those who haven't looked at the code, it is a fairly simple operation.
You have two images, and a grayscale mask image.
You have an outer loop that loops through the values 0 to 255.
A sub is called, passing that 0 to 255 value, and that sub loops through all the pixels in the grayscale mask, and if the grayscale pixel level matches the 0 to 255 value passed, copies the source image pixel to the destination picture.
So, the result is, your source image is copied to your destination image in 256 passes (destination image refreshed after each pass) so you see the destination updating in a pattern determined by the grayscale pixel values in the mask image.
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
dday9
could you possibly show a video of what you're attempting?
yes
here is the link: i just uploaded on youtube:
Code:
https://www.youtube.com/watch?v=hx10MKCC2EQ
thanks again for your reply though
best regards
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
passel
<I would have posted a little sooner but got interrupted by work while working on the post. See a few more have responded.>
thanks a lot for your help again a lot..
but sir, as i told, i am not interested in that code and that is old model/vb6 model code..
i post this project to wondering whether is there vb.net easier/faster/better function to do that :)
thanks again for your reply sir..
best regards
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
I realize that, but if someone was to use the vb6 code as a template to port to VB.Net, it helps eliminate some unnecessary extraneous code that shouldn't be accidentally ported as a straight translation of code to code. A quick understanding of what the current code is doing will help knowing what approach one might want to take in the porting, rather than just blind code to code translation.
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
passel
I realize that, but if someone was to use the vb6 code as a template to port to VB.Net, it helps eliminate some unnecessary extraneous code that shouldn't be accidentally ported as a straight translation of code to code. A quick understanding of what the current code is doing will help knowing what approach one might want to take in the porting, rather than just blind code to code translation.
i m very sorry i am mean rude by any means. You worked for me great ... but as i am looking for something new and don't want to care about that that's why i said that. If i make you hurts your feelings then i apologize
thanks again
best regards
-
1 Attachment(s)
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Well, I went ahead and spent an hour and took a shot at one way of doing the effect (using VB.Net 2010), and a class that allows direct access to the bits of a bitmap by pinning them in memory.
Its my first shot, and is not as fast as the VB6. As I said, the VB6 code after I made those changes did the transition in around .11 seconds.
It looks like my stab at some .Net code takes about .3 seconds so is about 3 times slower (on my machine, your mileage may vary). I'm sure there are some other things that could be done to improve the speed.
Your original jpgs are of different sizes and you scale them while loading to fit the size of the pictureboxes.
I added them as .Net resources, but did a similar thing to scale the images when putting them in the box, so they have the same number of pixels in all three images and are the same size pictureboxes as you had in the VB6, so should be an "apple" to "apple" comparison as far as doing the transition with the same number of pixels in play.
Here is the code in the form that is doing the setup and code in the button that is doing the transition (I didn't make a separate transition function in a module. You can do that if you want something reusable).
Code:
Public Class Form1
Dim quickBmpMask As DirectBitmap
Dim quickBmpPicA As DirectBitmap
Dim quickBmpPicB As DirectBitmap
Dim sw As New Stopwatch
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Init() 'use a sub so we can reinitialize the PicA image to its original later in the button click
quickBmpPicB = New DirectBitmap(picA.ClientSize.Width, picA.ClientSize.Height, New Bitmap(My.Resources.Pic_B, picA.ClientSize)) 'load and scale image
quickBmpMask = New DirectBitmap(picA.ClientSize.Width, picA.ClientSize.Height, New Bitmap(My.Resources.Pic_Mask, picA.ClientSize)) 'load and scale image
picB.Image = quickBmpPicB.Bmp 'Show the bitmap the quickBmpPicB object allows quick access to
picMask.Image = quickBmpMask.Bmp 'Same for the mask
End Sub
Private Sub Init()
quickBmpPicA = New DirectBitmap(picA.ClientSize.Width, picA.ClientSize.Height, New Bitmap(My.Resources.Pic_A, picA.ClientSize))
picA.Image = quickBmpPicA.Bmp
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim c As Integer 'Our grayscale color as an integer for comparison to the pixels as Integers from quickBmp
Init() 'Restore PicA to the original image
sw.Reset() 'Reset our stopwatch
sw.Start() 'Start timing
For i As Integer = 0 To 255 'For each grayscale level
c = Color.FromArgb(255, i, i, i).ToArgb ' Get the integer value of the grayscale level as a 32-bit color
For p As Integer = 0 To quickBmpMask.Pixels.Count - 1 ' For each pixel value in the grayscale mask
If quickBmpMask.Pixels(p) = c Then ' If the pixel color matches our chosen grayscale color
quickBmpPicA.Pixels(p) = quickBmpPicB.Pixels(p) ' Copy the corresponding pixel from picB to picA
End If
Next
picA.Refresh() ' Refresh picA so we can see the result of each of the 256 level transitions
Next
Me.Text = (sw.ElapsedMilliseconds / 1000).ToString & " Seconds" 'Update the titlebar to show how much time elapsed
End Sub
End Class
And the customized class (for this particular example) that provides the access to the pixels of the bitmap as an array of 32-bit integers.
Code:
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices
Public Class DirectBitmap
Private Handle As GCHandle
Public Pixels() As Int32
Public Bmp As Bitmap
Public ReadOnly Width As Integer
Public ReadOnly Height As Integer
Public Sub New(NewWidth As Integer, NewHeight As Integer, srcBitMap As Image)
Dim Area As Integer
Width = NewWidth
Height = NewHeight
Area = Width * Height
ReDim Pixels(Area - 1)
Handle = GCHandle.Alloc(Pixels, GCHandleType.Pinned)
Bmp = New Bitmap(Width, Height, 4 * Width, PixelFormat.Format32bppPArgb, Handle.AddrOfPinnedObject)
Using g As Graphics = Graphics.FromImage(Bmp)
g.DrawImage(srcBitMap, 0, 0)
End Using
End Sub
Protected Overrides Sub Finalize()
Bmp = Nothing
Handle.Free()
Handle = Nothing
Pixels = Nothing
MyBase.Finalize()
End Sub
End Class
That is all the code there is to this particular implementation.
Example project attached.
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
dday9
could you possibly show a video of what you're attempting?
what do yo think? passel is the best/good idea and it could be more optimized because that's look to me bit more complex? however thanks for your interest though..
best regards
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Short of migrating to WPF, the way Passel does it is about the only feasible one. The better-known way of converting a bitmap to a byte array -- using Bitmap.LockBits in conjunction with Marshalling -- doesn't work well for animated process like an image transition. That's because you don't get to see the result until you unlock the bits, which would entail the overhead of locking and unlocking the bitmap on every pass of the outer loop. The overhead for a pinned a bitmap seems to be larger but you only have to do it once because changes to the bitmap's bytes are immediately visible.
At first sight, the performance of the transition with Passel's code doesn't seem to be a problem because you don't want the transition to be too quick (otherwise you can't see it!) But presently it is the time to process the bitmap that determines the speed of the transition, so it will vary from one transition type to another, and from one computer to another. Ideally you want to control the transition speed with some form of timer. But then slow image processing could be a nuisance. A simple way to speed up Passel's code would be to skip some of the grayscale values, because you don't need all 255 to get a smooth animation. For example:
Code:
For i As Integer = 0 To 255 Step 5 'For each 5th grayscale level
'...
'...
If quickBmpMask.Pixels(p) <= c Then 'If the pixel color is not more than our chosen grayscale color
'...
'...
Next
As to WPF, it is much better equipped to do this kind of thing than GDI+, with classes like the WritebleBitmap, OpacityMask and Storyboard. I'm hoping to work out easier ways to take advantage of these without requiring the effort learning WPF; but that is going to be a longish story.
BB
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
boops boops idea of skipping steps was one of the ways of speeding up the apparent speed I was thinking.
One thing to be aware of is that you have to ensure your inner loop hits the 255 value, otherwise you will leave a number of pixel levels not transferred.
His example of "Step 5" works because 255 is a multiple of 5.
But if you were doing a "Step 7", the last grayscale level transferred would be 252, leaving a number of pixels in the corners and middle (levels 253 to 255), with the previous pictures pixels still there.
You could add a final optimized loop (no need to have an If statement), that would run if a check of the step size wasn't evenly divisible into 255.
But, it would probably be best to adjust the loop starting value so that it ensures the step size will always increment to include the 255 value. An example of that.
Code:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim c As Integer 'Our grayscale color as an integer for comparison to the pixels as Integers from quickBmp
Init() 'Restore PicA to the original image
sw.Reset() 'Reset our stopwatch
sw.Start() 'Start timing
Dim stepsize As Integer = 7 'A step size for example. This could be control by the program to tailor the speed for the machine
Dim stepStart As Integer = 255 Mod stepsize 'Adjust the starting loop value so that we always end our loop at iteration 255
For i As Integer = stepStart To 255 Step stepsize 'For each grayscale level at the current step level
c = Color.FromArgb(255, i, i, i).ToArgb ' Get the integer value of the grayscale level as a 32-bit color
For p As Integer = 0 To quickBmpMask.Pixels.Count - 1 ' For each pixel value in the grayscale mask
If quickBmpMask.Pixels(p) <= c Then ' If the pixel color matches our chosen grayscale color
quickBmpPicA.Pixels(p) = quickBmpPicB.Pixels(p) ' Copy the corresponding pixel from picB to picA
End If
Next
picA.Refresh() ' Refresh picA so we can see the result of each of the 256 level transitions
Next
Me.Text = (sw.ElapsedMilliseconds / 1000).ToString & " Seconds" 'Update the titlebar to show how much time elapsed
End Sub
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
passel
Well, I went ahead and spent an hour and took a shot at one way of doing the effect (using VB.Net 2010), and a class that allows direct access to the bits of a bitmap by pinning them in memory.
Its my first shot, and is not as fast as the VB6. As I said, the VB6 code after I made those changes did the transition in around .11 seconds.
It looks like my stab at some .Net code takes about .3 seconds so is about 3 times slower (on my machine, your mileage may vary). I'm sure there are some other things that could be done to improve the speed.
That is all the code there is to this particular implementation.
Example project attached.
thanks again, and i thought i already gave you thanks quite a few times by now :) lol
yes you really deserve that..
however, sir, can you tell me what is the purpose of that class module, can i skip that and use regular bitmap object instead of that class module?
i am trying to handle your code now and got stuck.. so, your earlier help will be highly appreciated :)
thanks in advance...
best regards
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
passel
Well, I went ahead and spent an hour and took a shot at one way of doing the effect (using VB.Net 2010), and a class that allows direct access to the bits of a bitmap by pinning them in memory.
Its my first shot, and is not as fast as the VB6. As I said, the VB6 code after I made those changes did the transition in around .11 seconds.
It looks like my stab at some .Net code takes about .3 seconds so is about 3 times slower (on my machine, your mileage may vary). I'm sure there are some other things that could be done to improve the speed.
That is all the code there is to this particular implementation.
Example project attached.
also, sir, your class module didn't use dispose function/sub? isn't that needed/necessary? or you forgot that?
thanks in advance....
best regards
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
Shohag_ifas
..., can you tell me what is the purpose of that class module, can i skip that and use regular bitmap object instead of that class module?
i am trying to handle your code now and got stuck.. so, your earlier help will be highly appreciated :)
...
The purpose of the class module is to take the place of the API calls you had in the VB6 code to set up a SafeArray structure and point it at the bitmap data which allowed you to access the bits of the bitmap directly through that array.
A difference being that your VB6 code created the SafeArray structure each time it was going to access the bitmaps. This was fairly quick to do because creating the SafeArray structure to point at the existing bitmap only had to create the "pointer" structure to the bitmap.
This class sort of does the same thing, but in reverse. The class will allocate an array in memory of the size needed to hold the bitmap. It will get a handle to that array memory, designating it as pinned so it will stay in place for as long as we need it.
It will then create a bitmap, passing the handle to the constructor, so the bitmap data will be stored using the same memory as the array.
Now you can access the bitmap as a bitmap, so you can use it for drawing with or drawing on using the normal .Net Graphics object methods, and you can access the pixels directly by changing values in the array.
This allows quick access to the pixels through the array. As boobs boops mentioned, the other quick way to get to the pixels involves mover logic to essential copy the bits into an array for access, making changes, then copying them back.
What does your code look like that is trying to make use of the class? What is hanging you up?
Quote:
Originally Posted by
Shohag_ifas
...also, sir, your class module didn't use dispose function/sub? isn't that needed/necessary? or you forgot that?...
No, not forgotten. You see the Sub Finalize. Whenever no references to an instance of the class exists, the object is available for Garbage Collection, and the GC will call that Finalize Sub to clean up the object. Setting the bmp reference to nothing will allow the GC to also clean up the associated memory and call the Dispose methods on those objects that implement the IDisposeable Interface. You can call the Dispose method yourself to even out timing, rather than have the GC do it later, especially if you are creating a lot of IDisposable objects for short periods of use. In this particular example we are not creating a lot of disposable objects rapidly. The bitmap create remains for as long as the instantiated object exists.
The only place, in the class, that an object should be disposed is in the finalize sub. That only occurs regularly in this example each time you click the button, and call the Init routine. It creates a new instance of the class, so the old instance is no longer referenced. Since this doesn't happen all that rapidly, the GC is allowed to clean up the object rather than add an IDisposable interface to the class.
If you put a counter in the Init sub, and a counter in the Finalize sub, and print out the count in each each time they are called, if the object was disposed of by the GC with every New call in the Init sub, then the Finalize count should always be one less than the Init count. But, the GC will finalize the object when it wants, so if you hit the button a lot, you may see the count differ by several for some period of time. But you will see it clean up several at a time sometimes, and generally remain close to the Init count, eventually event getting back to within 1, which means all old instances have been cleaned up.
It probably wouldn't hurt to dispose of the bitmap object ourselves in the Finalize sub if you want, but technically I don't think it is necessary in the long run.
Code:
Protected Overrides Sub Finalize()
Bmp.Dispose()
Bmp = Nothing
Handle.Free()
Handle = Nothing
Pixels = Nothing
MyBase.Finalize()
End Sub
p.s. Another way of speeding up the transition is to make the looping through the mask more efficient.
Right now, the looping though the bitmap to modify the bits takes slightly longer than the time it takes to refresh the screen, so that is the current bottleneck.
You can make that process about 200 times faster by making one pass through the bitmask whenever you load it, to create 256 linked lists. Each list represents the pixels of a given grayscale value (0 to 255).
That way, when you want to copy all the pixels from one image to the other where the grayscale value is a particular value, you just traverse the list for that level, and copy the pixels specified.
In the example, there are a little over 101 thousand pixels in the image. Rather than visit almost 26 million pixels for the complete transition (each pixel 256 times (256 * 101,376 = 25,952,256), you just copy the pixels designated in each of the list, so only "visit" each pixels once.
The linked lists are very simple, as you don't need a link and a value, you just link the pixels to each other so the link is the value. That makes the storage the same size as the original bitmap (one link per pixel), plus an array of 256 head pointers for the lists, to find the first pixel in each linked list.
If you're interested in that, I can update the example so show that. It isn't a lot of code, and not too much modification.
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
passel
The purpose of the class module is to take the place of the API calls you had in the VB6 code to set up a SafeArray structure and point it at the bitmap data which allowed you to access the bits of the bitmap directly through that array...........
thanks again for your kind reply
i would reply earlier but you have wrote a long message that took some time to read lol :) (thanks for all the time that you gave me to rely all those messages)
however meantime, i research a bit on your code and managed to use with my need :)
thanks again..
btw... sir, can you have a look at the following topic as you are always very kind to help me out. So, would you please check whether you can help me on that too :) ?
Code:
http://www.vbforums.com/showthread.php?787207-VB-Net-Stream-Port-Image-To-FFmpgeg-using-Standard-Input&p=4828337#post4828337
thanks in advance
take care
may Allah bless you
have a nice day
bye bye
-
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
Quote:
Originally Posted by
passel
boops boops idea of skipping steps was one of the ways of speeding up the apparent speed I was thinking
hi, sir how are you? hope being well..
sir, i am facing a issue with the code. can you help please?
i like to update the image specific number of times but not loos any pixel (0-255)/256
so, i have tried this code:
Code:
For i As Integer = 0 To 255 step 4
' for the base step
c = Color.FromArgb(255, i, i, i).ToArgb
For p As Integer = 0 To quickBmpMask.Pixels.Count - 1
If quickBmpMask.Pixels(p) = c Then
quickBmpPicA.Pixels(p) = quickBmpPicB.Pixels(p)
End If
Next
' for then 2nd step
c = Color.FromArgb(255, i+1, i+1, i+1).ToArgb
For p As Integer = 0 To quickBmpMask.Pixels.Count - 1
If quickBmpMask.Pixels(p) = c Then
quickBmpPicA.Pixels(p) = quickBmpPicB.Pixels(p)
End If
Next
' for the 3rd step
c = Color.FromArgb(255, i+2, i+2, i+2).ToArgb
For p As Integer = 0 To quickBmpMask.Pixels.Count - 1
If quickBmpMask.Pixels(p) = c Then
quickBmpPicA.Pixels(p) = quickBmpPicB.Pixels(p)
End If
Next
' for last/4th step
c = Color.FromArgb(255, i+3, i+3, i+3).ToArgb
For p As Integer = 0 To quickBmpMask.Pixels.Count - 1
If quickBmpMask.Pixels(p) = c Then
quickBmpPicA.Pixels(p) = quickBmpPicB.Pixels(p)
End If
Next
picA.Refresh() 'so, this will update the picture box only 64 times (256/4) but will not loose any pixel transformation.
Next
but now my problem is i can only handle it by step 4 as it is multiple of 256
so, it will lead to 64 refresh/image/frame
but how can i use/set a specific number of frames? i can't come out with the formula
for example
if i like to have 25 image only then
i think of
256/25 = 10.24
so, if i use step 10 then i will get 250 pixels and miss rest 6
i have also think to handle rest 6 pixel at last step (so for 25 there will be 6 pixel to handle at one step)
but this is going worse for other numbers
for example if i want 100 image
then :
256/100=2.56
so, if i use 2 step then i will get only 200 pixels and miss rest 56pixel
and if i just handle those 56 at a single/last step effect will not show good :(
so, my question is how can i divide each number of pixels into fixed number of image/frames?
i am sorry for my bad English and hope that makes sense (clear)
your once more help will be highly appreciated
thanks in advance
best regards
-
1 Attachment(s)
Re: Image Transition Effect (Using Gradient/Alpha Mask) Image Change One Image To Ano
------------------------------------------------------------------------------------
1. i like to update the image specific number of times but not loos any pixel (0-255)/256
------------------------------------------------------------------------------------
I assume you are trying to speed things up by skipping how often you refresh the picture, but as boops boops mentioned in post #14, the looping through all the pixels and comparing is the bottle neck in the code (takes longer to do) than the refreshing of the image.
So, what boops boops did was reduce the number of times you looped through all the pixels by skipping grayscale values.
A key part of making that work, is not to compare to see if the value was equal to the mask (quickBmpMask.Pixels(p) = c), but to see if it was less than or equal (quickBmpMask.Pixels(p) <= c).
That way as you loop through, you copy all the pixels equal to c, and all the pixels less than c, which will include the ones skipped.
So, you only need one loop when you skip four, not four loops like you're showing.
Since you skip four values, but then loop through the four values in four loops to catch the skipped ones, you are not really saving much time.
So, the first way to really save time is to change "= c" to "<= c" and only do one loop for each level.
------------------------------------------------------------------------------------
2. so, my question is how can i divide each number of pixels into fixed number of image/frames?
------------------------------------------------------------------------------------
This was covered in post #15.
Once you use "<= c", so you only have one loop per step, how do you end up at 255 at the last loop so all pixels are copied.
The answer is to change where your loop starts. Don't start at 0 unless the step size will divide evenly into 255. Start at a number greater than 0 that will allow the step size to accumulate and hit 255 exactly.
Your examples:
256/25 = 10.24 'You should actually be dividing into 255, so 255/25= 10.2 or 10 with 5 leftover.
255 Mod 25 = 5 'Mod gives you the remainder (number leftover) after the divide.
So, you start your loop at 5, and stepping by 25 will make your last loop be at 255.
Your second example is not that great, very coarse, but still would be.
255 Mod 100 = 55, so start your loop at 55, second time through it will be 155, and last time 255.
But, if you're willing, I will show you a different way to speed up the process by greatly eliminating the multiple passes through the pixels of the images and doing many,many compares, so you may choose not to use skipping to speed things up.
But, if you still want to skip, you can still do that even after speeding up the pixel compare process.
I didn't show you this before, because you might find it complicated, so didn't post it until seeing how things progressed.
I guess, now is the time to try.
Your current process involves comparing every pixels of the mask against every level of grayscale value you want to step through.
That gives you a nested loop, so multiply the number of pixels in the image times the number of levels of grayscale you want to step to get the total number of pixel comparisons you are doing.
In your original example, you had pictureboxes 352 width, 288 height, which is 101376 pixels. You loop though the picture 256 times to do the transition, so the total number of comparisons in your loops is 256 * 101376 = 25952256 (almost 26 million comparisons!).
Since you are using grayscale, there are only 256 different colors in your mask bitmap, so it would make a lot of sense if you could collect all the level 0 pixels in a list, and then all the level 1 pixels in another list, and the level 2 pixels in another list, and so on.
Now, instead of searching the whole image to find all the level 0 pixels and copy them, you only process the pixels in the 0 list. Then for level 1, only process the pixels in the level 1 list.
The end result, you make one pass through the mask bitmap, sorting the pixels into one of the 256 lists when you load the mask bitmap, then you never have to do that again until you load a different mask bitmap.
Then when you do the image transition, you don't have to do any comparisons at all, you just process the pixels in each list. So instead of 26 million comparisons and 101376 copies, you only do the 101376 copies. In theory that is around 256 times less work, and in practice ends up making the pixel processing about 200 times faster, so the time to refresh the screen does become the slower part of the process.
But, overall, the speed may now be too fast, even when you refresh for all 256 levels, so you will need to add a delay to the process, and then you may need to do some skipping to balance out the delays, if the delays can not be finely tuned.
OK, while the sorting of the pixels into lists and processing them may sound complicated, it isn't really, and the resulting code is not long at all.
The most compact and quick to process list is simply to use the pixel offsets within the pixel array as links in a linked list.
So, you need another array of integers, the same size as the number of pixels in the image. This will hold the offset to a given pixel and double as the link in the linked list at the same time. You need another array 0 to 255 to hold the offset to the first pixel offset for each level of grayscale. You preset this array with the value -1, indicating the end of the list. Since we haven't process the bitmap yet, there are no pixel offsets in any of the lists, so the -1 in the 0-255 array indicates that level has no pixels at this point.
For a given level, e.g. level 0, we don't care what order the level 0 pixels are added to the list, we just want to know what all the level 0 pixels are, so this makes populating the list easy. You just loop through the pixels by offset (from 0 to 101376) and whatever level the pixel is (0 to 255), you write the offset currently stored at that level in the level array (0 to 255) at this offset (0 to 101376), and write this offset (0 to 101376) to the level array.
When you're done, the level array (0 to 255) will hold the offset (aka index) of the last pixel found with that level of grayscale.
So, for example, to copy all the pixels with a grayscale level of 0, you read the value from index 0 of the (0 to 255) array. If the value is not -1, then you copy the pixel indicated by the value from bitmap to bitmap. You then use that value to get index into the (0 to 101376) and if it is not -1, you do the same thing, copy the pixel from bitmap to bitmap, and use the value to index to the next value. When you find an index with -1 in it, you are done and have transferred all the pixels that were level 0 in the mask, between the two bitmaps.
So, you only look at and copy the pixels for the grayscale level you need to copy, and don't waste any time looking at pixels that are not at that grayscale level.
So, the relevant code looks like this:
First the code that creates the two array we need for the linked lists, and the code that fills those arrays with the link/pixel offset values.
Code:
Dim maskBase(255) As Integer 'the base entry into the linked lists for each grayscale level
Dim maskLens() As Integer 'convert MaskPixels to Linked Lists so we can make one pass through the mask to create the lists,
'In the form load
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
'....Existing code to Init and set up PicB and BmpMask
'
'Create the linked lists from the Mask picture
ReDim maskLens(quickBmpMask.Pixels.Count - 1)
Dim c As Integer
For i As Integer = 0 To 255 : maskBase(i) = -1 : Next 'Set all the base pointers to -1 (end of list)
For p As Integer = 0 To quickBmpMask.Pixels.Count - 1 'Loop through all the pixels in the mask and link them into their respective lists
c = quickBmpMask.Pixels(p) And &HFF 'Isolate the Grayscale value (using the Red Color level)
maskLens(p) = maskBase(c) 'link this pixel to the last pixel found for this label
maskBase(c) = p 'Put this pixel as the new base (first pixel of the link list)
Next
End Sub
If we didn't want to skip values, but just do the full 256 grayscale transitions, refreshing the image each time, the process would be just this:
Code:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Init() 'Restore PicA to the original image
Dim p As Integer
For i = 0 To 255 'For each grayscale level
p = maskBase(i) ' Get the first pixel offset at this level
Do While p <> -1 ' While we haven't reached the end of the list
quickBmpPicA.Pixels(p) = quickBmpPicB.Pixels(p) ' Copy the corresponding pixel from picB to picA
p = maskLens(p) ' Get the offset of the next pixel
Loop ' Loop
picA.Refresh() ' Refresh picA so we can see the result of each of the 256 level transitions
Next
End Sub
The outer loop plus the inner loops will only loop once per pixels, plus 256 for detecting the end of list (-1) value, so very efficient compared to the original.
But, since it is so efficient, as already mentioned, we will want to add a delay to slow it down for visual effect, and then may want to skip some levels to balance it out. But since each grayscale level is now its own list, we can't catch skipped levels by doing a "<= c", because we aren't doing any comparisons, they don't apply (unless you preapplied the skip value and combined the pixels into fewer, but longer, lists when processing the mask bitmap at the start). So, you need to do all 256 outer loops, and process each list, and just refresh the screen at the skip levels, so you don't skip levels of list processing, just skip levels of refreshing the screen.
The code with skip processing built into it looks like:
Code:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Init() 'Restore PicA to the original image
sw.Reset() 'Reset our stopwatch
sw.Start() 'Start timing
Dim stepsize As Integer = 4 'A step size for example. This could be control by the program to tailor the speed for the machine
Dim stepStart As Integer = 255 Mod stepsize 'Adjust the starting loop value so that we always end our loop at iteration 255
Dim p As Integer
For i = 0 To 255 'For each grayscale level
p = maskBase(i) ' Get the first pixel offset at this level
Do While p <> -1 ' While we haven't reached the end of the list
quickBmpPicA.Pixels(p) = quickBmpPicB.Pixels(p) ' Copy the corresponding pixel from picB to picA
p = maskLens(p) ' Get the offset of the next pixel
Loop ' Loop
If i = stepStart Then
picA.Refresh() ' Refresh picA so we can see the result of each of the 256 level transitions
stepStart += stepsize ' Adjust stepStart by stepsize so we trigger at the next desired point
Threading.Thread.Sleep(1) ' Short delay so we don't transition too fast
End If
Next
End Sub
Project attached so you can see it in action.