0

I am attempting to use the pyueye library to run ML cameras, and am running into problems with ctypes. One function requires an argument of type 'ctypes instance,' and despite trying every possible variation I cannot figure out how to produce this with the ctypes library. There is no documentation for python with this library, but the C documentation of the function I am trying to use is:

Syntax

INT is_SetAutoParameter (HIDS hCam, INT param, double* pval1, double* pval2)

Example 1

//Enable auto gain control:

double dEnable = 1;

int ret = is_SetAutoParameter (hCam, IS_SET_ENABLE_AUTO_GAIN, &dEnable, 0);

The code and subsequent error I am recieving in python is:

nRet = ueye.is_SetAutoParameter(hCam, ueye.IS_SET_ENABLE_AUTO_GAIN, ctypes.byref(ctypes.c_long(1)), ctypes.byref(ctypes.c_long(0)))

Error:
ret = _is_SetAutoParameter(_hCam, _param, ctypes.byref(pval1), ctypes.byref(pval2))
TypeError: byref() argument must be a ctypes instance, not 'CArgObject'

Any advice on ctypes instances? Thanks

EDIT: Minimal reproducible example

from pyueye import ueye
import ctypes

class Turfcam:
    def main(self):
        turfcam.take_photo()

    def take_photo(self):
        hCam = ueye.HIDS(0)
        pval1 = ctypes.c_double(1)
        pval2 = ctypes.c_double(0)
        nRet = ueye.is_SetAutoParameter(hCam, ueye.IS_SET_ENABLE_AUTO_GAIN, ctypes.byref(pval1), ctypes.byref(pval2))

        # Camera Init
        nRet = ueye.is_InitCamera(hCam, None)

if __name__ == "__main__":
    turfcam = Turfcam()
    turfcam.main()
crushendo
  • 33
  • 2
  • 9
  • you have to tell ctypes how the function should be called by using [argtypes](https://docs.python.org/3/library/ctypes.html#specifying-the-required-argument-types-function-prototypes) and [restype](https://docs.python.org/3/library/ctypes.html#return-types). Also your C function prototype uses `double*`, thus you should use a pointer to `ctypes.c_double` (i.e `ctypes.POINTER(ctypes.c_double)` in your `argtypes`). – Neitsa Sep 08 '20 at 10:10
  • How would I get the output to be a ctype instance though? I see in the documentation all the normal stuff like c_double, but all of that returns exactly the same error. WTF is a ctypes instance? – crushendo Sep 09 '20 at 20:26

2 Answers2

1

The pyueye library has some minimal documentation:

_is_SetAutoParameter = _bind("is_SetAutoParameter", [ctypes.c_uint, ctypes.c_int, ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_double)], ctypes.c_int)


def is_SetAutoParameter(hCam, param, pval1, pval2):
    """
    :param hCam: c_uint (aka c-type: HIDS)
    :param param: c_int (aka c-type: INT)
    :param pval1: c_double (aka c-type: double \*)
    :param pval2: c_double (aka c-type: double \*)
    :returns: success, or no success, that is the answer
    :raises NotImplementedError: if function could not be loaded
    """
    if _is_SetAutoParameter is None:
        raise NotImplementedError()

    _hCam = _value_cast(hCam, ctypes.c_uint)
    _param = _value_cast(param, ctypes.c_int)

    ret = _is_SetAutoParameter(_hCam, _param, ctypes.byref(pval1), ctypes.byref(pval2))

    return ret

The wrapper is doing the byref, so only a ctypes object needs to be passed. The uEye docs say the parameters can be input or output parameters, so always create c_double objects and initialize them as needed for the function passed. Note that for an output parameter you must assign the object a name so it exists after the call to be queried. Input parameters can get away with passing ctypes.c_double(value) directly to the function, but for consistency I'd always assign names to the objects:

Example:

pval1 = ctypes.c_double()
pval2 = ctypes.c_double() # not used for output on IS_GET_ENABLE_AUTO_GAIN 
nRet = ueye.is_SetAutoParameter(hCam, ueye.IS_GET_ENABLE_AUTO_GAIN, pval1, pval2)
print(pval1.value) # query the returned value
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • I believe your answer is correct for the usage of ueye.IS_GET_ENABLE_AUTO_GAIN, which returns the parameters pval1 and pval2. However, I am attempting to set the gain with ueye.IS_SET_ENABLE_AUTO_GAIN, which requires that I use pval1 and pval2 as inputs, where pval1 holding a value of 1 enables the auto gain. I still have not figured out how to accomplish this yet. – crushendo Sep 09 '20 at 19:58
  • @crushendo `pval1 = ctypes.c_double(1)` should work. The default initializes to 0. You always create the parameters as I've shown, just initialize them for SET functions as needed. – Mark Tolonen Sep 09 '20 at 20:47
  • It definitely should work, but it does not. I have code written exactly as you have shown, with the correction to pval1 = ctypes.c_double(1), and I still receive the error 'TypeError: byref() argument must be a ctypes instance, not 'CArgObject'' – crushendo Sep 09 '20 at 21:03
  • Are you calling `_is_SetAutoParameter` directly? or `is_SetAutoParameter` (without the underscore)? Can you update your question with a [mcve]. – Mark Tolonen Sep 09 '20 at 22:03
  • With some experimentation, I only get that exact error message when I do `byref(byref(c_double(1)))`. Are you using `byref` anywhere? `_is_SetAutoParmaeter` adds one already. – Mark Tolonen Sep 09 '20 at 22:13
1

To complete the answer given by Mark Tolonen: the following code works OK (but probably you also want to check the error code nRet):

    def take_photo(self):
        hCam = ueye.HIDS(0)
        # Camera Init (you must do this before using hCam !!)
        nRet = ueye.is_InitCamera(hCam, None)
        
        pval1 = ctypes.c_double(1)
        pval2 = ctypes.c_double(0)
        nRet = ueye.is_SetAutoParameter(hCam, ueye.IS_SET_ENABLE_AUTO_GAIN, pval1, pval2)
AvD
  • 153
  • 7