From 88ed2d9d737de3f3e5c409482292274b3a331d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Wed, 1 Oct 2025 13:10:50 +0200 Subject: [PATCH 1/7] Bumped minor version as the changes on this branch will add new functions. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 50be812..4b05e83 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "PyVCAM" -version = "2.2.4" +version = "2.3.0.dev0" description = "Python wrapper for PVCAM functionality" authors = [ {name = "Teledyne Photometrics", email = "photometrics.support@teledyne.com"}, From fca9d8fc1707ba225139f08042519dcfcd00345e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Wed, 1 Oct 2025 13:12:01 +0200 Subject: [PATCH 2/7] Removed optional 'gui' dependencies as these are needed for examples only. --- pyproject.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4b05e83..6c691f9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,10 +35,6 @@ dependencies = [ ] [project.optional-dependencies] -gui = [ - "opencv-python", - "matplotlib", -] dev = [ "validate-pyproject[all]", "Flake8-pyproject", From ff7155750a34f61799ac68397976c8fbf94c1f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Wed, 1 Oct 2025 13:13:25 +0200 Subject: [PATCH 3/7] Enabled download URL pointing to PyPI as we have first release there yet. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6c691f9..f3489e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ dev = [ # Home page doesn't show up with 'pip show', used a workaround via setup.cfg or setup.py homepage = "https://github.com/Photometrics/PyVCAM" source = "https://github.com/Photometrics/PyVCAM" -#download = "https://pypi.org/project/PyVCAM/" +download = "https://pypi.org/project/PyVCAM/#files" tracker = "https://github.com/Photometrics/PyVCAM/issues" [build-system] From 5b28941a218b23d1e6fcdef05a2583f2a8f45052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Wed, 1 Oct 2025 13:36:54 +0200 Subject: [PATCH 4/7] Separated acquisition setup and start in pvc module. Added 4 new functions - pvc_start_live now internally only calls new pvc_setup_live and pvc_start_set_live, pvc_start_seq calls new pvc_setup_seq and pvc_start_set_seq. The pvc_setup_* functions proceed with all acq. setup, callback registration and buffer allocations, the pvc_start_set_* functions just reset FPS counters and start the acquisition. This allows finer control needed e.g. for a time-lapse acquisitions with Variable Timed exposure Mode (VTM), where the acq. should be set up only once and then for each frame is called set_param for PARAM_EXP_TIME with new value followed by acq. start capturing one frame with given exposure time. --- docs/PyVCAM.md | 52 +++++++------ src/pyvcam/pvcmodule.cpp | 164 +++++++++++++++++++++++++++++---------- 2 files changed, 151 insertions(+), 65 deletions(-) diff --git a/docs/PyVCAM.md b/docs/PyVCAM.md index f2cd908..b7acc77 100644 --- a/docs/PyVCAM.md +++ b/docs/PyVCAM.md @@ -374,30 +374,34 @@ example for a visual representation). **Note:** All functions will always have the `PyObject* self` and `PyObject* args` parameters. When parameters are listed, they are the Python parameters that are passed into the module. -| Function Name | Description | -|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `pvc_abort` | Given a camera handle, aborts any ongoing acquisition and de-registers the frame handler callback function.

**Parameters:**
  • Python int (camera handle).
  • | -| `pvc_check_frame_status` | Given a camera handle, returns the current frame status as a string. Possible return values:
    • `'READOUT_NOT_ACTIVE'`
    • `'EXPOSURE_IN_PROGRESS'`
    • `'READOUT_IN_PROGRESS'`
    • `'READOUT_COMPLETE'`/`'FRAME_AVAILABLE'`
    • `'READOUT_FAILED'`
    **Parameters:**
    • Python int (camera handle).
    | -| `pvc_check_param` | Given a camera handle and parameter ID, returns `True` if the parameter is available on the camera.

    **Parameters:**
    • Python int (camera handle).
    • Python int (parameter ID).
    | -| `pvc_close_camera` | Given a camera handle, closes the camera. Returns `True` upon success. `ValueError` is raised if invalid parameter is supplied. `RuntimeError` raised otherwise.

    **Parameters:**
    • Python int (camera handle).
    | -| `pvc_finish_seq` | Given a camera handle, finalizes sequence acquisition and cleans up resources. If a sequence is in progress, acquisition will be aborted.

    **Parameters:**
    • Python int (camera handle).
    | -| `pvc_get_cam_fw_version` | Given a camera handle, returns camera firmware version as a string.

    **Parameters:**
    • Python int (camera handle).
    | -| `pvc_get_cam_name` | Given a Python integer corresponding to a camera handle, returns the name of the camera with the associate handle.

    **Parameters:**
    • Python int (camera handle).
    | -| `pvc_get_cam_total` | Returns the total number of cameras currently attached to the system as a Python integer. | -| `pvc_get_frame` | Given a camera and a region, returns a Python numpy array of the pixel values of the data. Numpy array returned on success. `ValueError` raised if invalid parameters are supplied. `MemoryError` raised if unable to allocate memory for the camera frame. `RuntimeError` raised otherwise.

    **Parameters:**
    • Python int (camera handle).
    • Python list (Region of Interest objects)
    • Python int (Numpy data type enumeration value)
    • Python int (Frame timeout in milliseconds. Negative values will wait forever)
    • Python bool (Flag selecting oldest or newest frame)
    | -| `pvc_get_param` | Given a camera handle, a parameter ID, and the attribute of the parameter in question (AVAIL, CURRENT, etc.) returns the value of the parameter at the current attribute.

    **Note: This setting will only return a Python int or a Python string. Currently no other types are supported, but it is possible to extend the function as needed.**

    `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised if camera does not support the specified parameter. `RuntimeError` is raised otherwise.

    **Parameters:**
    • Python int (camera handle).
    • Python int (parameter ID).
    • Python int (parameter attribute).
    | -| `pvc_get_pvcam_version` | Returns a Python Unicode String of the current PVCAM version. | -| `pvc_init_pvcam` | Initializes the PVCAM library. Raises `RuntimeError` on failure. | -| `pvc_open_camera` | Given a Python string corresponding to a camera name, opens the camera. Returns `True` upon success. `ValueError` is raised if invalid parameter is supplied. `RuntimeError` raised otherwise.

    **Parameters:**
    • Python string (camera name).
    | -| `pvc_read_enum` | Function that when given a camera handle and a enumerated parameter will return a list mapping all valid setting names to their values for the camera. `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised if an invalid setting for the camera is supplied. `RuntimeError` is raised upon failure. A Python list of dictionaries is returned upon success.

    **Parameters:**
    • Python int (camera handle).
    • Python int (parameter ID).
    | -| `pvc_reset_frame_counter` | Given a camera handle, resets `frame_count` returned by `pvc_poll_frame` to zero.

    **Parameters:**
    • Python int (camera handle).
    | -| `pvc_reset_pp` | Given a camera handle, resets all camera post-processing parameters back to their default state.

    **Parameters:**
    • Python int (camera handle).
    | -| `pvc_set_exp_modes` | Given a camera, exposure mode, and an expose out mode, change the camera's exposure mode to be the bitwise OR of the exposure mode and expose out mode parameters. `ValueError` is raised if invalid parameters are supplied including invalid modes for either exposure mode or expose out mode. `RuntimeError` is raised upon failure.

    **Parameters:**
    • Python int (camera handle).
    • Python int (exposure mode).
    • Python int (expose out mode).
    | -| `pvc_set_param` | Given a camera handle, a parameter ID, and a new value for the parameter, set the camera's parameter to the new value. `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised when attempting to set a parameter not supported by a camera. `RuntimeError` is raised upon failure.

    **Parameters:**
    • Python int (camera handle).
    • Python int (parameter ID).
    • Generic Python value (any type) (new value for parameter).
    | -| `pvc_start_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up a live mode acquisition.

    **Parameters:**
    • Python int (camera handle).
    • Python list (Region of Interest objects)
    • Python int (exposure time).
    • Python int (exposure mode).
    • Python int (buffer frame count).
    • Python str (stream to disk path).
    • Python bool (reset frame counter)
    | -| `pvc_start_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up a sequence mode acquisition.

    **Parameters:**
    • Python int (camera handle).
    • Python list (Region of Interest objects)
    • Python int (exposure time).
    • Python int (exposure mode).
    • Python int (total frames).
    • Python bool (reset frame counter)
    | -| `pvc_sw_trigger` | Given a camera handle, performs a software trigger. Prior to using this function, the camera must be set to use either the `EXT_TRIG_SOFTWARE_FIRST` or `EXT_TRIG_SOFTWARE_EDGE` exposure mode.

    **Parameters:**
    • Python int (camera handle).
    • | -| `pvc_uninit_pvcam` | Uninitializes the PVCAM library. Raises `RuntimeError` on failure. | +| Function Name | Description | +|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `pvc_abort` | Given a camera handle, aborts any ongoing acquisition and de-registers the frame handler callback function.

      **Parameters:**
      • Python int (camera handle).
      • | +| `pvc_check_frame_status` | Given a camera handle, returns the current frame status as a string. Possible return values:
        • `'READOUT_NOT_ACTIVE'`
        • `'EXPOSURE_IN_PROGRESS'`
        • `'READOUT_IN_PROGRESS'`
        • `'READOUT_COMPLETE'`/`'FRAME_AVAILABLE'`
        • `'READOUT_FAILED'`
        **Parameters:**
        • Python int (camera handle).
        | +| `pvc_check_param` | Given a camera handle and parameter ID, returns `True` if the parameter is available on the camera.

        **Parameters:**
        • Python int (camera handle).
        • Python int (parameter ID).
        | +| `pvc_close_camera` | Given a camera handle, closes the camera. Returns `True` upon success. `ValueError` is raised if invalid parameter is supplied. `RuntimeError` raised otherwise.

        **Parameters:**
        • Python int (camera handle).
        | +| `pvc_finish_seq` | Given a camera handle, finalizes sequence acquisition and cleans up resources. If a sequence is in progress, acquisition will be aborted.

        **Parameters:**
        • Python int (camera handle).
        | +| `pvc_get_cam_fw_version` | Given a camera handle, returns camera firmware version as a string.

        **Parameters:**
        • Python int (camera handle).
        | +| `pvc_get_cam_name` | Given a Python integer corresponding to a camera handle, returns the name of the camera with the associate handle.

        **Parameters:**
        • Python int (camera handle).
        | +| `pvc_get_cam_total` | Returns the total number of cameras currently attached to the system as a Python integer. | +| `pvc_get_frame` | Given a camera and a region, returns a Python numpy array of the pixel values of the data. Numpy array returned on success. `ValueError` raised if invalid parameters are supplied. `MemoryError` raised if unable to allocate memory for the camera frame. `RuntimeError` raised otherwise.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (Numpy data type enumeration value)
        • Python int (Frame timeout in milliseconds. Negative values will wait forever)
        • Python bool (Flag selecting oldest or newest frame)
        | +| `pvc_get_param` | Given a camera handle, a parameter ID, and the attribute of the parameter in question (AVAIL, CURRENT, etc.) returns the value of the parameter at the current attribute.

        **Note: This setting will only return a Python int or a Python string. Currently no other types are supported, but it is possible to extend the function as needed.**

        `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised if camera does not support the specified parameter. `RuntimeError` is raised otherwise.

        **Parameters:**
        • Python int (camera handle).
        • Python int (parameter ID).
        • Python int (parameter attribute).
        | +| `pvc_get_pvcam_version` | Returns a Python Unicode String of the current PVCAM version. | +| `pvc_init_pvcam` | Initializes the PVCAM library. Raises `RuntimeError` on failure. | +| `pvc_open_camera` | Given a Python string corresponding to a camera name, opens the camera. Returns `True` upon success. `ValueError` is raised if invalid parameter is supplied. `RuntimeError` raised otherwise.

        **Parameters:**
        • Python string (camera name).
        | +| `pvc_read_enum` | Function that when given a camera handle and a enumerated parameter will return a list mapping all valid setting names to their values for the camera. `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised if an invalid setting for the camera is supplied. `RuntimeError` is raised upon failure. A Python list of dictionaries is returned upon success.

        **Parameters:**
        • Python int (camera handle).
        • Python int (parameter ID).
        | +| `pvc_reset_frame_counter` | Given a camera handle, resets `frame_count` returned by `pvc_poll_frame` to zero.

        **Parameters:**
        • Python int (camera handle).
        | +| `pvc_reset_pp` | Given a camera handle, resets all camera post-processing parameters back to their default state.

        **Parameters:**
        • Python int (camera handle).
        | +| `pvc_set_exp_modes` | Given a camera, exposure mode, and an expose out mode, change the camera's exposure mode to be the bitwise OR of the exposure mode and expose out mode parameters. `ValueError` is raised if invalid parameters are supplied including invalid modes for either exposure mode or expose out mode. `RuntimeError` is raised upon failure.

        **Parameters:**
        • Python int (camera handle).
        • Python int (exposure mode).
        • Python int (expose out mode).
        | +| `pvc_set_param` | Given a camera handle, a parameter ID, and a new value for the parameter, set the camera's parameter to the new value. `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised when attempting to set a parameter not supported by a camera. `RuntimeError` is raised upon failure.

        **Parameters:**
        • Python int (camera handle).
        • Python int (parameter ID).
        • Generic Python value (any type) (new value for parameter).
        | +| `pvc_setup_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up a live mode acquisition. Returns one frame size in bytes.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (exposure time).
        • Python int (exposure mode).
        • Python int (buffer frame count).
        • Python str (stream to disk path).
        | +| `pvc_setup_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up a sequence mode acquisition. Returns one frame size in bytes.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (exposure time).
        • Python int (exposure mode).
        • Python int (total frames).
        | +| `pvc_start_set_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, starts already sets up live mode acquisition.

        **Parameters:**
        • Python int (camera handle).
        | +| `pvc_start_set_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, starts already sets up sequence mode acquisition.

        **Parameters:**
        • Python int (camera handle).
        | +| `pvc_start_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up and starts a live mode acquisition. Internally combines `pvc_setup_live` and `pvc_start_set_live`. Returns one frame size in bytes.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (exposure time).
        • Python int (exposure mode).
        • Python int (buffer frame count).
        • Python str (stream to disk path).
        | +| `pvc_start_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up and starts a sequence mode acquisition. Internally combines `pvc_setup_seq` and `pvc_start_set_seq`. Returns one frame size in bytes.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (exposure time).
        • Python int (exposure mode).
        • Python int (total frames).
        | +| `pvc_sw_trigger` | Given a camera handle, performs a software trigger. Prior to using this function, the camera must be set to use either the `EXT_TRIG_SOFTWARE_FIRST` or `EXT_TRIG_SOFTWARE_EDGE` exposure mode.

        **Parameters:**
        • Python int (camera handle).
        • | +| `pvc_uninit_pvcam` | Uninitializes the PVCAM library. Raises `RuntimeError` on failure. | #### The Method Table All functions that need to be exposed to Python programs need to be included in the method table. diff --git a/src/pyvcam/pvcmodule.cpp b/src/pyvcam/pvcmodule.cpp index 9c4ce7a..64721c6 100644 --- a/src/pyvcam/pvcmodule.cpp +++ b/src/pyvcam/pvcmodule.cpp @@ -716,8 +716,8 @@ static PyObject* pvc_check_param(PyObject* self, PyObject* args) Py_RETURN_FALSE; } -/** Starts a live acquisition. */ -static PyObject* pvc_start_live(PyObject* self, PyObject* args) +/** Sets up a live acquisition. */ +static PyObject* pvc_setup_live(PyObject* self, PyObject* args) { int16 hcam; PyObject* roiListObj; @@ -733,9 +733,13 @@ static PyObject* pvc_start_live(PyObject* self, PyObject* args) if (roiArray.empty()) return NULL; - std::shared_ptr cam = GetCamera(hcam); - if (!cam) - return NULL; + uns32 frameBytes; + if (!pl_exp_setup_cont(hcam, (uns16)roiArray.size(), roiArray.data(), + expMode, expTime, &frameBytes, CIRC_OVERWRITE)) + return PvcamError(); + + if (!pl_cam_register_callback_ex3(hcam, PL_CALLBACK_EOF, (void*)NewFrameHandler, NULL)) + return PvcamError(); bool metadataAvail = false; bool metadataEnabled = false; @@ -753,16 +757,10 @@ static PyObject* pvc_start_live(PyObject* self, PyObject* args) } } - if (!pl_cam_register_callback_ex3(hcam, PL_CALLBACK_EOF, (void*)NewFrameHandler, NULL)) - return PvcamError(); - - uns32 frameBytes; - if (!pl_exp_setup_cont(hcam, (uns16)roiArray.size(), roiArray.data(), - expMode, expTime, &frameBytes, CIRC_OVERWRITE)) - return PvcamError(); + std::shared_ptr cam = GetCamera(hcam); + if (!cam) + return NULL; - void* acqBuffer = NULL; - uns32 acqBufferBytes = 0; { std::lock_guard lock(cam->m_mutex); @@ -782,22 +780,13 @@ static PyObject* pvc_start_live(PyObject* self, PyObject* args) cam->m_acqAbort = false; cam->m_acqNewFrame = false; cam->m_isSequence = false; - cam->m_fpsFrameCnt = 0; - cam->m_fpsLastTime = std::chrono::high_resolution_clock::now(); - cam->m_acqCbError.clear(); - - acqBuffer = cam->m_acqBuffer->data; - acqBufferBytes = (uns32)cam->m_acqBuffer->size; } - if (!pl_exp_start_cont(hcam, acqBuffer, acqBufferBytes)) - return PvcamError(); - return PyLong_FromUnsignedLong(frameBytes); } -/** Starts a sequence acquisition. */ -static PyObject* pvc_start_seq(PyObject* self, PyObject* args) +/** Sets up a sequence acquisition. */ +static PyObject* pvc_setup_seq(PyObject* self, PyObject* args) { int16 hcam; PyObject* roiListObj; @@ -812,9 +801,14 @@ static PyObject* pvc_start_seq(PyObject* self, PyObject* args) if (roiArray.empty()) return NULL; - std::shared_ptr cam = GetCamera(hcam); - if (!cam) - return NULL; + uns32 acqBufferBytes; + if (!pl_exp_setup_seq(hcam, expTotal, (uns16)roiArray.size(), roiArray.data(), + expMode, expTime, &acqBufferBytes)) + return PvcamError(); + const uns32 frameBytes = acqBufferBytes / expTotal; + + if (!pl_cam_register_callback_ex3(hcam, PL_CALLBACK_EOF, (void*)NewFrameHandler, NULL)) + return PvcamError(); bool metadataAvail = false; bool metadataEnabled = false; @@ -832,16 +826,10 @@ static PyObject* pvc_start_seq(PyObject* self, PyObject* args) } } - if (!pl_cam_register_callback_ex3(hcam, PL_CALLBACK_EOF, (void*)NewFrameHandler, NULL)) - return PvcamError(); - - uns32 acqBufferBytes; - if (!pl_exp_setup_seq(hcam, expTotal, (uns16)roiArray.size(), roiArray.data(), - expMode, expTime, &acqBufferBytes)) - return PvcamError(); - const uns32 frameBytes = acqBufferBytes / expTotal; + std::shared_ptr cam = GetCamera(hcam); + if (!cam) + return NULL; - void* acqBuffer = NULL; { std::lock_guard lock(cam->m_mutex); @@ -857,6 +845,56 @@ static PyObject* pvc_start_seq(PyObject* self, PyObject* args) cam->m_acqAbort = false; cam->m_acqNewFrame = false; cam->m_isSequence = true; + } + + return PyLong_FromUnsignedLong(frameBytes); +} + +/** Starts already set up live acquisition. */ +static PyObject* pvc_start_set_live(PyObject* self, PyObject* args) +{ + int16 hcam; + if (!PyArg_ParseTuple(args, "h", &hcam)) + return ParamParseError(); + + std::shared_ptr cam = GetCamera(hcam); + if (!cam) + return NULL; + + void* acqBuffer = NULL; + uns32 acqBufferBytes = 0; + { + std::lock_guard lock(cam->m_mutex); + + cam->m_fpsFrameCnt = 0; + cam->m_fpsLastTime = std::chrono::high_resolution_clock::now(); + cam->m_acqCbError.clear(); + + acqBuffer = cam->m_acqBuffer->data; + acqBufferBytes = (uns32)cam->m_acqBuffer->size; + } + + if (!pl_exp_start_cont(hcam, acqBuffer, acqBufferBytes)) + return PvcamError(); + + Py_RETURN_NONE; +} + +/** Starts already set up sequence acquisition. */ +static PyObject* pvc_start_set_seq(PyObject* self, PyObject* args) +{ + int16 hcam; + if (!PyArg_ParseTuple(args, "h", &hcam)) + return ParamParseError(); + + std::shared_ptr cam = GetCamera(hcam); + if (!cam) + return NULL; + + void* acqBuffer = NULL; + { + std::lock_guard lock(cam->m_mutex); + cam->m_fpsFrameCnt = 0; cam->m_fpsLastTime = std::chrono::high_resolution_clock::now(); cam->m_acqCbError.clear(); @@ -867,7 +905,43 @@ static PyObject* pvc_start_seq(PyObject* self, PyObject* args) if (!pl_exp_start_seq(hcam, acqBuffer)) return PvcamError(); - return PyLong_FromUnsignedLong(frameBytes); + Py_RETURN_NONE; +} + +/** Starts a live acquisition. */ +static PyObject* pvc_start_live(PyObject* self, PyObject* args) +{ + PyObject* frameBytesObj = pvc_setup_live(self, args); + if (!frameBytesObj) + return NULL; + + PyObject* arg1 = PyTuple_GetSlice(args, 0, 1); // Just hcam + if (!arg1) + return NULL; + + if (!pvc_start_set_live(self, arg1)) + frameBytesObj = NULL; + + Py_DECREF(arg1); + return frameBytesObj; +} + +/** Starts a sequence acquisition. */ +static PyObject* pvc_start_seq(PyObject* self, PyObject* args) +{ + PyObject* frameBytesObj = pvc_setup_seq(self, args); + if (!frameBytesObj) + return NULL; + + PyObject* arg1 = PyTuple_GetSlice(args, 0, 1); // Just hcam + if (!arg1) + return NULL; + + if (!pvc_start_set_seq(self, arg1)) + frameBytesObj = NULL; + + Py_DECREF(arg1); + return frameBytesObj; } /** Returns current acquisition status, works during acquisition only. */ @@ -1547,14 +1621,22 @@ static PyMethodDef pvcMethods[] = { PVC_ADD_METHOD_(check_param, METH_VARARGS, "Checks if a specified setting of a camera is available."), + PVC_ADD_METHOD_(setup_live, METH_VARARGS, + "Sets up live mode acquisition."), + PVC_ADD_METHOD_(setup_seq, METH_VARARGS, + "Sets up sequence mode acquisition."), + PVC_ADD_METHOD_(start_set_live, METH_VARARGS, + "Starts already set up live mode acquisition."), + PVC_ADD_METHOD_(start_set_seq, METH_VARARGS, + "Starts already set up sequence mode acquisition."), PVC_ADD_METHOD_(start_live, METH_VARARGS, - "Starts live mode acquisition."), + "Sets up and starts live mode acquisition."), PVC_ADD_METHOD_(start_seq, METH_VARARGS, - "Starts sequence mode acquisition."), + "Sets up and starts sequence mode acquisition."), PVC_ADD_METHOD_(check_frame_status, METH_VARARGS, "Checks status of frame transfer."), PVC_ADD_METHOD_(get_frame, METH_VARARGS, - "Gets latest frame."), + "Gets oldest or latest frame."), PVC_ADD_METHOD_(finish_seq, METH_VARARGS, "Finishes sequence mode acquisition. Must be called before another start_seq with different configuration."), PVC_ADD_METHOD_(abort, METH_VARARGS, From 2109cd9518839e775a438acd368bb201656d1e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Wed, 1 Oct 2025 16:12:38 +0200 Subject: [PATCH 5/7] Cleaned up PyVCAM documentation, removed chapters for developers only. --- docs/PyVCAM.md | 432 ++++++++++++++----------------------------------- 1 file changed, 119 insertions(+), 313 deletions(-) diff --git a/docs/PyVCAM.md b/docs/PyVCAM.md index b7acc77..a439fb3 100644 --- a/docs/PyVCAM.md +++ b/docs/PyVCAM.md @@ -5,11 +5,10 @@ * [Installing the Package](#installing-the-package) * [Creating a Wheel Package](#creating-a-wheel-package) * [Uninstalling the Package](#uninstalling-the-package) - * [`src` Folder](#src-folder) - * [`pyvcam` Folder](#pyvcam-folder) - * [`camera.py`](#camerapy) + * [`src/pyvcam` Folder](#srcpyvcam-folder) + * [`camera.py` aka `Camera` Class](#camerapy-aka-camera-class) * [Create Camera Example](#create-camera-example) - * [Methods of `Camera` class](#methods-of-camera-class) + * [Methods of `Camera` Class](#methods-of-camera-class) * [Camera Selection](#camera-selection) * [Basic Frame Acquisition](#basic-frame-acquisition) * [Advanced Frame Acquisition](#advanced-frame-acquisition) @@ -19,26 +18,13 @@ * [Properties](#properties) * [Using Properties](#using-properties) * [List of Properties](#list-of-properties) - * [`constants.py`](#constantspy) - * [`pvcmodule.cpp`](#pvcmodulecpp) - * [General Structure of a `pvc` Module Functions](#general-structure-of-a-pvc-module-functions) - * [Retrieving Data](#retrieving-data) - * [Arguments of `PyArg_ParseTuple`](#arguments-of-pyarg_parsetuple) - * [`PyArg_ParseTuple` Example](#pyarg_parsetuple-example) - * [Processing Acquired Data](#processing-acquired-data) - * [Return Data to a Python Script](#return-data-to-a-python-script) - * [Cast to Python Type](#cast-to-python-type) + * [`constants.py` aka `const` Module](#constantspy-aka-const-module) + * [`pvcmodule.cpp` aka `pvc` Module](#pvcmodulecpp-aka-pvc-module) * [Functions of `pvc` Module](#functions-of-pvc-module) - * [The Method Table](#the-method-table) - * [The Module Definition](#the-module-definition) - * [Module Creation](#module-creation) - * [Creating Extension Module](#creating-extension-module) - * [`constants_generator.py`](#constants_generatorpy) - * [Requirements](#requirements) - * [Running the Script](#running-the-script) - * [`tests` Folder](#tests-folder) + * [`examples` Folder](#examples-folder) * [`change_settings_test.py` (needs `camera_settings.py`)](#change_settings_testpy-needs-camera_settingspy) * [`check_frame_status.py`](#check_frame_statuspy) + * [`live_in_subprocess.py`](#live_in_subprocesspy) * [`live_mode.py`](#live_modepy) * [`multi_camera.py`](#multi_camerapy) * [`multi_rois.py`](#multi_roispy) @@ -48,35 +34,35 @@ * [`single_image_polling_show.py`](#single_image_polling_showpy) * [`stream_to_disk.py`](#stream_to_diskpy) * [`sw_trigger.py`](#sw_triggerpy) + * [`tests` Folder](#tests-folder) * [`test_camera.py`](#test_camerapy) *** ## Installing the Package -When you are ready to install the package, navigate to the directory that contains `pyproject.toml` -file and run `python -m pip install .`. +To install the latest stable version, simply run from anywhere `pip install PyVCAM`. + +Optionally, you can build and install the package from the sources. +Navigate to the directory that contains `pyproject.toml` file and run `pip install .`. +Please read the [README.md](https://github.com/Photometrics/PyVCAM/blob/master/README.md) +for more details. ## Creating a Wheel Package To create a PyVCAM Wheel package, navigate to the directory that contains `pyproject.toml` file and run `python -m build`. ## Uninstalling the Package -When you are ready to uninstall the package, run from anywhere `python -m pip uninstall PyVCAM`. +When you are ready to uninstall the package, run from anywhere `pip uninstall PyVCAM`. *** -## `src` Folder +## `src/pyvcam` Folder Where the source code of the `pyvcam` module is located. In addition to the code for the module, -any additional scripts that are used to help write the module are included as well. The most notable -helper script that is not included in the module is `constants_generator.py`, which generates the -`constants.py` module by parsing the PVCAM header file `pvcam.h`. - -## `pyvcam` Folder -The directory that contains the source code to the `pyvcam` module. These are the files installed -when users install the module. +any additional scripts that are used to help write the module are included as well. +These are the files installed when users install the module. -### `camera.py` +### `camera.py` aka `Camera` Class The `camera.py` module contains the `Camera` python class which is used to abstract the need to manually maintain, alter, and remember camera settings through PVCAM. @@ -93,41 +79,39 @@ cam = next(Camera.detect_camera()) # Use generator to find the first camera cam.open() # Open the camera ``` -#### Methods of `Camera` class +#### Methods of `Camera` Class ##### Camera Selection -| Method | Description | -|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `__init__` | (Magic Method) The `Camera`'s constructor. Note that this method should not be used in the construction of a `Camera`. Instead, use the `detect_camera` class method to generate `Camera` classes of the currently available cameras connected to the system. | -| `__repr__` | (Magic Method) Returns the name of the camera. | -| `get_available_camera_names` | Return a list of camera names connected to the system. Use this method in conjunction with `select_camera`. Refer to `multi_camera.py` for a usage example. | -| `detect_camera` | (Class method) Generator that yields a `Camera` object for a camera connected to the system. For an example of how to call `detect_camera`, refer to the code samples for creating a camera. | -| `select_camera` | (Class method) Generator that yields a `Camera` object for the camera that matches the provided name. Use this method in conjunction with `get_available_camera_names`. Refer to `multi_camera.py` for a usage example. | -| `open` | Opens the camera. Will set `__handle` to the correct value and `__is_open` to `True` if a successful call to PVCAM's open camera function is made. A `RuntimeError` will be raised if the call to PVCAM fails. For more information about how Python interacts with the PVCAM library, refer to the `pvcmodule.cpp` section of these notes. | -| `close` | Closes the camera. Will set `__handle` to the default value for a closed camera (`-1`) and will set `__is_open` to `False` if a successful call to PVCAM's close camera function is made. A `RuntimeError` will be raised if the call to PVCAM fails. For more information about how Python interacts with the PVCAM library, refer to the `pvcmodule.cpp` section of these notes. | +| Method | Description | +|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `__init__` | (Magic Method) The `Camera`'s constructor. Note that this method should not be used in the construction of a `Camera`. Instead, use the `detect_camera` class method to generate `Camera` classes of the currently available cameras connected to the system. | +| `__repr__` | (Magic Method) Returns the name of the camera. | +| `get_available_camera_names` | Return a list of camera names connected to the system. Use this method in conjunction with `select_camera`. Refer to `multi_camera.py` for a usage example. | +| `detect_camera` | (Class method) Generator that yields a `Camera` object for a camera connected to the system. For an example of how to call `detect_camera`, refer to the code samples for creating a camera. | +| `select_camera` | (Class method) Generator that yields a `Camera` object for the camera that matches the provided name. Use this method in conjunction with `get_available_camera_names`. Refer to `multi_camera.py` for a usage example. | +| `open` | Opens the camera. Will set `__handle` to the correct value and `__is_open` to `True` if a successful call to PVCAM's open camera function is made. A `RuntimeError` will be raised if the call to PVCAM fails. For more information about how Python interacts with the PVCAM library, refer to the `pvcmodule.cpp` section of these notes. | +| `close` | Closes the camera. Will set `__handle` to the default value for a closed camera (`-1`) and will set `__is_open` to `False` if a successful call to PVCAM's close camera function is made. A `RuntimeError` will be raised if the call to PVCAM fails. For more information about how Python interacts with the PVCAM library, refer to the `pvcmodule.cpp` section of these notes. | ##### Basic Frame Acquisition -| Method | Description | -|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `get_frame` | Calls the `pvc` module's `get_frame` function with current camera settings to get a 2D numpy array of pixel data from a single snap image. This method can either be called with or without a given exposure time. If given, the method will use the given parameter. Otherwise, if left out, will use the internal `exp_time` attribute.

          **Parameters:**
          • Optional: `exp_time` (int): The exposure time to use.
          • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
          • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`.
          | -| `get_sequence` | Calls the `pvc` module's `get_frame` function with cameras current settings in rapid-succession to get a 3D numpy array of pixel data from a single snap image. Multiple ROIs are not supported.

          **Getting a sequence example:**
          `# Given that the camera is already opened as openCam`
          `stack = openCam.get_sequence(8) # Getting a sequence of 8 frames`
          `firstFrame = stack[0] # Accessing 2D frames from 3D stack`
          `lastFrame = stack[7]`

          **Parameters:**
          • `num_frames` (int): The number of frames to be captured in the sequence.
          • Optional: `exp_time` (int): The exposure time to use.
          • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
          • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`.
          | -| `get_vtm_sequence` | Modified `get_sequence` to be used for Variable Timed Mode. Before calling it, set the camera's exposure mode to `'Variable Timed'`. The timings will always start at the first given and keep looping around until it is captured the number of frames given. Multiple ROIs are not supported.

          **Parameters:**
          • `time_list` (list of int): The timings to be used by the camera in Variable Timed Mode.
          • `exp_res` (int): The exposure time resolution. Supported are milliseconds (`0`), and for selected cameras also microseconds (`1`) and seconds (`2`). Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) `PARAM_EXP_RES` and `PARAM_EXP_RES_INDEX`.
          • `num_frames` (int): The number of frames to be captured in the sequence.
          • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
          • Optional: `interval` (int): Time to between each sequence frame (in milliseconds).
          • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`.
          | +| Method | Description | +|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `get_frame` | Calls the `pvc` module's `get_frame` function with current camera settings to get a 2D numpy array of pixel data from a single snap image. This method can either be called with or without a given exposure time. If given, the method will use the given parameter. Otherwise, if left out, will use the internal `exp_time` property.

          **Parameters:**
          • Optional: `exp_time` (int): The exposure time to use. Default is `None` which will use the value set via `exp_time` property.
          • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
          • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`. Default is `False`.
          | +| `get_sequence` | Calls the `pvc` module's `get_frame` function with cameras current settings in rapid-succession to get a 3D numpy array of pixel data from a single snap image. Multiple ROIs are not supported.

          **Getting a sequence example:**
          `# Given that the camera is already opened as openCam`
          `stack = openCam.get_sequence(8) # Getting a sequence of 8 frames`
          `firstFrame = stack[0] # Accessing 2D frames from 3D stack`
          `lastFrame = stack[7]`

          **Parameters:**
          • `num_frames` (int): The number of frames to be captured in the sequence.
          • Optional: `exp_time` (int): The exposure time to use. Default is `None` which will use the value set via `exp_time` property.
          • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
          • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`. Default is `False`.
          | +| `get_vtm_sequence` | Modified `get_sequence` to be used for Variable Timed Mode. Before calling it, set the camera's exposure mode to `'Variable Timed'`/`const.VARIABLE_TIMED_MODE`. If the camera doesn't support this mode or when the mode is not set, this function will emulate the same behavior as a sequence of single snaps with given exposure times. The timings will always start at the first given and keep looping around until it is captured the number of frames given. Multiple ROIs are not supported.

          **Parameters:**
          • `time_list` (list of int): The exposure times to be used by the camera.
          • `exp_res` (int): The exposure time resolution. Supported are milliseconds (`0`/`const.EXP_RES_ONE_MILLISEC`), and for selected cameras also microseconds (`1`/`EXP_RES_ONE_MICROSEC`) and seconds (`2`/`EXP_RES_ONE_SEC`). Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) `PARAM_EXP_RES` and `PARAM_EXP_RES_INDEX`.
          • `num_frames` (int): The number of frames to be captured in the sequence.
          • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
          • Optional: `interval` (int): Time between each sequence frame (in milliseconds). Default is `None`.
          • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`. Default is `False`.
          | ##### Advanced Frame Acquisition -| Method | Description | -|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `start_live` | Calls `pvc.start_live` to setup a live mode acquisition. This must be called before `poll_frame`.

          **Parameters:**
          • Optional: `exp_time` (int): The exposure time for the acquisition. If not provided, the `exp_time` attribute is used.
          • Optional: `buffer_frame_count` (int): The number of frames in the circular frame buffer. The default is 16 frames.
          • Optional: `stream_to_disk_path` (str): The file path for data written directly to disk by PVCAM. The default is `None` which disables this feature.
          • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`.
          | -| `start_seq` | Calls `pvc.start_seq` to setup a sequence mode acquisition. This must be called before `poll_frame`.

          **Parameters:**
          • Optional: `exp_time` (int): The exposure time for the acquisition. If not provided, the `exp_time` attribute is used.
          • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`.
          | -| `check_frame_status` | Calls `pvc.check_frame_status` to report status of camera. This method can be called regardless of an acquisition being in progress.

          **Parameters:**
          • None
          | -| `poll_frame` | Returns a single frame as a dictionary with optional metadata if available. This method must be called after either `start_live` or `start_seq` and before either `abort` or `finish`. Pixel data can be accessed via the `'pixel_data'` key. Available metadata can be accessed via the `'meta_data'` key.

          If multiple ROIs are set, pixel data will be a list of region pixel data of length number of ROIs. Metadata will also contain information for ech ROI.

          Use `cam.set_param(constants.PARAM_METADATA_ENABLED, True)` or `cam.metadata_enabled = True` to enable the metadata.


        **Parameters:**
        • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
        • Optional: `oldestFrame` (bool): If `True`, the returned frame will the oldest frame and will be popped off the queue. If `False`, the returned frame will be the newest frame and will not be removed from the queue. Default is `True`.
        • Optional: `copyData` (bool): Returned numpy frames will contain a copy of image data. Without this copy, the numpy frame image data will point directly to the underlying frame buffer used by PVCAM. Disabling this copy will improve performance and decrease memory usage, but care must be taken. In live and sequence mode, frame memory is unallocated when calling abort or finish. In live mode, a circular frame buffer is used so frames are continuously overwritten. Default is `True`.
        | -| `reset_frame_counter` | Resets `frame_count` returned by `poll_frame` to zero.

        **Parameters:**
        • None
        | -| `abort` | Calls `pvc.abort` to return the camera to its normal state prior to completing acquisition.

        **Parameters:**
        • None
        | -| `finish` | Calls either `pvc.stop_live` or `pvc.finish_seq` to return the camera to its normal state after acquiring images.

        **Parameters:**
        • None
        | +| Method | Description | +|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `start_live` | Calls `pvc.start_live` to setup a live mode acquisition. This must be called before `poll_frame`.

        **Parameters:**
        • Optional: `exp_time` (int): The exposure time for the acquisition. If not provided, the `exp_time` property is used.
        • Optional: `buffer_frame_count` (int): The number of frames in the circular frame buffer. The default is 16 frames.
        • Optional: `stream_to_disk_path` (str): The file path for data written directly to disk by PVCAM. The default is `None` which disables this feature.
        • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`.
        | +| `start_seq` | Calls `pvc.start_seq` to setup a sequence mode acquisition. This must be called before `poll_frame`.

        **Parameters:**
        • Optional: `exp_time` (int): The exposure time for the acquisition. If not provided, the `exp_time` property is used.
        • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`.
        | +| `check_frame_status` | Calls `pvc.check_frame_status` to report status of camera. This method can be called regardless of an acquisition being in progress.

        **Parameters:**
        • None
        | +| `poll_frame` | Returns a single frame as a dictionary with optional metadata if available. This method must be called after either `start_live` or `start_seq` and before `finish`. Pixel data can be accessed via the `'pixel_data'` key. Available metadata can be accessed via the `'meta_data'` key.

        If multiple ROIs are set, pixel data will be a list of region pixel data of length number of ROIs. Metadata will also contain information for ech ROI.

        Use `cam.set_param(constants.PARAM_METADATA_ENABLED, True)` or `cam.metadata_enabled = True` to enable the metadata.


      **Parameters:**
      • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
      • Optional: `oldestFrame` (bool): If `True`, the returned frame will the oldest frame and will be popped off the queue. If `False`, the returned frame will be the newest frame and will not be removed from the queue. Default is `True`.
      • Optional: `copyData` (bool): Returned numpy frames will contain a copy of image data. Without this copy, the numpy frame image data will point directly to the underlying frame buffer used by PVCAM. Disabling this copy will improve performance and decrease memory usage, but care must be taken. In live and sequence mode, frame memory is unallocated when calling abort or finish. In live mode, a circular frame buffer is used so frames are continuously overwritten. Default is `True`.
      | +| `finish` | Calls either `pvc.abort` or `pvc.finish_seq` to return the camera to its normal state after acquiring images.

      **Parameters:**
      • None
      | ##### Acquisition Configuration | Method | Description | |--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `reset_rois` | Restores region of interest to default which is full frame with binning disabled.

      **Parameters:**
      • None
      | +| `reset_rois` | Restores region of interest to default which is full frame with binning disabled (1x1).

      **Parameters:**
      • None
      | | `set_roi` | Appends a new ROI to the camera's list of regions of interest. If the default ROI is currently set, this method will over-write that ROI. Each camera has a pre-defined maximum number of ROIs, which is typically 15. New ROIs can not exceed the boundaries of the sensor and can not overlap with existing ROIs.

      **Parameters:**
      • `s1`(int): Serial (X) coordinate of the ROI top-left corner.
      • `p1`(int): Parallel (Y) coordinate of the ROI top-left corner.
      • `width`(int): Num pixels in serial direction.
      • `height`(int): Num pixels in parallel direction.
      | | `shape` | Returns the reshape factor to be used when acquiring a ROI. This is equivalent to an acquired images shape.

      **Parameters:**
      • `roi_index`
      | @@ -139,11 +123,11 @@ cam.open() # Open the camera ##### Parameters | Method | Description | |-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `get_param` | Gets the current value of a specified attribute of given parameter. Usually not called directly since the properties (see below) will handle most cases of getting camera attributes. However, not all cases may be covered by the properties and a direct call may need to be made to PVCAM's `pl_get_param` function.

      **Parameters**:
      • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and `constants.py` section for list of available parameter ID values.
      • `param_attr` (int): The PVCAM defined value that corresponds to an attribute of a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and `constants.py` section for list of available attribute ID values.
      | -| `set_param` | Sets a specified camera parameter to a new value. Usually not called directly since the properties (see below) will handle most cases of setting camera attributes. However, not all cases may be covered by the properties and a direct call may need to be made to PVCAM's `pl_set_param` function.

      **Parameters:**
      • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and `constants.py` section for list of available parameter ID values.
      • `value` (various): The value to set the camera setting to. Make sure that its type closely matches the attribute's type so it can be properly set. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) for all possible attributes and their types.
      | +| `get_param` | Gets the current value of a specified attribute of given PVCAM parameter. Usually not called directly since the properties (see below) will handle most cases of getting camera parameters. However, not all cases may be covered by the properties and a direct call may need to be made to PVCAM's `pl_get_param` function.

      **Parameters**:
      • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and `constants.py` section for list of available parameter ID values.
      • `param_attr` (int): The PVCAM defined value that corresponds to an attribute of a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and `constants.py` section for list of available attribute ID values.
      | +| `set_param` | Sets a specified camera parameter to a new value. Usually not called directly since the properties (see below) will handle most cases of setting camera parameters. However, not all cases may be covered by the properties and a direct call may need to be made to PVCAM's `pl_set_param` function.

      **Parameters:**
      • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and `constants.py` section for list of available parameter ID values.
      • `value` (various): The value to set the camera setting to. Make sure that its type closely matches the attribute's type so it can be properly set. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) for all possible attributes and their types.
      | | `check_param` | Checks if a camera parameter is available. This method is useful for checking certain features are available (such as post-processing, expose out mode). Returns `True` if available, `False` if not.

      **Parameters:**
      • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and constants.py section for list of available parameter ID values.
      | -| `get_post_processing_param` | Gets the current value of a specified post-processing parameter.

      **Parameters**:
      • `feature_name` (str): A string name for the post-processing feature using this parameter. Feature names can be determined from the `post_processing_table` attribute.
      • `param_name` (str): A string name for the post-processing parameter. Parameter names can be determined from the `post_processing_table` attribute.
      | -| `set_post_processing_param` | Sets the value of a specified post-processing parameter.

      **Parameters**:
      • `feature_name` (str): A string name for the post-processing feature using this parameter. Feature names can be determined from the `post_processing_table` attribute.
      • `param_name` (str): A string name for the post-processing parameter. Parameter names can be determined from the `post_processing_table` attribute.
      • `value` (int): The value to be assigned to the post-processing parameter. Value must fall within the range provided by the `post_processing_table` attribute.
      | +| `get_post_processing_param` | Gets the current value of a specified post-processing parameter.

      **Parameters**:
      • `feature_name` (str): A string name for the post-processing feature using this parameter. Feature names can be determined from the `post_processing_table` property.
      • `param_name` (str): A string name for the post-processing parameter. Parameter names can be determined from the `post_processing_table` property.
      | +| `set_post_processing_param` | Sets the value of a specified post-processing parameter.

      **Parameters**:
      • `feature_name` (str): A string name for the post-processing feature using this parameter. Feature names can be determined from the `post_processing_table` property.
      • `param_name` (str): A string name for the post-processing parameter. Parameter names can be determined from the `post_processing_table` property.
      • `value` (int): The value to be assigned to the post-processing parameter. Value must fall within the range provided by the `post_processing_table` property.
      | | `reset_pp` | If post-processing is available on the camera, the function will call `pvc.reset_pp` to reset all post-processing features back to their default state.

      **Parameters:**
      • None
      | | `read_enum` | Returns all settings names paired with their values of a specified setting.

      **Parameters:**
      • `param_id` (int): The parameter ID.
      | @@ -152,51 +136,50 @@ All properties are accessed via getters and setters. This means that it will app accessing instance variables from a camera, but in reality, these properties are making specially formatted calls to the `Camera` methods `get_param` and `set_param`. These getters and setters make use of the property decorator that is built into Python. The reasoning behind the usage of the -property decorator is that attributes will change dynamically during a `Camera`'s lifetime and in +property decorator is that properties will change dynamically during a `Camera`'s lifetime and in order to abstract PVCAM as far away from the end user as possible, the property decorator allows for users to intuitively view and change camera settings. The downside to this approach is that when a new parameter is required, an associated getter/setter -needs to be written and tested. Another downside to this implementation is that attribute lookup -time is not instant; instead, a call must be made to the `pvc` module wrapper which will then call -PVCAM, which will then return a result to the wrapper, which will finally return the result to the -user. The time it takes is currently considered -insignificant, but if this were to become an issue, the code could be refactored such that all -attributes also have instance variables which are changed only when `set_param` or their associated -setter is called on them. +needs to be written and tested. Another downside to this implementation is that property lookup +time is not instant; instead, a call must be made to the `pvc` module which will then call PVCAM, +which will then return a result to the wrapper, which will finally return the result to the user. +The time it takes is currently considered insignificant, but if this were to become an issue, +the code could be refactored such that all properties also have instance variables which are changed +only when `set_param` or their associated setter is called on them. ##### Using Properties ``` # Assume 'cam' is an already constructed 'Camera' instance -current_gain = cam.gain # To call getter, simply read the property value +current_gain = cam.gain # To call getter, simply read the property value cam.gain = current_gain # To call setter, simply assign new value to the property ``` ##### List of Properties | Property | Description | |-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `adc_offset` | (read-only) **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the camera's current ADC offset value. Only CCD camera's have ADCs (analog-to-digital converters). | +| `adc_offset` | (read-only) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the camera's current ADC offset value. Only CCD camera's have ADCs (analog-to-digital converters). | | `binning` | (read-write) Returns or changes the current serial and parallel binning values in a tuple.

      The setter can be either a tuple for the binning (x, y) or a single value and will set a square binning with the given number, for example `cam.binning = x` makes `cam.__binning = (x, x)`.

      Binning cannot be changed directly on the camera; but is used for setting up acquisitions and returning correctly shaped images returned from `get_frame`. The setter has built in checking to see that the given binning it able to be used later. Binning settings for individual ROIs is not supported. | | `binnings` | (read-only) Returns a list of supported combinations of serial and parallel binning factors if limited by the camera. If the camera supports arbitrary binning `None` is retuned. | | `bit_depth` | (read-only) Returns the native bit depth of pixel data for images collected with this camera.
      Bit depth cannot be changed directly; instead, users must select a desired speed that has the desired bit depth. Note that a camera may have additional speed table entries for different readout ports. See [Port and Speed Choices](https://docs.teledynevisionsolutions.com/_speed_table.xhtml) section inside the PVCAM User Manual for a visual representation of a speed table and to see which settings are controlled by which speed is currently selected. | | `bit_depth_host` | (read-only) Returns the bit depth of pixel data outputted to the host. This parameter differs from the `bit_depth` in a way that it reports the bit depth of the output frame - a frame that is delivered to the host. Since PVCAM supports various host side post processing features, the host bit depth may differ from the native camera bit depth, depending on what host-side post processing features are active.
      As a general rule, the application should always rely on the host-specific parameters when identifying the output data format. The native parameters should be used only for informational purposes, e.g. to show the camera native format in the GUI. | | `cam_fw` | (read-only) Returns the cameras current firmware version as a string. | -| `centroids_mode` | (read-write) **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the current centroids mode, `'Locate'`, `'Track'` or `'Blob'`. | +| `centroids_mode` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the current centroids mode, `'Locate'`/`const.PL_CENTROIDS_MODE_LOCATE`, `'Track'`/`const.PL_CENTROIDS_MODE_TRACK` or `'Blob'`/`const.PL_CENTROIDS_MODE_BLOB`. | | `centroids_modes` | (read-only) Returns a dictionary containing centroid modes supported by the camera. | | `chip_name` | (read-only) Returns the camera sensor's name as a string. | -| `clear_mode` | (read-write): **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the current clear mode of the camera. Note that clear modes have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the clear mode of a camera, either the integer value or the name of the clear mode can be specified. Refer to `constants.py` for the names of the clear modes. | +| `clear_mode` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the current clear mode of the camera. Note that clear modes have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the clear mode of a camera, either the integer value or the name of the clear mode can be specified. Refer to `constants.py` for the names of the clear modes. | | `clear_modes` | (read-only) Returns a dictionary containing clear modes supported by the camera. | -| `clear_time` | (read-only): **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the last acquisition's clearing time as reported by the camera in microseconds. | +| `clear_time` | (read-only): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the last acquisition's clearing time as reported by the camera in microseconds. | | `driver_version` | (read-only) Returns a formatted string containing the major, minor, and build version. When `get_param` is called on the device driver version, it returns a highly formatted 16 bit integer. The first 8 bits correspond to the major version, bits 9-12 are the minor version, and the last nibble is the build number. | | `exp_mode` | (read-write): Returns or changes the current exposure mode of the camera. Note that exposure modes have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the exposure mode of a camera, either the integer value or the name of the expose out mode can be specified. Refer to `constants.py` for the names of the exposure modes. | | `exp_modes` | (read-only) Returns a dictionary containing exposure modes supported by the camera. | -| `exp_out_mode` | (read-write): **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns or changes the current expose out mode of the camera. Note that expose out modes have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the expose out mode of a camera, either the integer value or the name of the expose out mode can be specified. Refer to `constants.py` for the names of the expose out modes. | +| `exp_out_mode` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns or changes the current expose out mode of the camera. Note that expose out modes have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the expose out mode of a camera, either the integer value or the name of the expose out mode can be specified. Refer to `constants.py` for the names of the expose out modes. | | `exp_out_modes` | (read-only) Returns a dictionary containing exposure out modes supported by the camera. | | `exp_res` | (Getter and setter) Returns/changes the current exposure resolution of a camera. Note that exposure resolutions have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the exposure resolution of a camera, either the integer value or the name of the resolution can be specified. Refer to `constants.py` for the names of the exposure resolutions. | | `exp_res_index` | (read-only): Returns the current exposure resolution index. | | `exp_resolutions` | (read-only) Returns a dictionary containing exposure resolutions supported by the camera. | | `exp_time` | (read-write): Returns or changes the exposure time the camera will use if not given an exposure time. It is recommended to modify this value to modify your acquisitions for better abstraction. | -| `fan_speed` | (read-write): **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the current fan speed setpoint of the camera. Note that fan speeds have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the fan speed of a camera, either the integer value or the name of the fan speed can be specified. Refer to `constants.py` for the names of the fan speeds. | +| `fan_speed` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the current fan speed setpoint of the camera. Note that fan speeds have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the fan speed of a camera, either the integer value or the name of the fan speed can be specified. Refer to `constants.py` for the names of the fan speeds. | | `fan_speeds` | (read-only) Returns a dictionary containing fan speeds supported by the camera. | | `gain` | (read-write) Returns or changes the current gain index for a camera. A `ValueError` will be raised if an invalid gain index is supplied to the setter. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. | | `gain_name` | (read-only) Returns the name of currently selected gain via `gain` under selected port and speed. It is either hard-coded generic string or provided by the camera. | @@ -208,268 +191,82 @@ cam.gain = current_gain # To call setter, simply assign new value to the proper | `pix_time` | (read-only) Returns the camera's pixel time, which is the inverse of the speed of the camera. Pixel time cannot be changed directly; instead users must select a desired speed that has the desired pixel time. Note that a camera may have additional speed table entries for different readout ports. See [Port and Speed Choices](https://docs.teledynevisionsolutions.com/_speed_table.xhtml) section inside the PVCAM User Manual for a visual representation of a speed table and to see which settings are controlled by which speed table entry is currently selected. | | `port_speed_gain_table` | (read-only) Returns a dictionary containing the port, speed and gain table, which gives information such as bit depth and pixel time for each readout port, speed and gain. | | `post_processing_table` | (read-only) Returns a dictionary containing post-processing features and parameters as well as the minimum and maximum value for each parameter. | -| `post_trigger_delay` | (read-only): **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the last acquisition's post-trigger delay as reported by the camera in microseconds. | -| `pre_trigger_delay` | (read-only): **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the last acquisition's pre-trigger delay as reported by the camera in microseconds | -| `prog_scan_mode` | (read-write) **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the current programmable scan mode, Auto, Line Delay or Scan Width. | +| `post_trigger_delay` | (read-only): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the last acquisition's post-trigger delay as reported by the camera in microseconds. | +| `pre_trigger_delay` | (read-only): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the last acquisition's pre-trigger delay as reported by the camera in microseconds | +| `prog_scan_mode` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the current programmable scan mode, `Auto`/`const.PL_SCAN_MODE_AUTO`, `Line Delay`/`const.PL_SCAN_MODE_PROGRAMMABLE_LINE_DELAY` or `Scan Width`/`const.PL_SCAN_MODE_PROGRAMMABLE_SCAN_WIDTH`. | | `prog_scan_modes` | (read-only) Returns a dictionary containing programmable scan modes supported by the camera. | -| `prog_scan_dir` | (read-write) **Warning: Camera specific setting. Not all camera's support this attribute. If an unsupported camera attempts to access its readout_port, an AttributeError will be raised.**

      Returns/changes the current programmable scan direction, `'Auto'`, `'Line Delay'` or `'Scan Width'`. | +| `prog_scan_dir` | (read-write) **Warning: Camera specific setting. Not all camera's support this parameter. If an unsupported camera attempts to access its readout_port, an AttributeError will be raised.**

      Returns/changes the current programmable scan direction, `'Down'`/`const.PL_SCAN_DIRECTION_DOWN`, `'Up'`/`const.PL_SCAN_DIRECTION_UP` or `'Down/Up Alternate'`/`const.PL_SCAN_DIRECTION_DOWN_UP`. | | `prog_scan_dirs` | (read-only) Returns a dictionary containing programmable scan directions supported by the camera. | -| `prog_scan_dir_reset` | (read-write) **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes scan direction reset state of camera. The parameter is used with alternate scan directions (down-up) to reset the direction with every acquisition. | -| `prog_scan_line_delay` | (read-write) **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the scan line delay. The parameter access mode depends on the `prog_scan_mode` selection. | -| `prog_scan_width` | (read-write) **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the scan width. The parameter access mode depends on the `prog_scan_mode` selection. | -| `readout_port` | (read-write) **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Some cameras may have many readout ports, which are output nodes from which a pixel stream can be read from. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. For more information about readout ports, refer to the [Port and Speed Choices](https://docs.teledynevisionsolutions.com/_speed_table.xhtml) section inside the PVCAM User Manual. | +| `prog_scan_dir_reset` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes scan direction reset state of camera. The parameter is used with alternate scan directions (down-up) to reset the direction with every acquisition. | +| `prog_scan_line_delay` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the scan line delay. The parameter access mode depends on the `prog_scan_mode` selection. | +| `prog_scan_width` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the scan width. The parameter access mode depends on the `prog_scan_mode` selection. | +| `readout_port` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Some cameras may have many readout ports, which are output nodes from which a pixel stream can be read from. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. For more information about readout ports, refer to the [Port and Speed Choices](https://docs.teledynevisionsolutions.com/_speed_table.xhtml) section inside the PVCAM User Manual. | | `readout_ports` | (read-only) Returns a dictionary containing readout ports supported by the camera. | | `readout_time` | (read-only): Returns the last acquisition's readout time as reported by the camera in microseconds. | -| `scan_line_time` | (Getter) **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the scan line time of camera in nano seconds. | +| `scan_line_time` | (Getter) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the scan line time of camera in nano seconds. | | `sensor_size` | (read-only) Returns the sensor size of the current camera in a tuple in the form (serial sensor size, parallel sensor size) | | `serial_no` | (read-only) Returns the camera's serial number as a string. | | `speed` | (read-write) Returns or changes the current numerical index of the speed table of a camera. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. See the [Port and Speed Choices](https://docs.teledynevisionsolutions.com/_speed_table.xhtml) section inside the PVCAM User Manual for a detailed explanation about PVCAM speed tables. | | `speed_name` | (read-only) Returns the name of currently selected speed via `speed` under selected port. It is either hard-coded generic string or provided by the camera. | -| `temp` | (read-only): **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the current temperature of a camera in Celsius. | -| `temp_setpoint` | (read-write): **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the camera's temperature setpoint. The temperature setpoint is the temperature that a camera will attempt to keep its temperature (in Celsius) at. | +| `temp` | (read-only): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns the current temperature of a camera in Celsius. | +| `temp_setpoint` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns/changes the camera's temperature setpoint. The temperature setpoint is the temperature that a camera will attempt to keep its temperature (in Celsius) at. | | `trigger_table` | (read-only) Returns a dictionary containing a table consisting of information of the last acquisition such as exposure time, readout time, clear time, pre-trigger delay, and post-trigger delay. If any of the parameters are unavailable, the dictionary item will be set to `'N/A'`. | -| `vtm_exp_time` | (read-write): **Warning: Camera specific setting. Not all cameras support this attribute. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns or changes the variable timed exposure time the camera uses for the `'Variable Timed'` exposure mode. | +| `vtm_exp_time` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

      Returns or changes the variable timed exposure time the camera uses for the `'Variable Timed'` exposure mode.

      Warning: New sequence acquisition must be started after setting this property to apply the value to the camera. Reading the value right after it was written will return a value from last VTM acquisition. If unsure, use `get_vtm_sequence` function instead. | -### `constants.py` +### `constants.py` aka `const` Module The `constants.py` is a large data file that contains various camera settings and internal PVCAM structures used to map meaningful variable names to predefined integer values that camera firmware interprets as settings. -This file is not (and should never be) constructed by hand. Instead, use the most recent version -of `pvcam.h` and run `constants_generator.py` to (re)build this file. A more detailed explanation -can be found under the `constants_generator.py` section, but the basic concept is that `pvcam.h` is -parsed line by line, finding all predefined constants, enums, and structs to grant Python users -access to the necessary data to perform basic PVCAM functions that have multiple settings. - -There are four main sections to this file that are found following a formatted comment like this -`# # # # # #`: - -1. Defines - 1. Much of the necessary data from `pvcam.h` is saved as C preprocessor macros which are easy to - strip from the file and construct a Python variable whose name is the macros name and the - value is what the macro expands to. - 2. Macros can be thought of as Python variables in this case, as none (of the necessary macros) - in `pvcam.h` expand to more than a literal. -2. Enums - 1. Enums (also known as enumerated types) are data types that contain named members used to - identify certain integer values. Typically, if no values are specified, the first member will - be assigned the value 0, and the successor will be 1+ the value of their predecessor. However, - you can specify specific numbers for all members. - 2. Vanilla Python has no enum type (it must be imported; see documentation here), and even still - Python's enum class behaves somewhat differently in terms of accessing members. Instead, we - will insert a comment above all enumerated types and have their members just be simple Python - variables whose values where the integer assigned to them in the `pvcam.h` file. -3. Structs - 1. Structs are preserved as Python classes. No testing/implementation has been done with these, - so results may be unexpected if implemented. -4. Added By Hand - 1. These are quality of life/readability dictionaries that map named settings of various camera - modes to their `pvcam.h` integer value. These allow for fast look-up and intuitive setting - changes for end users. - -### `pvcmodule.cpp` +This file is not (and should never be) constructed by hand. Instead, it is generated with the most +recent version of `pvcam.h` and by running `constants_generator.py`. + +### `pvcmodule.cpp` aka `pvc` Module The `pvcmodule.cpp` is a set of C++ functions that make use of and extend the Python C-API known as -a Python Extension Module. The need for a Python extension module is two-fold: first to allow +a Python Extension Module `pvc`. The need for a Python extension module is two-fold: first to allow communication between the static PVCAM library and Python scripts, and second for fast acquisition and conversion from native C types (namely C arrays of pixel data) to Python data types. The extension module needs to be compiled, so it will be necessary to have a C/C++ compiler to -successfully install this application. The module will be compiled into a shared-object library, -which can then be imported from Python; read more here. - -#### General Structure of a `pvc` Module Functions -The registered functions of a `pvc` module usually follow a three-step process: -1. Retrieve data from Python script -2. Process acquired data -3. Return data to Python script - -#### Retrieving Data -Functions receive data dynamically through use of parameters, and the `pvc` module's functions are -no different. However, the Python API states that all data is of type `PyObject`, which the C/C++ -programming language offer no builtin support for. In addition to, each Python-facing function must -only have two arguments: `PyObject* self` (a pointer to the instance of whichever Python object -called this C function) and `PyObject* args` (a Python tuple object that contains all the arguments -passed into the C function call). - -However, we can make use of the `PyArg_ParseTuple` (see example here) function from the Python API -to easily coerce the Python objects from the args tuple to their respective C type. In order for -the conversion to occur, we must specify which type we want to coerce each Python argument to using -a formatted string (see second argument for `PyArg_ParseTuple`). Each character in the formatted -string are known as "format units" and are interpreted in the same order that the variables for -the coerced C data are provided. Find below a small list of C data types and their corresponding -format units. Use Python documentation for complete list. - -| C Type | Character Representation | -|------------------------|--------------------------| -| `long` | `l` | -| `int` | `i` | -| `double` | `d` | -| `float` | `f` | -| string (`const char*`) | `s` | -| `PyObject` | `O` | - -#### Arguments of `PyArg_ParseTuple` -1. `args` (`PyObject*`) - A Python tuple object that contains the arguments from the Python function - call. For example, if a function call from Python is made: `my_c_func(1, "test")`, the `args` - tuple would contain two `PyObject` pointers: one to the Python integer 1 and another to the - Python Unicode-String `"test"`. -2. `format` (`const char*`) - A String containing the format units for all the arguments found in - the args in the same order in which they appear in the tuple. Going off of the example from the - previous argument, the desired formatted string would be `"is"`: `'i'` for the integer 1, and - `'s'` for the string `"test"`. - -In addition to these two arguments, addresses to the variables in which the coerced C data should be -stored must also be passed as arguments to the `PyArg_ParseTuple` call. (See example for more details). - -#### `PyArg_ParseTuple` Example -``` -static PyObject* example(PyObject* self, PyObject* args) -{ - int myNum; - char* myString; - PyArg_ParseTuple(args, "is", &myNum, &myString); - printf("myNum: %d\n", myNum); // Prints "myNum: 1" - printf("myString: %s\n", myString); // Prints "myString: test" - Py_RETURN_NONE; -} -``` - -#### Processing Acquired Data -Using the data supplied by the Python function call, we can now perform normal camera operations -using PVCAM library function calls. The most common form of processing acquired data is to read the -camera handle from the arguments provided, then performing a camera operation (changing/reading -settings, getting images, etc.) using the acquired handle to identify which camera to perform the -action on. - -Generally speaking, this part of the function should be very similar to writing normal C/C++ modules -that use the PVCAM library. If there is any confusion about how to write C/C++ code to make calls to -PVCAM, refer to the PvcamCodeSamples found in the Examples directory of the PVCAM SDK. - -Sometimes, processing data from a Python function call may entail answering a query. If this is the -case, we need to specify what to return, and how to convert it into a corresponding Python type. - -#### Return Data to a Python Script -Similar to how issues arose when passing data from the Python function call to the C/C++ module, -there is no simple casting solution to convert C/C++ data types to Python data types when returning -from a function. - -Thankfully, there are some functions that were included in the Python header file included at the -top of each module to allow us to cast data to an equivalent Python type. - -#### Cast to Python Type -``` -{ - ... - const char* myString = "ika"; - return PyUnicode_FromString(myString); // Returns a Python string back to the calling function -} -``` - -There is one small catch, however. All Python functions must return an object; there is no such -thing as a `void` function. This means that we must always return something in our C/C++ modules as -well (which we can tell by looking at the signature). -If you wish to return `None`, simply use the `Py_RETURN_NONE` macro (see the `PyArg_ParseTuple` -example for a visual representation). +successfully install PyVCAM. The module will be compiled into a shared-object library, +which can then be imported from Python. #### Functions of `pvc` Module **Note:** All functions will always have the `PyObject* self` and `PyObject* args` parameters. When parameters are listed, they are the Python parameters that are passed into the module. -| Function Name | Description | -|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `pvc_abort` | Given a camera handle, aborts any ongoing acquisition and de-registers the frame handler callback function.

      **Parameters:**
      • Python int (camera handle).
      • | -| `pvc_check_frame_status` | Given a camera handle, returns the current frame status as a string. Possible return values:
        • `'READOUT_NOT_ACTIVE'`
        • `'EXPOSURE_IN_PROGRESS'`
        • `'READOUT_IN_PROGRESS'`
        • `'READOUT_COMPLETE'`/`'FRAME_AVAILABLE'`
        • `'READOUT_FAILED'`
        **Parameters:**
        • Python int (camera handle).
        | -| `pvc_check_param` | Given a camera handle and parameter ID, returns `True` if the parameter is available on the camera.

        **Parameters:**
        • Python int (camera handle).
        • Python int (parameter ID).
        | -| `pvc_close_camera` | Given a camera handle, closes the camera. Returns `True` upon success. `ValueError` is raised if invalid parameter is supplied. `RuntimeError` raised otherwise.

        **Parameters:**
        • Python int (camera handle).
        | -| `pvc_finish_seq` | Given a camera handle, finalizes sequence acquisition and cleans up resources. If a sequence is in progress, acquisition will be aborted.

        **Parameters:**
        • Python int (camera handle).
        | -| `pvc_get_cam_fw_version` | Given a camera handle, returns camera firmware version as a string.

        **Parameters:**
        • Python int (camera handle).
        | -| `pvc_get_cam_name` | Given a Python integer corresponding to a camera handle, returns the name of the camera with the associate handle.

        **Parameters:**
        • Python int (camera handle).
        | -| `pvc_get_cam_total` | Returns the total number of cameras currently attached to the system as a Python integer. | -| `pvc_get_frame` | Given a camera and a region, returns a Python numpy array of the pixel values of the data. Numpy array returned on success. `ValueError` raised if invalid parameters are supplied. `MemoryError` raised if unable to allocate memory for the camera frame. `RuntimeError` raised otherwise.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (Numpy data type enumeration value)
        • Python int (Frame timeout in milliseconds. Negative values will wait forever)
        • Python bool (Flag selecting oldest or newest frame)
        | -| `pvc_get_param` | Given a camera handle, a parameter ID, and the attribute of the parameter in question (AVAIL, CURRENT, etc.) returns the value of the parameter at the current attribute.

        **Note: This setting will only return a Python int or a Python string. Currently no other types are supported, but it is possible to extend the function as needed.**

        `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised if camera does not support the specified parameter. `RuntimeError` is raised otherwise.

        **Parameters:**
        • Python int (camera handle).
        • Python int (parameter ID).
        • Python int (parameter attribute).
        | -| `pvc_get_pvcam_version` | Returns a Python Unicode String of the current PVCAM version. | -| `pvc_init_pvcam` | Initializes the PVCAM library. Raises `RuntimeError` on failure. | -| `pvc_open_camera` | Given a Python string corresponding to a camera name, opens the camera. Returns `True` upon success. `ValueError` is raised if invalid parameter is supplied. `RuntimeError` raised otherwise.

        **Parameters:**
        • Python string (camera name).
        | -| `pvc_read_enum` | Function that when given a camera handle and a enumerated parameter will return a list mapping all valid setting names to their values for the camera. `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised if an invalid setting for the camera is supplied. `RuntimeError` is raised upon failure. A Python list of dictionaries is returned upon success.

        **Parameters:**
        • Python int (camera handle).
        • Python int (parameter ID).
        | -| `pvc_reset_frame_counter` | Given a camera handle, resets `frame_count` returned by `pvc_poll_frame` to zero.

        **Parameters:**
        • Python int (camera handle).
        | -| `pvc_reset_pp` | Given a camera handle, resets all camera post-processing parameters back to their default state.

        **Parameters:**
        • Python int (camera handle).
        | -| `pvc_set_exp_modes` | Given a camera, exposure mode, and an expose out mode, change the camera's exposure mode to be the bitwise OR of the exposure mode and expose out mode parameters. `ValueError` is raised if invalid parameters are supplied including invalid modes for either exposure mode or expose out mode. `RuntimeError` is raised upon failure.

        **Parameters:**
        • Python int (camera handle).
        • Python int (exposure mode).
        • Python int (expose out mode).
        | -| `pvc_set_param` | Given a camera handle, a parameter ID, and a new value for the parameter, set the camera's parameter to the new value. `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised when attempting to set a parameter not supported by a camera. `RuntimeError` is raised upon failure.

        **Parameters:**
        • Python int (camera handle).
        • Python int (parameter ID).
        • Generic Python value (any type) (new value for parameter).
        | -| `pvc_setup_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up a live mode acquisition. Returns one frame size in bytes.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (exposure time).
        • Python int (exposure mode).
        • Python int (buffer frame count).
        • Python str (stream to disk path).
        | -| `pvc_setup_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up a sequence mode acquisition. Returns one frame size in bytes.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (exposure time).
        • Python int (exposure mode).
        • Python int (total frames).
        | -| `pvc_start_set_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, starts already sets up live mode acquisition.

        **Parameters:**
        • Python int (camera handle).
        | -| `pvc_start_set_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, starts already sets up sequence mode acquisition.

        **Parameters:**
        • Python int (camera handle).
        | -| `pvc_start_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up and starts a live mode acquisition. Internally combines `pvc_setup_live` and `pvc_start_set_live`. Returns one frame size in bytes.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (exposure time).
        • Python int (exposure mode).
        • Python int (buffer frame count).
        • Python str (stream to disk path).
        | -| `pvc_start_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up and starts a sequence mode acquisition. Internally combines `pvc_setup_seq` and `pvc_start_set_seq`. Returns one frame size in bytes.

        **Parameters:**
        • Python int (camera handle).
        • Python list (Region of Interest objects)
        • Python int (exposure time).
        • Python int (exposure mode).
        • Python int (total frames).
        | -| `pvc_sw_trigger` | Given a camera handle, performs a software trigger. Prior to using this function, the camera must be set to use either the `EXT_TRIG_SOFTWARE_FIRST` or `EXT_TRIG_SOFTWARE_EDGE` exposure mode.

        **Parameters:**
        • Python int (camera handle).
        • | -| `pvc_uninit_pvcam` | Uninitializes the PVCAM library. Raises `RuntimeError` on failure. | - -#### The Method Table -All functions that need to be exposed to Python programs need to be included in the method table. -The method table is partially responsible for allowing Python programs to call functions from an -extension module. It does this by creating a list of `PyMethodDef` structs with a sentinel struct -at the end of the list. The list of method definitions are then passed to the `PyModuleDef` struct, -which contains the necessary information to construct the module. - -The method table is a list of `PyMethodDef` structs, which have the following four fields: - -| Field Name | C Type | Description | -|------------|---------------|-------------------------------------------------------------------------| -| `ml_name` | `const char*` | Name of the method (when called from Python) | -| `ml_meth` | `PyCFunction` | Pointer to the C implementation of the function in the module. | -| `ml_flags` | `int` | Flag bits indicating how the call to the function should be constructed | -| `ml_doc` | `const char*` | Points to the contents of the docstring for the method. | - -#### The Module Definition -The `PyModuleDef` structure contains all the information required to create the top-level module object. - -| Field Name | C Type | Description | -|-------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `m_base` | `PyModuleDef_Base` | Always initialize this member to `PyModuleDef_HEAD_INIT` | -| `m_name` | `const char*` | Name for the new module (must match the name in the Module Init function). | -| `m_doc` | `const char*` | Docstring for the module. | -| `m_size` | `Py_ssize_t` | Specifies the additional amount of memory a module requires for its "state".
          Only needed if running in sub-interpreters; otherwise set to -1, signifying that the module does not support sub-interpreters because it has global state. | -| `m_methods` | `PyMethodDef*` | Pointer to the method table. Can be `NULL` if no functions are present. | - -After creating the module definition structure, it can then be passed into the module creation function. - -#### Module Creation -The module initialization function will create and return the module object directly. - -To initialize a module, write the `PyInit_{modulename}` function, which calls and returns the value -of `PyModule_Create`. See example below: - -#### Creating Extension Module -``` -PyMODINIT_FUNC -PyInit_pvc(void) -{ - return PyModule_Create(&pvcModule); -} -``` - -### `constants_generator.py` -The purpose of the `constants_generator.py` file is to easily construct a new `constants.py` data -file should the file become tainted or a new version of PVCAM is released. - -The script targets three main parts of the header file: the predefined macros, the enums, -and the structs. - -#### Requirements -The constants generator targets the installation location of the PVCAM SDK on your machine, meaning -that the script will fail to run if you do not have the SDK installed. - -#### Running the Script -In order to run the script, ensure that you are running it from `/PyVCAM/pyvcam/src/`, or else it -will fail to find the correct directory to write the generated `constants.py` file to. - -The script can be run using the following command when you are in the correct directory: -`python constants_generator.py` +| Function Name | Description | +|---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `pvc_abort` | Given a camera handle, aborts any ongoing acquisition and de-registers the frame handler callback function.

          **Parameters:**
          • Python int (camera handle).
          • | +| `pvc_check_frame_status` | Given a camera handle, returns the current frame status as a string. Possible return values:
            • `'READOUT_NOT_ACTIVE'`
            • `'EXPOSURE_IN_PROGRESS'`
            • `'READOUT_IN_PROGRESS'`
            • `'READOUT_COMPLETE'`/`'FRAME_AVAILABLE'`
            • `'READOUT_FAILED'`
            **Parameters:**
            • Python int (camera handle).
            | +| `pvc_check_param` | Given a camera handle and parameter ID, returns `True` if the parameter is available on the camera.

            **Parameters:**
            • Python int (camera handle).
            • Python int (parameter ID).
            | +| `pvc_close_camera` | Given a camera handle, closes the camera. Returns `True` upon success. `ValueError` is raised if invalid parameter is supplied. `RuntimeError` raised otherwise.

            **Parameters:**
            • Python int (camera handle).
            | +| `pvc_finish_seq` | Given a camera handle, finalizes sequence acquisition and cleans up resources. If a sequence is in progress, acquisition will be aborted.

            **Parameters:**
            • Python int (camera handle).
            | +| `pvc_get_cam_fw_version` | Given a camera handle, returns camera firmware version as a string.

            **Parameters:**
            • Python int (camera handle).
            | +| `pvc_get_cam_name` | Given a Python integer corresponding to a camera handle, returns the name of the camera with the associate handle.

            **Parameters:**
            • Python int (camera handle).
            | +| `pvc_get_cam_total` | Returns the total number of cameras currently attached to the system as a Python integer. | +| `pvc_get_frame` | Given a camera and a region, returns a Python numpy array of the pixel values of the data. Numpy array returned on success. `ValueError` raised if invalid parameters are supplied. `MemoryError` raised if unable to allocate memory for the camera frame. `RuntimeError` raised otherwise.

            **Parameters:**
            • Python int (camera handle).
            • Python list (Region of Interest objects)
            • Python int (Numpy data type enumeration value)
            • Python int (Frame timeout in milliseconds. Negative values will wait forever)
            • Python bool (Flag selecting oldest or newest frame)
            | +| `pvc_get_param` | Given a camera handle, a parameter ID, and the attribute ID of the parameter in question (AVAIL, CURRENT, etc.) returns the value of the parameter at the current attribute.

            **Note: This setting will only return a Python int or a Python string. Currently no other types are supported, but it is possible to extend the function as needed.**

            `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised if camera does not support the specified parameter. `RuntimeError` is raised otherwise.

            **Parameters:**
            • Python int (camera handle).
            • Python int (parameter ID).
            • Python int (attribute ID).
            | +| `pvc_get_pvcam_version` | Returns a Python Unicode String of the current PVCAM version. | +| `pvc_init_pvcam` | Initializes the PVCAM library. Raises `RuntimeError` on failure. | +| `pvc_open_camera` | Given a Python string corresponding to a camera name, opens the camera. Returns `True` upon success. `ValueError` is raised if invalid parameter is supplied. `RuntimeError` raised otherwise.

            **Parameters:**
            • Python string (camera name).
            | +| `pvc_read_enum` | Function that when given a camera handle and a enumerated parameter will return a list mapping all valid setting names to their values for the camera. `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised if an invalid setting for the camera is supplied. `RuntimeError` is raised upon failure. A Python list of dictionaries is returned upon success.

            **Parameters:**
            • Python int (camera handle).
            • Python int (parameter ID).
            | +| `pvc_reset_frame_counter` | Given a camera handle, resets `frame_count` returned by `pvc_poll_frame` to zero.

            **Parameters:**
            • Python int (camera handle).
            | +| `pvc_reset_pp` | Given a camera handle, resets all camera post-processing parameters back to their default state.

            **Parameters:**
            • Python int (camera handle).
            | +| `pvc_set_exp_modes` | Given a camera, exposure mode, and an expose out mode, change the camera's exposure mode to be the bitwise OR of the exposure mode and expose out mode parameters. `ValueError` is raised if invalid parameters are supplied including invalid modes for either exposure mode or expose out mode. `RuntimeError` is raised upon failure.

            **Parameters:**
            • Python int (camera handle).
            • Python int (exposure mode).
            • Python int (expose out mode).
            | +| `pvc_set_param` | Given a camera handle, a parameter ID, and a new value for the parameter, set the camera's parameter to the new value. `ValueError` is raised if invalid parameters are supplied. `AttributeError` is raised when attempting to set a parameter not supported by a camera. `RuntimeError` is raised upon failure.

            **Parameters:**
            • Python int (camera handle).
            • Python int (parameter ID).
            • Generic Python value (any type) (new value for parameter).
            | +| `pvc_setup_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up a live mode acquisition. Returns one frame size in bytes.

            **Parameters:**
            • Python int (camera handle).
            • Python list (Region of Interest objects)
            • Python int (exposure time).
            • Python int (exposure mode).
            • Python int (buffer frame count).
            • Python str (stream to disk path).
            | +| `pvc_setup_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up a sequence mode acquisition. Returns one frame size in bytes.

            **Parameters:**
            • Python int (camera handle).
            • Python list (Region of Interest objects)
            • Python int (exposure time).
            • Python int (exposure mode).
            • Python int (total frames).
            | +| `pvc_start_set_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, starts already sets up live mode acquisition.

            **Parameters:**
            • Python int (camera handle).
            | +| `pvc_start_set_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, starts already sets up sequence mode acquisition.

            **Parameters:**
            • Python int (camera handle).
            | +| `pvc_start_live` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up and starts a live mode acquisition. Internally combines `pvc_setup_live` and `pvc_start_set_live`. Returns one frame size in bytes.

            **Parameters:**
            • Python int (camera handle).
            • Python list (Region of Interest objects)
            • Python int (exposure time).
            • Python int (exposure mode).
            • Python int (buffer frame count).
            • Python str (stream to disk path).
            | +| `pvc_start_seq` | Given a camera handle, region of interest, binning factors, exposure time and exposure mode, sets up and starts a sequence mode acquisition. Internally combines `pvc_setup_seq` and `pvc_start_set_seq`. Returns one frame size in bytes.

            **Parameters:**
            • Python int (camera handle).
            • Python list (Region of Interest objects)
            • Python int (exposure time).
            • Python int (exposure mode).
            • Python int (total frames).
            | +| `pvc_sw_trigger` | Given a camera handle, performs a software trigger. Prior to using this function, the camera must be set to use either the `EXT_TRIG_SOFTWARE_FIRST` or `EXT_TRIG_SOFTWARE_EDGE` exposure mode.

            **Parameters:**
            • Python int (camera handle).
            • | +| `pvc_uninit_pvcam` | Uninitializes the PVCAM library. Raises `RuntimeError` on failure. | *** -## `tests` Folder -The `tests` directory contains unit tests to ensure the quality of the code of the module and to -also include some basic examples on how to perform basic operations on a camera. +## `examples` Folder +Include some basic examples on how to perform basic operations on a camera. ### `change_settings_test.py` (needs `camera_settings.py`) The `change_settings_test.py` is used to show one way of keeping camera settings in one file and @@ -484,6 +281,10 @@ dig through a large testing script and manually changing the settings within it. The `check_frame_status.py` is used to demonstrate how to query frame status for both live and sequence acquisition modes. +### `live_in_subprocess.py` +The `live_in_subprocess.py` is very similar to `live_mode.py` example and is used to demonstrate how +to perform live frame acquisition with PyVCAM isolated in a subprocess. + ### `live_mode.py` The `live_mode.py` is used to demonstrate how to perform live frame acquisition using the advanced frame acquisition features of PyVCAM. @@ -525,6 +326,11 @@ a PVCAM C++ callback. The `sw_trigger.py` is used to demonstrate how to perform a software trigger using two Python threads, one to configure acquisition and one to perform the trigger. +*** + +## `tests` Folder +The `tests` directory contains unit tests to ensure the quality of the code of the module. + ### `test_camera.py` The `test_camera.py` contains the unit tests for this module. It tests the getting and setting properties and edge cases of all available settings. From 9b2104f800d9b88302aa060fc3b1ccf117432960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Wed, 1 Oct 2025 16:15:25 +0200 Subject: [PATCH 6/7] Fixed Camera.get_vtm_sequence to use new pvc functions for proper VTM acq. --- src/pyvcam/camera.py | 60 +++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/src/pyvcam/camera.py b/src/pyvcam/camera.py index 261e23e..fc822b5 100644 --- a/src/pyvcam/camera.py +++ b/src/pyvcam/camera.py @@ -706,30 +706,56 @@ def get_vtm_sequence(self, time_list, exp_res, num_frames, timeout_ms=WAIT_FOREV A 3D np.array containing the pixel data from the captured sequence. """ - old_res = self.exp_res - self.exp_res = exp_res - if len(self.__rois) > 1: raise ValueError('get_vtm_sequence does not support multi-roi captures') shape = self.__rois[0].shape stack = np.empty((num_frames, shape[1], shape[0]), dtype=self.__dtype) - for i in range(num_frames): - exp_time = time_list[i % len(time_list)] - try: - self.vtm_exp_time = exp_time - stack[i] = self.get_frame(exp_time=self.vtm_exp_time, - timeout_ms=timeout_ms, - reset_frame_counter=reset_frame_counter) - reset_frame_counter = False - except Exception as ex: - raise ValueError('Could not collect vtm frame') from ex + old_res = self.exp_res + self.exp_res = exp_res - if isinstance(interval, int) and i + 1 < num_frames: - time.sleep(interval / 1000) + try: + uses_vtm = self.exp_mode == const.VARIABLE_TIMED_MODE + if uses_vtm: # Native VTM + + if reset_frame_counter: + pvc.reset_frame_counter(self.__handle) + + # Use non-zero exposure time for VTM, the actual will be set later + pvc.setup_seq(self.__handle, self.__rois, 1, self.__mode, 1) + self.__acquisition_mode = 'Sequence' + + for i in range(num_frames): + exp_time = time_list[i % len(time_list)] + + self.vtm_exp_time = exp_time + pvc.start_set_seq(self.__handle) + + frame, _, _ = self.poll_frame(timeout_ms=timeout_ms) + stack[i] = frame['pixel_data'] + + if isinstance(interval, int) and i + 1 < num_frames: + time.sleep(interval / 1000) + + self.finish() + + else: # Emulated VTM, very similar to get_sequence() + + for i in range(num_frames): + exp_time = time_list[i % len(time_list)] + + stack[i] = self.get_frame(exp_time=exp_time, + timeout_ms=timeout_ms, + reset_frame_counter=reset_frame_counter) + reset_frame_counter = False + + if isinstance(interval, int) and i + 1 < num_frames: + time.sleep(interval / 1000) + + finally: + self.exp_res = old_res - self.exp_res = old_res return stack def start_live(self, exp_time=None, buffer_frame_count=16, @@ -1197,7 +1223,6 @@ def exp_res_index(self): @property def exp_time(self): - # TODO: Testing if not self.__is_open: raise RuntimeError('Camera is not open') return self.__exp_time @@ -1247,6 +1272,7 @@ def vtm_exp_time(self): def vtm_exp_time(self, value): min_exp_time = self.get_param(const.PARAM_EXPOSURE_TIME, const.ATTR_MIN) max_exp_time = self.get_param(const.PARAM_EXPOSURE_TIME, const.ATTR_MAX) + max_exp_time = min(max_exp_time, 65535) # uns16 limit if not min_exp_time <= value <= max_exp_time: raise ValueError(f'Invalid value: {value} - {self} only supports ' f'exposure times between {min_exp_time} and {max_exp_time}') From a0aeb07463f1fdf7b99c2258cae24b0e25ec41cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Wed, 1 Oct 2025 16:16:38 +0200 Subject: [PATCH 7/7] Fixed seq_mode.py to properly use VTM acq. if the camera supports it. --- examples/seq_mode.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/seq_mode.py b/examples/seq_mode.py index 9baa6c5..558653a 100644 --- a/examples/seq_mode.py +++ b/examples/seq_mode.py @@ -40,7 +40,12 @@ def main(): cnt += 1 print_frame_details(frame, cnt) - print('\nUsing get_vtm_sequence:') + has_vtm = const.VARIABLE_TIMED_MODE in cam.exp_modes.values() + print(f'\nUsing get_vtm_sequence with ' + f'{"native" if has_vtm else "emulated"} VTM:') + if has_vtm: + old_exp_mode = cam.exp_mode + cam.exp_mode = const.VARIABLE_TIMED_MODE time_list = [i * 10 for i in range(1, 8)] frames = cam.get_vtm_sequence(time_list, const.EXP_RES_ONE_MILLISEC, NUM_FRAMES) i = 0 @@ -48,6 +53,8 @@ def main(): cnt += 1 print_frame_details(frame, cnt, f'\tExp. time: {time_list[i]}') i = (i + 1) % len(time_list) + if has_vtm: + cam.exp_mode = old_exp_mode try: print('\nUsing poll_frame without starting acquisition:')