Closed npyoung closed 7 years ago
Yes I didn't ever implement the callback as waitFrameCapture
was adequate for my needs. Would be cool if you got that working. Never mind about the pico reference, that's just an old comment, I'll remove it.
Can you link to the code where you got the callback working? As a wild guess (I don't have a camera to test with) you would need to do something like:
In vimbaframe.py, add a C function type definition outside the class block so the argument and return types are defined (the first argument of CFUNCTYPE
is the return type of the call) like this:
C_FRAME_READY_CALLBACK = CFUNCTYPE(None, c_void_p, POINTER(VimbaFrame))
which says the callback function VmbFrameCallback returns None and takes a handle and a pointer to a frame as the args.
Add a private method to the VimbaFrame class like:
def _get_callback_func(self):
def cb_func(handle, p_frame):
print 'callback function called!'
return C_FRAME_READY_CALLBACK(cb_func)
Then in the queueFrameCapture method, update the call to:
self._rfrc_func = self._get_callback_func()
errorCode = VimbaDLL.captureFrameQueue(self._handle,
byref(self._frame),
self._rfrc_func)
In reality that will be a little useless as your higher level application would want to be registering a Python function to be called I imagine, but it would be a good first test to get working. You shouldn't need to do anything with the frame pointer, you can just use the callback as a trigger to ready the contents of that frame in the usual way, e.g. imgData = frame0.getBufferByteData() as it should now be populated.
Hope that helps.
My implementation defines the callback signature here and implements passing a callback here. You would do something like
def myfun(frame_ptr):
print "frame done!"
frame0.queueFrameCapture(vimbadll.frameDoneCallback(myfun))
I could just use the callback as a trigger to get the buffer from a frame and requeue it, but if I have multiple frames, as I anticipate needing for my high-speed application, then you need to know which frame got filled, and the callback only provides you with a pointer.
Rather than have to reference vimbadll directly from your application, it's probably cleaner to get vimbaframe.py to do it for you:
def queueFrameCapture(self, frameCallback=None):
"""
Queue frames that may be filled during frame capturing.
Runs VmbCaptureFrameQueue
Call after announceFrame and startCapture
frameCallback function must accept argument of type frame
"""
# remember user's callback function
self._frameCallback = frameCallback
# define here so it's not a bound method (can't use self parameter)
def frameCallbackIntercept(_handle, p_frame):
# ignore the handle and frame pointer we get back as we already know which frame this is
# instead call user's callback function with this frame as the argument
self._frameCallback(self)
if self._frameCallback is None:
self._frameCallbackIntercept_C = None
else:
# keep reference to prevent garbage collection issues
self._frameCallbackIntercept_C = VimbaDLL.frameDoneCallback(frameCallbackIntercept)
errorCode = VimbaDLL.captureFrameQueue(self._handle,
byref(self._frame),
self._frameCallbackIntercept_C) # callback
if errorCode != 0:
raise VimbaException(errorCode)
That way you just call it like:
def myfun(frame):
print 'frame ready!'
# do something with the actual frame object (not a pointer), maybe could even requeue it e.g.
# frame.getBufferByteData()
# frame.queueFrameCapture(myfun)
frame0.queueFrameCapture(myfun)
Hopefully that works! The CFUNCTYPE definition might need to be outside the class block.
Has anyone had success with callbacks? The solution of @npyoung seems to be broken with Vimba 1.4. and the testfile he once created (https://github.com/npyoung/pymba/blob/f1558fa3e1910eb27a78d9fda669bda218103e4b/pymba/tests/test_frame_callbacks.py) is not runable (and never was?) because of a undefined function.
On my machine (Windows 7, Vimba 1.4, Mantas Camera), Python crashed without a Traceback... If someone can give me any hints im willing to fix this!
I have created a gist with my scripts for this: https://gist.github.com/jrast/eeda7458d8216d9dd73f
Currently the output looks like this:
Created Frame <pymba.vimbaframe.VimbaFrame object at 0x02BADA30>, Struct <pymba.vimbastructure.VimbaFrame object at 0x02BC8A80>
Created Frame <pymba.vimbaframe.VimbaFrame object at 0x02BADBB0>, Struct <pymba.vimbastructure.VimbaFrame object at 0x02BC8C10>
Qeueing Frame <pymba.vimbaframe.VimbaFrame object at 0x02BADA30> with callback <function frame_cb at 0x024DC1F0>
Qeueing Frame <pymba.vimbaframe.VimbaFrame object at 0x02BADBB0> with callback <function frame_cb at 0x024DC1F0>
Start Callback Wrapper for Cam 5923, Frame <pymba.vimbadll.LP_VimbaFrame object at 0x02BC8C60>, Callback <function frame_cb at 0x024DC1F0>
Start Callback <function frame_cb at 0x024DC1F0> with Frame <pymba.vimbaframe.VimbaFrame object at 0x02BADA30>
Qeueing Frame <pymba.vimbaframe.VimbaFrame object at 0x02BADA30> with callback <function frame_cb at 0x024DC1F0>
End Callback <function frame_cb at 0x024DC1F0> with Frame <pymba.vimbaframe.VimbaFrame object at 0x02BADA30>
End Callback Wrapper for Cam 5923, Frame <pymba.vimbadll.LP_VimbaFrame object at 0x02BC8C60>, Callback <function frame_cb at 0x024DC1F0>
Note that the callback wrapper does receive a frame which is not created by me: The address of the frame is at 0x02BC8C60
and at this address none of my frames exist.
Have a look at the gist to see all the changes that I have made to get this output.
OK, probably I have found the solution:
In vibadll.py, line 314, change the frameDoneCallback as shown:
# callback for frame queue
# frameDoneCallback = CFUNCTYPE(c_void_p, # camera handle
# POINTER(structs.VimbaFrame)) # pointer to frame
frameDoneCallback = WINFUNCTYPE(c_void_p, # Return Type
c_void_p, # Camera Handle
POINTER(structs.VimbaFrame)) # Pointer to frame
In VimbaFrame.queueFrameCapture, change the wrapper function to:
def frameCallbackWrapper(cam_handle, p_frame):
self._frameCallback(self)
I will create a pull request as soon as I have made some more tests.
Presumed fixed!
I was working on doing this myself, and actually managed to get the C API to accept and call my python function, but this leaves me inside a function with nothing but a pointer to the frame. I don't have enough experience with ctypes to know what to do from here. Is anyone working on this?
There's a note in the source about a callback example in pico (vimbaframe.py:96). What does that refer to?