Hi - I’ve got a slow process running in a script DAT. If I leave it alone, it slows the network to about 15fps.
I don’t really need the results of that script at every single frame-- 15fps would probably be fine.
So I naively tried to have the script return early on every other frame. And that causes the script never to cook again. Is there a way to force it to cook every [other] frame? I looked at the docs for Cook, but it wasn’t clear exactly how I should be pulling from that DAT (or the CHOP I make from it) to make sure it keeps getting cooked.
This may be the wrong way to think about this. Is there another way you’d approach a script that doesn’t run fast enough but which is OK running more slowly, as long as everything else doesn’t run slowly?
Here’s the relevant script source:
def onCook(scriptOp):
scriptOp.clear()
# Set some text in the parent dat so we can see when we cook
scriptOp.text = str(absTime.frame)
# On even frames, I don't need to run anything, so just return
if absTime.frame %2 == 0:
return # commenting out this line causes
# Now Do some heavy OpenCV processing here on odd frames,
# then set values in scriptOp based on the results
# <your code here... >
pass
OK, that helps! I’m feeding a TOP to the script CHOP, and I wasn’t accessing any of the TOP’s data on every frame. So once a frame was skipped, the node didn’t cook again since it wasn’t accessing that data at all.
If I access the TOP a tiny bit each frame, it cooks every time, allowing me to skip the expensive processing when I need to.
One last question. I force the Script CHOP to cook every frame by accessing a single pixel in the TOP. Is this the cheapest way to use the TOP’s data to force the cook?
Thanks for clearing that up!
Relevant source:
# press 'Setup Parameters' in the OP to call this function to re-create the parameters.
def onSetupParameters(scriptOp):
page = scriptOp.appendCustomPage('Custom')
p = page.appendTOP('Top')
return
def onCook(scriptOp):
topRef = scriptOp.par.Top.eval()
# The magic: make sure we use some data from the input TOP every frame;
# Otherwise this node won't cook after the frame is skipped
# TODO: is this the cheapest way to pull info from the TOP?
sample = topRef.sample(x=0, y=0)
if absTime.frame % 4 != 0:
# print('%d: script returning early'%(absTime.frame))
return
else:
# Expensive processing would go here here...
scriptOp.clear()
# print('%d: script setting "frame" channel to %d'%(absTime.frame, absTime.frame))
frameChan = scriptOp.appendChan('frame')
frameChan[0] = absTime.frame
pixelChan = scriptOp.appendChan('upperLeftGreen')
pixelChan[0] = sample[1]
return
You might consider using a TopToCHOP first. There’s an optimization approach here that provides the data a frame behind the current frame that’s rendering allowing the download from the GPU to speed up significantly. You can also use the TopToCHOP to isolate a specific pixel, row, or column of pixels. You might then use this to drive a CHOP execute. Depending on what you’re up to this might prove to be a little faster / more efficient than a pure Python approach.
Thanks, Matt. I’ve taken a look with the Probe panel to compare checking a sample from the TOP on every frame with
dummy_sample = topRef.sample(0,0)
vs using a TopTo Chop & then checking that value with
dummy_sample = scriptOp.inputs[0]['r']
.
It is definitely faster in my script to access the TopTo Chop like you suggested, although that chop incurs its own expense; looks like it’s more or less a wash so far.
If I can avoid cooking the OpenCV script at all except when I want it to, that would be the biggest win; I’ll try that out tomorrow.