AlexShkarin / pyLabLib

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

IMAQdx grabbing only partial image #41

Closed bhathawayML closed 1 year ago

bhathawayML commented 1 year ago

I am using pylablib.devices.IMAQdx and am experiencing an issue with the raw image frames. Both snap() and grab() seem to only capture a portion of the image. I've attached examples taken using NI MAX (software_image.png) and the IMAQdx library (imaqdx_image.png) for comparison. I have tried four different cameras including the webcam, but they all have the issue. I have also examined the raw image frame and have confirmed that every 4th entry is zero (pixel format of BGRA). This confuses me though because the size of the image array should be WxHx4 instead of WxHx3. Below I have the simple script I am using to examine the raw frame...

from pylablib.devices.IMAQdx import IMAQdx

# Open Camera
device = IMAQdx.IMAQdxCamera("cam5")

# Send settings
device.enable_raw_readout("frame")  # camera format: RGBA 8 Packed
device.set_attribute_value("AcquisitionAttributes/VideoMode", "1920x1520 MJPG 30.00fps")
device.set_attribute_value("CameraAttributes/Exposure/Value", 150000)

# Get image
pic = device.snap()  # value: array([66, 101, 102, 0, 66, 101, 102, 0, ..., 75, 108, 111, 0], dtype=uint8)
pic_size = pic.size  # value: 8755200 (which is 1920*1520*3)

# Close camera
device.close()

Please let me know if you are aware of any solution to this, I have been struggling for two weeks now. Thank you in advance!

Specs: Windows 10 64-bit Python 3.10 (also tried with 3.6) pylablib v1.4.1 (also tried all other available versions) LabVIEW 2021 with Vision Assistant, MAX, IMAQ, IMAQdx, IMAQ IO

From NI MAX: software_image From pylablib.IMAQdx: imaqdx_image

AlexShkarin commented 1 year ago

Yeah, it looks like the frame size is calculated incorrectly. This is a bit strange, though, since the code uses the IMAQdx-provided PayloadSize attribute which, one would hope, should be correct.

To start, it would be interesting to check all other camera attributes. Could you get their values by running atts=device.cav[""] and send them here? In addition it would be good to compare these with the values you get in the Acquisition Attributes tab in NI MAX, and check the possible values of Video Mode and Pixel Format parameters there.

bhathawayML commented 1 year ago

Hello!

This is my output (and I confirmed these are the same values I see in NI MAX):

atts = Dictionary( 'AcquisitionAttributes/Bayer/Algorithm': Bilinear 'AcquisitionAttributes/Bayer/GainB': 1.0 'AcquisitionAttributes/Bayer/GainG': 1.0 'AcquisitionAttributes/Bayer/GainR': 1.0 'AcquisitionAttributes/Bayer/Pattern': Use hardware value 'AcquisitionAttributes/BitsPerPixel': Use hardware value 'AcquisitionAttributes/HardwareMaximumQueuedBufferCount': 1000 'AcquisitionAttributes/HardwareRequeueBufferListThreshold': 50.0 'AcquisitionAttributes/Height': 1520 'AcquisitionAttributes/ImageDecoderCopyMode': Auto 'AcquisitionAttributes/OutputImageType': Auto 'AcquisitionAttributes/OverwriteMode': Get Newest 'AcquisitionAttributes/PayloadSize': 8755200 'AcquisitionAttributes/PixelFormat': BGRA 8 Packed 'AcquisitionAttributes/ReceiveTimestampMode': None 'AcquisitionAttributes/ShiftPixelBits': False 'AcquisitionAttributes/SwapPixelBytes': False 'AcquisitionAttributes/Timeout': 5000 'AcquisitionAttributes/VerticalMirror': False 'AcquisitionAttributes/VideoMode': 1920x1520 MJPG 30.00fps 'AcquisitionAttributes/Width': 1920 'CameraAttributes/BacklightCompensation/Mode': Manual 'CameraAttributes/BacklightCompensation/Value': True 'CameraAttributes/Brightness/Mode': Manual 'CameraAttributes/Brightness/Value': 0 'CameraAttributes/Contrast/Mode': Manual 'CameraAttributes/Contrast/Value': 0.0 'CameraAttributes/Exposure/Mode': Manual 'CameraAttributes/Exposure/Value': 0.125 'CameraAttributes/Gamma/Mode': Manual 'CameraAttributes/Gamma/Value': 1.0 'CameraAttributes/Hue/Mode': Manual 'CameraAttributes/Hue/Value': 0.0 'CameraAttributes/Saturation/Mode': Manual 'CameraAttributes/Saturation/Value': 64 'CameraAttributes/Sharpness/Mode': Manual 'CameraAttributes/Sharpness/Value': 2 'CameraAttributes/WhiteBalance/Mode': Manual 'CameraAttributes/WhiteBalance/Value': 4600 'CameraInformation/BaseAddress': 0 'CameraInformation/BusType': DirectShow 'CameraInformation/ModelName': 'CameraInformation/SerialNumberHigh': 2531778714 'CameraInformation/SerialNumberLow': 2530362052 'CameraInformation/VendorName': MD1200A 'StatusInformation/AcqInProgress': True 'StatusInformation/LastBufferCount': 131 'StatusInformation/LastBufferNumber': 130 'StatusInformation/LostBufferCount': 0 'Height': 1520 'PayloadSize': 8755200 'PixelFormat': BGRA 8 Packed 'Width': 1920)

AlexShkarin commented 1 year ago

Could you examine other possible pixel formats by checking the value of ``device.ca["PixelFormat"].values"? It could be that some other format (e.g., not involving the alpha-channel or a monochrome one) would work better for you.

bhathawayML commented 1 year ago

Only ['BGRA 8 Packed'] is an available option.

AlexShkarin commented 1 year ago

OK, in this case the only solution I can see is to try to override the value if PayloadSize. For that you'll need to edit pylablib/devices/IMAQdx/IMAQdx.py file line 433 and replace it with, e.g., size_bytes=self.cav["Height"]*self.cav["Width"]*4. This will break the functionality for other pixel formats (which don't have 4 bytes per pixel), but has a chance of fixing your issue.

bhathawayML commented 1 year ago

That fixed it! Thank you so much. I added the following lines after the pixel_formatdefinition to hopefully avoid problems with other formats:

if "BGRA" in pixel_format or "RGBA" in pixel_format:
    size_bytes = self.cav["Height"] * self.cav["Width"] * 4
else:
    size_bytes = self.cav["PayloadSize"]
AlexShkarin commented 1 year ago

Glad that worked! I'll add something similar to the next version, either by trying to figure out the number of bytes based on the pixel format, or by adding an option to specify it explicitly (for some weird packed formats).