diff --git a/cython/factory.pyx b/cython/factory.pyx index b316788..6897654 100644 --- a/cython/factory.pyx +++ b/cython/factory.pyx @@ -7,6 +7,13 @@ import numpy as np from pylon_def cimport * +cdef extern from "pylon/PylonIncludes.h" namespace 'Pylon': + + cpdef enum EGrabStrategy: + GrabStrategy_OneByOne, + GrabStrategy_LatestImageOnly, + GrabStrategy_LatestImages, + GrabStrategy_UpcomingImage cdef class DeviceInfo: cdef: @@ -195,6 +202,10 @@ cdef class Camera: self.camera.Close() elif not self.opened and opened: self.camera.Open() + + property is_grabbing: + def __get__(self): + return self.camera.IsGrabbing() def open(self): self.camera.Open() @@ -202,19 +213,23 @@ cdef class Camera: def close(self): self.camera.Close() + def stop_grabbing(self): + if self.camera.IsGrabbing(): + self.camera.StopGrabbing() + def __del__(self): + self.stop_grabbing() self.close() self.camera.DetachDevice() def __repr__(self): return ''.format(self.device_info.friendly_name, self.opened) - def grab_images(self, int nr_images, unsigned int timeout=5000): + def grab_images(self, int nr_images = -1, EGrabStrategy grab_strategy=GrabStrategy_OneByOne, unsigned int timeout=5000): + if not self.opened: raise RuntimeError('Camera not opened') - self.camera.StartGrabbing(nr_images) - cdef CGrabResultPtr ptr_grab_result cdef IImage* img @@ -224,44 +239,73 @@ cdef class Camera: assert image_format.startswith('Mono'), 'Only mono images allowed at this point' assert not image_format.endswith('p'), 'Packed data not supported at this point' - while self.camera.IsGrabbing(): + try: + if nr_images < 1: + self.camera.StartGrabbing(grab_strategy) + else: + self.camera.StartGrabbing(nr_images, grab_strategy) + + while self.camera.IsGrabbing(): + + with nogil: + # Blocking call into native Pylon C++ SDK code, release GIL so other python threads can run + self.camera.RetrieveResult(timeout, ptr_grab_result) - with nogil: - # Blocking call into native Pylon C++ SDK code, release GIL so other python threads can run - self.camera.RetrieveResult(timeout, ptr_grab_result) + if not ACCESS_CGrabResultPtr_GrabSucceeded(ptr_grab_result): + error_desc = ((ACCESS_CGrabResultPtr_GetErrorDescription(ptr_grab_result))).decode() + raise RuntimeError(error_desc) - if not ACCESS_CGrabResultPtr_GrabSucceeded(ptr_grab_result): - error_desc = ((ACCESS_CGrabResultPtr_GetErrorDescription(ptr_grab_result))).decode() - raise RuntimeError(error_desc) + img = &(ptr_grab_result) + if not img.IsValid(): + raise RuntimeError('Graped IImage is not valid.') - img = &(ptr_grab_result) - if not img.IsValid(): - raise RuntimeError('Graped IImage is not valid.') + if img.GetImageSize() % img.GetHeight(): + print('This image buffer is wired. Probably you will see an error soonish.') + print('\tBytes:', img.GetImageSize()) + print('\tHeight:', img.GetHeight()) + print('\tWidth:', img.GetWidth()) + print('\tGetPaddingX:', img.GetPaddingX()) - if img.GetImageSize() % img.GetHeight(): - print('This image buffer is wired. Probably you will see an error soonish.') - print('\tBytes:', img.GetImageSize()) - print('\tHeight:', img.GetHeight()) - print('\tWidth:', img.GetWidth()) - print('\tGetPaddingX:', img.GetPaddingX()) + assert not img.GetPaddingX(), 'Image padding not supported.' + # TODO: Check GetOrientation to fix oritentation of image if required. - assert not img.GetPaddingX(), 'Image padding not supported.' - # TODO: Check GetOrientation to fix oritentation of image if required. + img_data = np.frombuffer((img.GetBuffer())[:img.GetImageSize()], dtype='uint'+bits_per_pixel_prop[3:]) - img_data = np.frombuffer((img.GetBuffer())[:img.GetImageSize()], dtype='uint'+bits_per_pixel_prop[3:]) + # TODO: How to handle multi-byte data here? + img_data = img_data.reshape((img.GetHeight(), -1)) + # img_data = img_data[:img.GetHeight(), :img.GetWidth()] + yield img_data - # TODO: How to handle multi-byte data here? - img_data = img_data.reshape((img.GetHeight(), -1)) - # img_data = img_data[:img.GetHeight(), :img.GetWidth()] - yield img_data + except: + self.stop_grabbing() + raise - def grab_image(self, unsigned int timeout=5000): - return next(self.grab_images(1, timeout)) + def grab_image(self, EGrabStrategy grab_strategy=GrabStrategy_OneByOne, unsigned int timeout=5000): + return next(self.grab_images(1, grab_strategy, timeout)) property properties: def __get__(self): return _PropertyMap.create(&self.camera.GetNodeMap()) + # Configuration properties associated with various grab strategies + property max_num_buffer: + def __get__(self): + return self.camera.MaxNumBuffer.GetValue() + def __set__(self, value): + self.camera.MaxNumBuffer.SetValue(value) + + property max_num_queued_buffer: + def __get__(self): + return self.camera.MaxNumQueuedBuffer.GetValue() + def __set__(self, value): + self.camera.MaxNumQueuedBuffer.SetValue(value) + + property output_queue_size: + def __get__(self): + return self.camera.OutputQueueSize.GetValue() + def __set__(self, value): + self.camera.OutputQueueSize.SetValue(value) + cdef class Factory: def __cinit__(self): @@ -288,4 +332,4 @@ cdef class Factory: def create_device(self, DeviceInfo dev_info): cdef CTlFactory* tl_factory = &GetInstance() - return Camera.create(tl_factory.CreateDevice(dev_info.dev_info)) \ No newline at end of file + return Camera.create(tl_factory.CreateDevice(dev_info.dev_info)) diff --git a/cython/pylon_def.pxd b/cython/pylon_def.pxd index e5ccd59..9f8955a 100644 --- a/cython/pylon_def.pxd +++ b/cython/pylon_def.pxd @@ -109,6 +109,12 @@ cdef extern from "pylon/PylonIncludes.h" namespace 'Pylon': String_t GetVendorName() except + String_t GetDeviceClass() except + + cdef enum EGrabStrategy: + GrabStrategy_OneByOne, + GrabStrategy_LatestImageOnly, + GrabStrategy_LatestImages, + GrabStrategy_UpcomingImage + cdef cppclass CInstantCamera: CInstantCamera() void Attach(IPylonDevice*) @@ -116,14 +122,24 @@ cdef extern from "pylon/PylonIncludes.h" namespace 'Pylon': void IsCameraDeviceRemoved() void Open() except + void Close() except + + void StopGrabbing() except + bool IsOpen() except + IPylonDevice* DetachDevice() except + - void StartGrabbing(size_t maxImages) except + #FIXME: implement different strategies + void StartGrabbing(EGrabStrategy strategy) except + + void StartGrabbing(size_t maxImages, EGrabStrategy strategy) except + bool IsGrabbing() # RetrieveResult() is blocking call into C++ native SDK, allow it to be called without GIL bool RetrieveResult(unsigned int timeout_ms, CGrabResultPtr& grab_result) nogil except + # FIXME: Timout handling INodeMap& GetNodeMap() + # From CInstantCameraParams_Params base class + IInteger &MaxNumBuffer; + IInteger &MaxNumQueuedBuffer; + IInteger &OutputQueueSize; + + + + cdef cppclass DeviceInfoList_t: cppclass iterator: CDeviceInfo operator*() @@ -148,4 +164,4 @@ cdef extern from "pylon/PylonIncludes.h" namespace 'Pylon::CTlFactory': cdef extern from 'hacks.h': bool ACCESS_CGrabResultPtr_GrabSucceeded(CGrabResultPtr ptr) String_t ACCESS_CGrabResultPtr_GetErrorDescription(CGrabResultPtr ptr) - uint32_t ACCESS_CGrabResultPtr_GetErrorCode(CGrabResultPtr ptr) \ No newline at end of file + uint32_t ACCESS_CGrabResultPtr_GetErrorCode(CGrabResultPtr ptr) diff --git a/pypylon/__init__.py b/pypylon/__init__.py index a61d829..21ead66 100644 --- a/pypylon/__init__.py +++ b/pypylon/__init__.py @@ -1,5 +1,26 @@ from pypylon.cython.factory import Factory from pypylon.cython.version import PylonVersion +# With earlier versions of python that don't support PEP 435 enums (discovered on an Ubuntu 14.04 with stock python 2.7.6) cython +# seems to silently drop the EGrabStrategy enum. declared with cpdef directive in factory.pyx, so have to define it manually. +GrabStrategy_OneByOne = 0 +GrabStrategy_LatestImageOnly = 1 +GrabStrategy_LatestImages = 2 +GrabStrategy_UpcomingImage = 3 + +try: + # If running on python version where EGrabStrategy is sucessfully exported, sanity check that values match our manual + # definitions + from pypylon.cython.factory import EGrabStrategy + + assert GrabStrategy_OneByOne == EGrabStrategy.GrabStrategy_OneByOne + assert GrabStrategy_LatestImageOnly == EGrabStrategy.GrabStrategy_LatestImageOnly + assert GrabStrategy_LatestImages == EGrabStrategy.GrabStrategy_LatestImages + assert GrabStrategy_UpcomingImage == EGrabStrategy.GrabStrategy_UpcomingImage + +except ImportError: + pass + + factory = Factory() -pylon_version = PylonVersion() \ No newline at end of file +pylon_version = PylonVersion()