AlexShkarin / pyLabLib

Python package for device control and experiment automation
http://pylablib.readthedocs.io
GNU General Public License v3.0
125 stars 28 forks source link

PixelFormat name compatibility issue between pylablib/IMAQdx and Basler piA1600-35gm camera #63

Open MangledPotat0 opened 8 months ago

MangledPotat0 commented 8 months ago

Code:

from pylablib.devices import IMAQdx as iqx
from pylablib.devices.IMAQdx.NIIMAQdx_lib import IMAQdxLibError
import cv2 as cv

def camera_auto():
    cameras = iqx.list_cameras()
    names = [camera.name for camera in cameras]
    print(names)
    camera = iqx.IMAQdxCamera(cameras[0].name)
    camera.set_attribute_value("AcquisitionAttributes/PacketSize", 1500)

    attr = camera.get_attribute("PixelFormat")

    camera.set_attribute_value("PixelFormat", "Mono8")
    frame = camera.snap()
    cv.imwrite("sadf.png", frame)
    camera.close()

if __name__ == "__main__":
    camera_auto()

Expected behavior:

Takes image using the camera, at 8-bit pixel format, and prints the shape of the image.

Actual behavior:

Camera fails to take the image upon calling cam.snap(). Error message:

['cam1', 'cam2', 'cam3', 'cam4']
Traceback (most recent call last):
  File "{CODEPATH}", line 20, in <module>
  File "{CODEPATH}", line 15, in camera_auto
    frame = camera.snap()
            ^^^^^^^^^^^^^
  File "{LIBRARYPATH}\pylablib\devices\interface\camera.py", line 682, in snap
    res=self.grab(frame_timeout=timeout,return_info=return_info)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "{LIBRARYPATH}\pylablib\devices\interface\camera.py", line 673, in grab
    new_frames,rng=self.read_multiple_images(missing_frame=missing_frame,return_rng=True)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^
  File "{LIBRARYPATH}\pylablib\core\devio\interface.py", line 666, in wrapped
    res=func(**all_args)
        ^^^^^^^^^^^^^^^^
  File "{LIBRARYPATH}\pylablib\devices\interface\camera.py", line 568, in read_multiple_images
    frames_data=self._read_frames(rng,return_info=return_info)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "{LIBRARYPATH}\pylablib\devices\IMAQdx\IMAQdx.py", line 470, in _read_frames
    frames=[self._parse_data(f,shape,pixel_format) for f in frames]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "{LIBRARYPATH}\pylablib\devices\IMAQdx\IMAQdx.py", line 470, in <listcomp>
    frames=[self._parse_data(f,shape,pixel_format) for f in frames]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "{LIBRARYPATH}\pylablib\devices\IMAQdx\IMAQdx.py", line 434, in _parse_data
    raise IMAQdxError("pixel format {} is not supported, only [{}] are supported; raw data readout can be enabled via enable_raw_readout method".format(pixel_format,sf_string))
pylablib.devices.IMAQdx.NIIMAQdx_lib.IMAQdxError: pixel format Mono 8 is not supported, only [Mono8, Mono10, Mono12, Mono16, Mono32] are supported; raw data readout can be enabled via enable_raw_readout method

Further information

The choices for the enum "PixelFormat" for the camera was inspected:

attr = cam.get_attribute("PixelValue")
print(attr.values)

and it returns the following list:

['Mono 8', 'Mono 12 Packed', 'Mono 16', 'YUV 422 Packed', 'YUV 422 (YUYV) Packed']

(Temporary) Solution

I located where the currently supported pixel values are enumerated:

https://github.com/AlexShkarin/pyLabLib/blob/c3521c8ad2fa6064b3f8a117576ed3053b7fa69f/pylablib/devices/IMAQdx/IMAQdx.py#L431-L436

and added "Mono 8" to supported_formats on line 431, and modified line 435 to

if pixel_format=="Mono8" or pixel_format=="Mono 8":

and that fixes the problem. Note I could not test "Mono 16" because even though attr.values include "Mono 16" the camera doesn't actually support 16-bit image according to the camera spec sheet.

The temporary fix I attempted feels pretty hacky and since there are multiple possible ways to write the format name (uppercase, lowercase, capitalized, abbreviated, etc.), enumerating them all in if would quickly get overwhelming. This may be a single exception, but if it turns out to be a recurring issue, it may be appropriate to make PixelFormat objects that ensures any string representation of a given pixel format is supported, similar to how the path objects in python ensure compatibility between different OS.