# coding: utf-8
from time import time, strftime, gmtime
from typing import Optional, Tuple, Dict, Any
import numpy as np
import logging
from warnings import warn
from .meta_camera import Camera
from .._global import OptionalModule
try:
from ximea import xiapi
except (ModuleNotFoundError, ImportError):
xiapi = OptionalModule("ximea", "To use XiAPI cameras, please install the "
"official ximea Python module")
# Camera models that were added in Crappy
SUPPORTED = ('MQ042MG-CM', 'MC124MG-SY-UB')
# Available data formats for the supported cameras
DATA_FORMATS = {'MQ042MG-CM': {'XI_MONO8': 'Mono (8 bits)',
'XI_MONO16': 'Mono (16 bits)',
'XI_RAW8': 'Raw (8 bits)',
'XI_RAW16': 'Raw (16 bits)'},
'MC124MG-SY-UB': {'XI_MONO8': 'Mono (8 bits)',
'XI_MONO16': 'Mono (16 bits)',
'XI_RAW8': 'Raw (8 bits)',
'XI_RAW16': 'Raw (16 bits)'}
}
DATA_FORMATS_INV = {num: dict(zip(dic.values(), dic.keys()))
for num, dic in DATA_FORMATS.items()}
# Available framerate modes for the supported cameras
FRAMERATE_MODES = {'MQ042MG-CM':
{'XI_ACQ_TIMING_MODE_FREE_RUN': 'Free run',
'XI_ACQ_TIMING_MODE_FRAME_RATE': 'Framerate target'},
'MC124MG-SY-UB':
{'XI_ACQ_TIMING_MODE_FREE_RUN': 'Free run',
'XI_ACQ_TIMING_MODE_FRAME_RATE_LIMIT': 'Framerate limit'}
}
FRAMERATE_MODES_INV = {num: dict(zip(dic.values(), dic.keys()))
for num, dic in FRAMERATE_MODES.items()}
# Available downsampling modes for the supported cameras
DOWNSAMPLING_MODES = {'MC124MG-SY-UB': {'XI_DWN_1x1': '1x1',
'XI_DWN_2x2': '2x2'}}
DOWNSAMPLING_MODES_INV = {num: dict(zip(dic.values(), dic.keys()))
for num, dic in DOWNSAMPLING_MODES.items()}
[docs]
class XiAPI(Camera):
"""This class can read images from any of the Ximea cameras.
It heavily relies on the :mod:`ximea` module, distributed by Ximea, which is
itself a wrapper around the XiAPI low-level library.
Note:
Both the Python module and the camera drivers have to be installed from
Ximea's website in order for this class to run.
.. versionadded:: 1.4.0
.. versionchanged:: 2.0.0 renamed from *Xiapi* to *XiAPI*
"""
[docs]
def __init__(self) -> None:
"""Instantiates a Ximea Camera and a Ximea Image object."""
super().__init__()
self._cam = None
self._started: bool = False
self._model: Optional[str] = None
self._timeout: Optional[int] = None
self._cam = xiapi.Camera()
self._img = xiapi.Image()
# Stores the last requested or read trigger mode value
self._trig = 'Free run'
[docs]
def open(self,
serial_number: Optional[str] = None,
timeout: Optional[int] = None,
trigger: Optional[str] = None,
data_format: Optional[str] = None,
exposure_time_us: Optional[int] = None,
gain: Optional[float] = None,
auto_exposure_auto_gain: Optional[bool] = None,
gamma_y: Optional[float] = None,
gamma_c: Optional[float] = None,
sharpness: Optional[float] = None,
image_width: Optional[int] = None,
image_height: Optional[int] = None,
x_offset: Optional[int] = None,
y_offset: Optional[int] = None,
framerate_mode: Optional[str] = None,
framerate: Optional[float] = None,
downsampling_mode: Optional[str] = None,
width: Optional[int] = None,
height: Optional[int] = None,
xoffset: Optional[int] = None,
yoffset: Optional[int] = None,
exposure: Optional[float] = None,
AEAG: Optional[bool] = None,
external_trig: Optional[bool] = None,) -> None:
"""Opens the connection to the camera, instantiates the available settings
and starts the acquisition.
Also sets custom values for the settings if provided by the user, otherwise
sets them to their default.
Args:
serial_number: A :obj:`str` containing the serial number of the camera to
open, in case several cameras are connected. If not provided and
several cameras are available, one of them will be opened randomly.
.. versionchanged:: 2.0.0 renamed from *sn* to *serial_number*
timeout: The number of milliseconds the camera is allowed to wait for an
image before raising a :exc:`TimeoutError`, as an :obj:`int`. Mostly
useful when using an external trigger, or a very long exposure time.
The default is 5000ms.
.. versionadded:: 2.0.2
trigger: Drives the trigger status of the camera. Can be either
`'Free run'`, `'Hdw after config'`, or `'Hardware'`. The default is
`'Free run'`.
.. versionadded:: 2.0.0
data_format: The data format to use for acquisition as a :obj:`str` (e.g.
`'Mono (8 bits)'`). The available formats depend on the model of the
camera. This setting is only implemented for a subset of all the Ximea
cameras, get in touch with the maintainers to implement in on other
models.
.. versionadded:: 2.0.2
exposure_time_us: The exposure time to use for acquiring images, in µs.
Only has an effect if ``auto_exposure_auto_gain`` is set to
:obj:`False`, and if ``framerate_mode`` is not in `'Free run'`.
Depending on the camera might set the *target* or the *limit*
framerate. The range of values depends on the model of the driven
camera. This setting is only implemented for a subset of all the Ximea
cameras, get in touch with the maintainers to implement in on other
models.
.. versionadded:: 2.0.2
gain: The gain in dB to apply to the acquired images, as a :obj:`float`.
Only has an effect if ``auto_exposure_auto_gain`` is set to
:obj:`False`. The valid range of values depends on the model of the
driven camera.
auto_exposure_auto_gain: When set to :obj:`True`, overwrites the
``exposure_time_us`` and ``gain`` values and drives the exposure and
the gain automatically.
.. versionadded:: 2.0.2
gamma_y: The luminosity gamma value, for color images only, as a
:obj:`float`. The valid range of values depends on the model of the
driven camera.
.. versionadded:: 2.0.2
gamma_c: The chromaticity gamma value, for color images only, as a
:obj:`float`. The valid range of values depends on the model of the
driven camera.
.. versionadded:: 2.0.2
sharpness: The sharpness strength value, for color images only, as a
:obj:`float`. The valid range of values depends on the model of the
driven camera.
.. versionadded:: 2.0.2
image_width: The width of the ROI to acquire in pixels, as an :obj:`int`.
The valid range of values depends on the model of the driven camera,
and on the ``downsampling_mode`` if supported.
.. versionadded:: 2.0.2
image_height: The height of the ROI to acquire in pixels, as an
:obj:`int`. The valid range of values depends on the model of the
driven camera, and on the ``downsampling_mode`` if supported.
.. versionadded:: 2.0.2
x_offset: The X offset of the ROI to acquire in pixels, as an :obj:`int`.
The valid range of values depends on the model of the driven camera,
on the selected ``width``, and on the ``downsampling_mode`` if
supported.
.. versionadded:: 2.0.2
y_offset: The Y offset of the ROI to acquire in pixels, as an :obj:`int`.
The valid range of values depends on the model of the driven camera,
on the selected ``height``, and on the ``downsampling_mode`` if
supported.
.. versionadded:: 2.0.2
framerate_mode: The mode for driving the acquisition framerate. Can be
one of `'Free run'`, `'Framerate target'` or `'Framerate limit'`,
but not all camera models support the three options. This setting is
only implemented for a subset of all the Ximea cameras, get in touch
with the maintainers to implement in on other models.
.. versionadded:: 2.0.2
framerate: Either the target or the limit framerate for image
acquisition, depending on the ``framerate_mode`` value, as a
:obj:`float`. The valid range of values depends on the model of the
driven camera, and on the ``exposure_time_us`` value. Only has an
effect if ``framerate_mode`` is not set to `'Free run'`. This setting
is only implemented for a subset of all the Ximea cameras, get in touch
with the maintainers to implement in on other models.
.. versionadded:: 2.0.2
downsampling_mode: The downsampling mode to apply to the acquired images,
as a :obj:`str` (e.g. `'2x2'`). This setting is only implemented for a
subset of all the Ximea cameras, get in touch with the maintainers to
implement in on other models.
.. versionadded:: 2.0.2
width: .. deprecated:: 2.0.2 Use ``image_width`` instead.
height: .. deprecated:: 2.0.2 Use ``image_height`` instead.
xoffset: .. deprecated:: 2.0.2 Use ``x_offset`` instead.
yoffset: .. deprecated:: 2.0.2 Use ``y_offset`` instead.
exposure: .. deprecated:: 2.0.2 Use ``exposure_time_us`` instead.
AEAG: .. deprecated:: 2.0.2 Use ``auto_exposure_auto_gain`` instead.
external_trig: .. deprecated:: 2.0.0 Use ``trigger`` instead.
"""
# Managing the deprecated arguments
if width is not None:
warn("The width argument is deprecated for the XiAPI camera, use "
"image_width instead !", FutureWarning)
image_width = width
if height is not None:
warn("The height argument is deprecated for the XiAPI camera, use "
"image_height instead !", FutureWarning)
image_height = height
if xoffset is not None:
warn("The xoffset argument is deprecated for the XiAPI camera, use "
"x_offset instead !", FutureWarning)
x_offset = xoffset
if yoffset is not None:
warn("The yoffset argument is deprecated for the XiAPI camera, use "
"y_offset instead !", FutureWarning)
y_offset = yoffset
if exposure is not None:
warn("The exposure argument is deprecated for the XiAPI camera, use "
"exposure_time_us instead !", FutureWarning)
exposure_time_us = exposure
if AEAG is not None:
warn("The AEAG argument is deprecated for the XiAPI camera, use "
"auto_exposure_auto_gain instead !", FutureWarning)
auto_exposure_auto_gain = AEAG
if external_trig is not None:
warn("The external_trig argument is deprecated for the XiAPI camera, use"
" trigger instead !", FutureWarning)
trigger = 'Hdw after config'
self._timeout = timeout
# First, checking if there are connected cameras
num_dev = self._cam.get_number_devices()
if not num_dev:
raise IOError("No connected Ximea camera was detected !")
else:
self.log(logging.INFO, f"Detected {num_dev} connected Ximea camera(s)")
# Opening the camera by serial number if any was provided
if serial_number is not None:
self.log(logging.INFO, f"Opening the connection to the camera with "
f"serial number {serial_number}")
self._cam.open_device_by_SN(serial_number)
else:
self.log(logging.INFO, "Opening the connection to a default camera")
self._cam.open_device()
# Checking the model of the opened camera and logging to the user
self._model = self._cam.get_device_name().decode()
self.log(logging.INFO, f"Opened the Ximea camera model "
f"{self._model}, with serial number "
f"{self._cam.get_device_sn().decode()}")
if self._model not in SUPPORTED:
self.log(logging.WARNING, f"The model {self._model} was never "
f"specifically implemented in Crappy, some if "
f"its features might not be available ! Get "
f"in touch with the maintainers to have it "
f"implemented.")
# Data format parameter
if self._model in DATA_FORMATS:
self.add_choice_setting('data_format',
DATA_FORMATS[self._model].values(),
self._get_data_format,
self._set_data_format,
self._get_data_format())
# Gain and exposure parameters
self.add_scale_setting('exposure_time_us',
self._cam.get_exposure_minimum(),
min(self._cam.get_exposure_maximum(), 100000),
self._get_exp,
self._set_exp,
10000)
self.add_scale_setting('gain',
self._cam.get_gain_minimum(),
self._cam.get_gain_maximum(),
self._get_gain,
self._set_gain,
0.0)
self.add_bool_setting('auto_exposure_auto_gain',
self._get_aeag,
self._set_aeag,
False)
# Color-related parameters
self.add_scale_setting('gamma_y',
self._cam.get_gammaY_minimum(),
self._cam.get_gammaY_maximum(),
self._get_gamma_y,
self._set_gamma_y,
self._cam.get_gammaY(),
self._cam.get_gammaY_increment())
self.add_scale_setting('gamma_c',
self._cam.get_gammaC_minimum(),
self._cam.get_gammaC_maximum(),
self._get_gamma_c,
self._set_gamma_c,
self._cam.get_gammaC(),
self._cam.get_gammaC_increment())
self.add_scale_setting('sharpness',
self._cam.get_sharpness_minimum(),
self._cam.get_sharpness_maximum(),
self._get_sharpness,
self._set_sharpness,
self._cam.get_sharpness(),
self._cam.get_sharpness_increment())
# ROI parameters
self.add_scale_setting('image_width',
self._cam.get_width_minimum(),
self._cam.get_width_maximum(),
self._get_w,
self._set_w,
self._get_w(),
self._cam.get_width_increment())
self.add_scale_setting('image_height',
self._cam.get_height_minimum(),
self._cam.get_height_maximum(),
self._get_h,
self._set_h,
self._get_h(),
self._cam.get_height_increment())
self.add_scale_setting('x_offset',
self._cam.get_offsetX_minimum(),
self._cam.get_offsetX_maximum(),
self._get_ox,
self._set_ox,
self._get_ox(),
self._cam.get_offsetX_increment())
self.add_scale_setting('y_offset',
self._cam.get_offsetY_minimum(),
self._cam.get_offsetY_maximum(),
self._get_oy,
self._set_oy,
self._get_oy(),
self._cam.get_offsetY_increment())
# External trigger parameter
self.add_trigger_setting(self._get_extt, self._set_ext_trig)
# Framerate parameters
if self._model in FRAMERATE_MODES:
self.add_choice_setting('framerate_mode',
FRAMERATE_MODES[self._model].values(),
self._get_framerate_mode,
self._set_framerate_mode,
self._get_framerate_mode())
self.add_scale_setting('framerate',
self._cam.get_framerate_minimum(),
min(self._cam.get_framerate_maximum(), 500),
self._get_framerate,
self._set_framerate,
self._cam.get_framerate(),
self._cam.get_framerate_increment())
# Downsampling parameter
if self._model in DOWNSAMPLING_MODES:
self.add_choice_setting('downsampling_mode',
DOWNSAMPLING_MODES[self._model].values(),
self._get_downsampling_mode,
self._set_downsampling_mode,
self._get_downsampling_mode())
# Collecting the kwargs to set and setting them
to_set = {name: arg for name, arg in zip(
('exposure_time_us', 'gain', 'auto_exposure_auto_gain', 'gamma_y',
'gamma_c', 'sharpness', 'image_width', 'image_height', 'x_offset',
'y_offset', 'framerate_mode', 'framerate', 'downsampling_mode',
'trigger'),
(exposure_time_us, gain, auto_exposure_auto_gain, gamma_y, gamma_c,
sharpness, image_width, image_height, x_offset, y_offset,
framerate_mode, framerate, downsampling_mode, trigger))
if arg is not None}
self.set_all(**to_set)
# Starting the acquisition
self.log(logging.INFO, "Starting the image acquisition")
self._cam.start_acquisition()
self._started = True
[docs]
def get_image(self) -> Tuple[Dict[str, Any], np.ndarray]:
"""Reads a frame from the camera, and returns it along with its metadata.
The acquired metadata contains the following fields :
* `'t(s)'`: The current timestamp as returned by :obj:`time.time`.
* `'DateTimeOriginal'`: The current date up to the second as a valid exif
tag, based on the value of `'t(s)'`.
* `'SubsecTimeOriginal'`: The sub-second part of the current date as a
valid exif tag, based on the value of `'t(s)'`.
* `'XimeaSec'`: The number of seconds the camera has been up.
* `'XimeaUSec'`: The decimal part of the above field, value in µs.
* `'ImageWidth'`: The width of the acquired image, in pixels.
* `'ImageHeight'`: The height of the acquired image, in pixels.
* `'ExposureTime'`: The exposure time of the acquired image, in µs.
* `'AbsoluteOffsetX'`: The offset of the acquired ROI along the X axis, in
pixels.
* `'AbsoluteOffsetY'`: The offset of the acquired ROI along the Y axis, in
pixels.
* `'DownsamplingX'`: The downsampling factor along the X axis.
* `'DownsamplingY'`: The downsampling factor along the Y axis.
* `'ImageUniqueID'`: The index of the acquired image, as returned by the
camera.
"""
if self._timeout is not None:
self._cam.get_image(self._img, timeout=self._timeout)
else:
self._cam.get_image(self._img)
# Returning metadata from the camera long with the captured image
t = time()
metadata = {'t(s)': t,
'DateTimeOriginal': strftime("%Y:%m:%d %H:%M:%S", gmtime(t)),
'SubsecTimeOriginal': f'{t % 1:.6f}',
'XimeaSec': self._img.tsSec,
'XimeaUSec': self._img.tsUSec,
'ImageWidth': self._img.width,
'ImageHeight': self._img.height,
'ExposureTime': self._img.exposure_time_us,
'AbsoluteOffsetX': self._img.AbsoluteOffsetX,
'AbsoluteOffsetY': self._img.AbsoluteOffsetY,
'DownsamplingX': self._img.DownsamplingX,
'DownsamplingY': self._img.DownsamplingY,
'ImageUniqueID': self._img.acq_nframe}
return metadata, self._img.get_image_data_numpy()
[docs]
def close(self) -> None:
"""Closes the connection to the camera and releases the resources."""
if self._cam is not None:
self.log(logging.INFO, "Closing the connection to the camera")
self._cam.close_device()
def _get_data_format(self) -> str:
"""Returns the current data format of the acquired images."""
return DATA_FORMATS[self._model][self._cam.get_imgdataformat()]
def _get_exp(self) -> float:
"""Returns the exposure time, in microseconds."""
return self._cam.get_exposure()
def _get_aeag(self) -> bool:
"""Return the status of the Auto Exposure / Auto Gain setting."""
return self._cam.is_aeag()
def _get_gain(self) -> float:
"""Returns the gain, in dB."""
return self._cam.get_gain()
def _get_gamma_y(self) -> float:
"""Returns the current Gamma Y value of the camera."""
return self._cam.get_gammaY()
def _get_gamma_c(self) -> float:
"""Returns the current Gamma C value of the camera."""
return self._cam.get_gammaC()
def _get_sharpness(self) -> float:
"""Returns the current sharpness value of the camera."""
return self._cam.get_sharpness()
def _get_w(self) -> int:
"""Returns the width in pixels for selecting a region of interest."""
return self._cam.get_width()
def _get_h(self) -> int:
"""Returns the height in pixels for selecting a region of interest."""
return self._cam.get_height()
def _get_ox(self) -> int:
"""Returns the `x` offset in pixels for selecting a region of interest."""
return self._cam.get_offsetX()
def _get_oy(self) -> int:
"""Returns the `y` offset in pixels for selecting a region of interest."""
return self._cam.get_offsetY()
def _get_extt(self) -> str:
"""Returns the current trigger mode value, and updates the last read
trigger mode value if needed.
The possible values for the trigger mode are `'Hardware'`, `'Free run'`,
and `'Hdw after config'`.
"""
r = self._cam.get_trigger_source()
if r == 'XI_TRG_OFF' and self._trig == 'Hardware':
self._trig = 'Free run'
elif r != 'XI_TRG_OFF' and self._trig != 'Hardware':
self._trig = 'Hardware'
return self._trig
def _get_framerate(self) -> float:
"""Returns the current framerate value of the camera."""
return self._cam.get_framerate()
def _get_framerate_mode(self) -> str:
"""Returns the current frame rate mode for the camera."""
return FRAMERATE_MODES[self._model][self._cam.get_acq_timing_mode()]
def _get_downsampling_mode(self) -> str:
"""Returns the current downsampling mode."""
return DOWNSAMPLING_MODES[self._model][self._cam.get_downsampling()]
def _set_data_format(self, fmt: str) -> None:
"""sets the requested data format."""
if self._started:
self.log(logging.DEBUG, "Stopping the image acquisition")
self._cam.stop_acquisition()
self._cam.set_imgdataformat(DATA_FORMATS_INV[self._model][fmt])
if self._started:
self.log(logging.DEBUG, "Starting the image acquisition")
self._cam.start_acquisition()
def _set_exp(self, exposure: float) -> None:
"""Sets the exposure time, in microseconds."""
if self._get_aeag():
self.log(logging.WARNING, "Setting the exposure won't work as long as "
"the AEAG is enabled !")
self._cam.set_exposure(exposure)
def _set_aeag(self, val: bool) -> None:
"""Enables or disables the Auto Exposure / Auto Gain setting."""
if val:
self._cam.enable_aeag()
else:
self._cam.disable_aeag()
def _set_gain(self, gain: float) -> None:
"""Sets the gain, in dB."""
if self._get_aeag():
self.log(logging.WARNING, "Setting the gain won't work as long as the "
"AEAG is enabled !")
self._cam.set_gain(gain)
def _set_gamma_y(self, gamma: float) -> None:
"""Sets the Gamma Y value on the camera."""
self._cam.set_gammaY(gamma)
def _set_gamma_c(self, gamma: float) -> None:
"""Sets the Gamma C value on the camera."""
self._cam.set_gammaC(gamma)
def _set_sharpness(self, sharpness: float) -> None:
"""Sets the sharpness value on the camera."""
self._cam.set_sharpness(sharpness)
def _set_w(self, width: int) -> None:
"""Sets the width in pixels for selecting a region of interest."""
# Lowering the X offset if it conflicts with the new image width
if self.x_offset + width > self.settings['image_width'].highest:
self.x_offset = self.settings['image_width'].highest - width
if self._started:
self.log(logging.DEBUG, "Stopping the image acquisition")
self._cam.stop_acquisition()
# Setting the requested width and reloading the X offset
self._cam.set_width(width)
if self._started:
self.log(logging.DEBUG, "Starting the image acquisition")
self._cam.start_acquisition()
self.settings['x_offset'].reload(self._cam.get_offsetX_minimum(),
self._cam.get_offsetX_maximum(),
self._get_ox(),
self._get_ox(),
self._cam.get_offsetX_increment())
def _set_h(self, height: int) -> None:
"""Sets the height in pixels for selecting a region of interest."""
# Lowering the Y offset if it conflicts with the new image height
if self.y_offset + height > self.settings['image_height'].highest:
self.y_offset = self.settings['image_height'].highest - height
if self._started:
self.log(logging.DEBUG, "Stopping the image acquisition")
self._cam.stop_acquisition()
# Setting the requested height and reloading the Y offset
self._cam.set_height(height)
if self._started:
self.log(logging.DEBUG, "Starting the image acquisition")
self._cam.start_acquisition()
self.settings['y_offset'].reload(self._cam.get_offsetY_minimum(),
self._cam.get_offsetY_maximum(),
self._get_oy(),
self._get_oy(),
self._cam.get_offsetY_increment())
def _set_ox(self, x_offset: int) -> None:
"""Sets the `x` offset in pixels for selecting a region of interest."""
if self._started:
self.log(logging.DEBUG, "Stopping the image acquisition")
self._cam.stop_acquisition()
self._cam.set_offsetX(x_offset)
if self._started:
self.log(logging.DEBUG, "Starting the image acquisition")
self._cam.start_acquisition()
def _set_oy(self, y_offset: int) -> None:
"""Sets the `y` offset in pixels for selecting a region of interest."""
if self._started:
self.log(logging.DEBUG, "Stopping the image acquisition")
self._cam.stop_acquisition()
self._cam.set_offsetY(y_offset)
if self._started:
self.log(logging.DEBUG, "Starting the image acquisition")
self._cam.start_acquisition()
def _set_ext_trig(self, trig: str) -> None:
"""Sets the requested trigger mode value, and updates the last requested
trigger mode value.
The possible values for the trigger mode are `'Hardware'`, `'Free run'`,
and `'Hdw after config'`.
"""
if self._started:
self.log(logging.DEBUG, "Stopping the image acquisition")
self._cam.stop_acquisition()
if trig == 'Hardware':
self._cam.set_gpi_mode('XI_GPI_TRIGGER')
self._cam.set_trigger_source('XI_TRG_EDGE_RISING')
else:
self._cam.set_gpi_mode('XI_GPI_OFF')
self._cam.set_trigger_source('XI_TRG_OFF')
self._trig = trig
if self._started:
self.log(logging.DEBUG, "Starting the image acquisition")
self._cam.start_acquisition()
def _set_framerate_mode(self, mode: str) -> None:
"""Sets the framerate mode for the camera to use."""
self._cam.set_acq_timing_mode(FRAMERATE_MODES_INV[self._model][mode])
self.settings['framerate'].reload(self._cam.get_framerate_minimum(),
min(self._cam.get_framerate_maximum(),
500),
self._cam.get_framerate(),
self._cam.get_framerate(),
self._cam.get_framerate_increment())
def _set_framerate(self, framerate) -> None:
"""Sets the target framerate value of the camera."""
if self._get_framerate_mode() == 'Free run':
self.log(logging.WARNING, "Setting the framerate won't work as long as "
"the camera is in free run mode !")
self._cam.set_framerate(framerate)
def _set_downsampling_mode(self, mode: str) -> None:
"""Sets the downsampling mode on the camera."""
if self._started:
self.log(logging.DEBUG, "Stopping the image acquisition")
self._cam.stop_acquisition()
self._cam.set_downsampling(DOWNSAMPLING_MODES_INV[self._model][mode])
if self._started:
self.log(logging.DEBUG, "Starting the image acquisition")
self._cam.start_acquisition()
self.settings['image_width'].reload(self._cam.get_width_minimum(),
self._cam.get_width_maximum(),
self._get_w(),
self._get_w(),
self._cam.get_width_increment())
self.settings['image_height'].reload(self._cam.get_height_minimum(),
self._cam.get_height_maximum(),
self._get_h(),
self._get_h(),
self._cam.get_height_increment())
self.settings['x_offset'].reload(self._cam.get_offsetX_minimum(),
self._cam.get_offsetX_maximum(),
self._get_ox(),
self._get_ox(),
self._cam.get_offsetX_increment())
self.settings['y_offset'].reload(self._cam.get_offsetY_minimum(),
self._cam.get_offsetY_maximum(),
self._get_oy(),
self._get_oy(),
self._cam.get_offsetY_increment())