Slider for scrolling through frames of a video in Igor 7
serrano
I am working on a piece of code to display frames of a video (e.g. a 3D Wave) and scroll through the frames of the video using a slider. On top of displaying the frames, I want to also do some on-line analysis on a given frame.
I realized that my code that was working fine on Igor 6.37 had issues on Igor 7: Slowly dragging the slider would only occasionally update the image and the interface would feel quite unresponsive. A strategically(?) placed
DoUpdate
resolved this. However, now when I stop dragging the slider (after having it dragged back and forth for a few seconds), the program freezes up for a few seconds. It seems that Igor still works on a queue of instructions at that time, but the graph is not updated any more.I'd appreciate insights in how I can resolve this. This only occurs on Igor 7.
Here is a minimal working example:
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
// Minimal example:
// genData()
// show()
// Then drag slider
Function Show()
Wave data
Matrixop/O frame = data[][][0]
NewImage/N=win frame
controlbar 50
SetWindow win hook(myhook) = hook
slider sld, limits={0,99,1}, size={300,20},vert=0,proc=ActionProcName
End
Function gendata()
Make/O/N=(512,256, 100) data
data = Gauss(x,z,3, y, z, 3)
End
Function updateframe()
Wave data
Controlinfo sld
Variable value = v_value
Matrixop/O frame = data[][][value]
//Some dummy function to simulate a lengthy calculation that I want do do after drawing the frame
Make/O/N=(500,1000)/FREE tmp
tmp = p*q
doupdate //<— This seems to be needed in Igor 7 to make the image update responsive
//Remove this: Updates become very slow. Have it present: Igor locks up for a few seconds after dragging the slider back and forth for a while
End
Function hook(s)
STRUCT WMWinHookStruct &s
Variable hookResult = 0
print "HOOK"
switch(s.eventCode)
//The real code also contains some hooks for working with the displayed data
endswitch
return hookResult
End
Function ActionProcName(sa) : SliderControl
STRUCT WMSliderAction &sa
print "SLD"
sa.blockReentry=1
if(sa.eventcode == 9)
updateFrame()
endif
End
// Minimal example:
// genData()
// show()
// Then drag slider
Function Show()
Wave data
Matrixop/O frame = data[][][0]
NewImage/N=win frame
controlbar 50
SetWindow win hook(myhook) = hook
slider sld, limits={0,99,1}, size={300,20},vert=0,proc=ActionProcName
End
Function gendata()
Make/O/N=(512,256, 100) data
data = Gauss(x,z,3, y, z, 3)
End
Function updateframe()
Wave data
Controlinfo sld
Variable value = v_value
Matrixop/O frame = data[][][value]
//Some dummy function to simulate a lengthy calculation that I want do do after drawing the frame
Make/O/N=(500,1000)/FREE tmp
tmp = p*q
doupdate //<— This seems to be needed in Igor 7 to make the image update responsive
//Remove this: Updates become very slow. Have it present: Igor locks up for a few seconds after dragging the slider back and forth for a while
End
Function hook(s)
STRUCT WMWinHookStruct &s
Variable hookResult = 0
print "HOOK"
switch(s.eventCode)
//The real code also contains some hooks for working with the displayed data
endswitch
return hookResult
End
Function ActionProcName(sa) : SliderControl
STRUCT WMSliderAction &sa
print "SLD"
sa.blockReentry=1
if(sa.eventcode == 9)
updateFrame()
endif
End
It does work here with
•print IgorInfo(0) IGORVERS:7.09;BUILD:31798;IGORKIND:pro64
also when I remove the DoUpdate.The controlinfo call is superfluous as WMSliderAction has a curval member.
May 18, 2018 at 06:10 am - Permalink
DoUpdate helps a little for more frequent updates during sliding.
Does your actual hook-code cover the situation of nested calls?
HJ
May 18, 2018 at 06:21 am - Permalink
I consistently get the same laggy response on 7.08 32-bit, 7.08 64-bit and also on the latest nightly
IGORVERS:7.09;BUILD:31828;IGORKIND:pro64
All on a Mac.
Maybe I should clarify how I get it to reproduce the behavior: Click and drag the slider around for a few seconds, the longer the worse the lag gets. During dragging, the Console expectedly gets filled with the messages "HOOK" and "SLD". After I then let go of the mouse button, the image stops updating, but the console still keeps displaying additional lines of "HOOK and "SLD".
Also thanks for pointing out the superfluous
ControlInfo
. I should change that in the real code.The actual hook code doesn't handle the event of nested calls. I doubt this is the reason for the behavior I'm seeing though as the minimal example with a hook that doesn't do much except print "HOOK" still can reproduce the weirdness. Also, I get the same even when I disable the hook function.
May 18, 2018 at 07:12 am - Permalink
Win7-64bit, 16GB RAM (6GB used), i7-2630QM @ 2GHz
Cannot try on Mac.
HJ
May 18, 2018 at 07:55 am - Permalink
No issues.
MacBook Pro (Retina, 13-inch, Mid 2014)
2.6 GHz Intel Core i5
Intel Iris 1536 MB
Andy
May 18, 2018 at 08:06 am - Permalink
https://www.dropbox.com/s/tgxk298orxeezxq/with%20DoUpdate.mov?dl=0
https://www.dropbox.com/s/9rtvfugpagwf5ho/without%20DoUpdate.mov?dl=0
The system is OsX 10.13.4 (iMac i5 2017) with Igor-64 7.08.
May 18, 2018 at 09:05 am - Permalink
I agree that without the DoUpdate command, the image isn't super responsive (though in my opinion it still looks pretty responsive).
I think the issue you are seeing with the "freeze" is really an artifact of your use of print statements. Printing to the history in Igor 7+ can be slower than Igor 6, and hundreds or thousands of print statements in a row can slow down the rest of your code.
I replaced your print statements with a ValDisplay in your control bar that changes color when the slider action procedure executes. Now, if I move the slider back and forth for a while and stop, the LED continues to flash for maybe 1/2 a second.
Using Igor 8, I think the update speed without the DoUpdate command is a little better, for what it's worth.
// genData()
// show()
// Then drag slider
Function Show()
Wave data
Matrixop/O frame = data[][][0]
NewImage/N=win frame
controlbar 50
SetWindow win hook(myhook) = hook
slider sld, limits={0,99,1}, size={300,20},vert=0,proc=ActionProcName
ValDisplay valdisp0,pos={341.00,1.00},size={20.00,20.00},bodyWidth=20
ValDisplay valdisp0,limits={0,1,0.5},barmisc={0,0},mode= 2
ValDisplay valdisp0,value= #"doingActionProc"
End
Function gendata()
Make/O/N=(512,256, 100) data
data = Gauss(x,z,3, y, z, 3)
Variable/G doingActionProc
End
Function updateframe()
Wave data
Controlinfo sld
Variable value = v_value
Matrixop/O frame = data[][][value]
//Some dummy function to simulate a lengthy calculation that I want do do after drawing the frame
Make/O/N=(500,1000)/FREE tmp
tmp = p*q
doupdate //<— This seems to be needed in Igor 7 to make the image update responsive
//Remove this: Updates become very slow. Have it present: Igor locks up for a few seconds after dragging the slider back and forth for a while
End
Function hook(s)
STRUCT WMWinHookStruct &s
Variable hookResult = 0
//print "HOOK"
switch(s.eventCode)
//The real code also contains some hooks for working with the displayed data
endswitch
return hookResult
End
Function ActionProcName(sa) : SliderControl
STRUCT WMSliderAction &sa
NVAR doingActionProc
doingActionProc = !doingActionProc
//print "SLD"
sa.blockReentry=1
if(sa.eventcode & 0x01) // value set
updateFrame()
endif
End
May 18, 2018 at 09:35 am - Permalink
Make/O/N=(3000,1000)/FREE tmp
, without the use of print.It seems that the
sa.blockReentry=1
in 6.3 prevented the build up of an execution queue.Nevertheless, in case I don't pass the slider value as a parameter from ActionProcName() to updateframe() but instead use Controlinfo in updateframe(), I can use the following workaround to prevent the lockup:
// genData()
// show()
// Then drag slider
Function Show()
Wave data
Matrixop/O frame = data[][][0]
NewImage/N=win frame
controlbar 50
SetWindow win hook(myhook) = hook
slider sld, limits={0,99,1}, size={300,20},vert=0,proc=ActionProcName
ValDisplay valdisp0,pos={341.00,1.00},size={20.00,20.00},bodyWidth=20
ValDisplay valdisp0,limits={0,1,0.5},barmisc={0,0},mode= 2
ValDisplay valdisp0,value= #"doingActionProc"
End
Function gendata()
Make/O/N=(512,256, 100) data
data = Gauss(x,z,3, y, z, 3)
Variable/G doingActionProc
Variable/G lastslidervalue = 0
End
Function updateframe()
NVAR lastSliderValue
Wave data
Controlinfo sld
if(v_value == lastslidervalue)
print "BLOCKED"
return NaN
endif
lastslidervalue = v_value
Matrixop/O frame = data[][][v_value]
//Some dummy function to simulate a lengthy calculation that I want do do after drawing the frame
Make/O/N=(3000,1000)/FREE tmp
tmp = p*q
doupdate //<— This seems to be needed in Igor 7 to make the image update responsive
//Remove this: Updates become very slow. Have it present: Igor locks up for a few seconds after dragging the slider back and forth for a while
End
Function hook(s)
STRUCT WMWinHookStruct &s
Variable hookResult = 0
//switch here etc.
return hookResult
End
Function ActionProcName(sa) : SliderControl
STRUCT WMSliderAction &sa
NVAR doingActionProc
doingActionProc = !doingActionProc
sa.blockReentry=1
if(sa.eventcode & 2^0) // value set
updateFrame()
endif
End
May 20, 2018 at 06:36 am - Permalink
For Igor 7, re-entry is strictly controlled, so you will never see that the action procedure is called while it is already running. This was a potential problem in Igor 6.
But Igor 7 will add an event to the action queue while a previous call is running. That is why you saw a string of calls happening after you released the mouse after moving the slider around manically. I added a debugging statement in my development Igor that showed that I had at one point 12 calls waiting in the queue!
Your method for avoiding calls after the mouse is released is quite clever.
Looking at the source code (I have an advantage you don't have :) the blockReentry member works by preventing queueing of further events while the action procedure is running. Well, that's clearly what was intended, but it doesn't work- it searches the event queue for a queued action that has blockReentry set, and doesn't queue another if it finds it. Unfortunately, the currently running action has already been dequeued, so it is never found.
I made an experimental change so that the currently running queue is also searched. That, indeed, results in no extra calls being queued, and probably fixes your problem. But I'm hesitant to put that change into a shipping version of Igor- from the documentation:
That makes it evident that the blockReentry member is truly meant to prevent reentry, not multiple queued events.
I will think about the right thing to do...
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
May 21, 2018 at 02:42 pm - Permalink
In reply to by johnweeks
John,
Thanks for the helpful description of reentry and blockReentry in IP6 and 7.
Could you provide an update on reentry and blockRentry in IP8?
Thank you
December 18, 2018 at 03:30 pm - Permalink
There have been no changes in IP8. If any changes happen, it would in IP9.
December 18, 2018 at 04:24 pm - Permalink
Um, thanks for reminding me...
December 18, 2018 at 04:25 pm - Permalink
Apologies for missing the original thread.
Using MatrixOP to extract the frame is nice but may not be necessary. If you display a 3D wave as an image you can call from your slider procedure:
ModifyImage imageName plane=n
This will change the display without using MatrixOP. I have not tested this against the code suggested here but it may be worth the trouble.
A.G.
December 18, 2018 at 04:32 pm - Permalink
Thanks for the tip, A.G.
Unfortunately, my case is a little bit different and I had left that part out in the MWE. I'm actually generating the displayed frames on the fly while the slider is dragged. I first realized that something was different in IP 7 when I started adding code to the generation routine that made it run slower.
In any case, I'm looking forward to a future solution that doesn't require workarounds. For the moment, the hack still works though.
January 10, 2019 at 06:29 am - Permalink
Hello Serrano,
Please contact me through support@wavemetrics.com to discuss the details of your problem and I will see what we can do.
A.G.
January 10, 2019 at 04:06 pm - Permalink