Source code for herosdevices.hardware.ids.pixelformat
"""Various methods to unpack pixel formats supported by the IDS cameras."""
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ids_peak_ipl.ids_peak_ipl import Image
import numpy as np
try:
from ids_peak_common.datatypes.pixelformat import PixelFormat
_ids_peak_available = True
except ModuleNotFoundError:
_ids_peak_available = False
def _unpack_mono12g24(buffer: bytearray, shape: tuple | None = None) -> np.ndarray:
"""Unpack the MONO12G24IDS format used by some IDS cameras.
The format packs 2 x 12bit into 3 bytes as shown in
https://www.1stvision.com/cameras/IDS/IDS-manuals/en/basics-monochrome-pixel-formats.html
In short for the two consecutive pixels A and B with bits A0..A11 and B0..B11 (A0 and B0 being MSB) the packing is
| A0..A7 | B0..B7 | B8..B11 A8..A11 |
| byte 0 | byte 1 | byte 2 |
The method returns a uint16 ndarray in the given shape.
Args:
buffer: the buffer/memoryview holding the packed data
shape: shape of the numpy array to return. If none is given a flat array is returned.
"""
np_buffer = np.frombuffer(buffer, dtype=np.uint8).astype(np.uint16)
img = np.empty(int(len(np_buffer) / 3) * 2, dtype=np.uint16)
img[0::2] = (np_buffer[0::3] << 4) + (np_buffer[2::3] & 0xF)
img[1::2] = (np_buffer[1::3] << 4) + ((np_buffer[2::3] & 0xF0) >> 4)
shape = shape if shape is not None else (len(img),)
return img.reshape(shape)
def _unpack_mono10g40(buffer: bytearray, shape: tuple | None = None) -> np.ndarray:
"""Unpack the MONO10G40IDS format used by some IDS cameras.
The format packs 4 x 10bit into 5 bytes as shown in
https://www.1stvision.com/cameras/IDS/IDS-manuals/en/basics-monochrome-pixel-formats.html
In short for the four consecutive pixels A to D with bits A0..A9 to D0..D9 (A0 and D0 being MSB) the packing is
| A0..A7 | B0..B7 | C0..C7 | D0..D7 | D8..D9 C8..C9 B8..B9 A8..A9 |
| byte 0 | byte 1 | byte 2 | byte 3 | byte 4 |
The method returns a uint16 ndarray in the given shape.
Args:
buffer: the buffer/memoryview holding the packed data
shape: shape of the numpy array to return. If none is given a flat array is returned.
"""
np_buffer = np.frombuffer(buffer, dtype=np.uint8).astype(np.uint16)
img = np.empty(int(len(np_buffer) / 5) * 4, dtype=np.uint16)
img[0::4] = (np_buffer[0::5] << 2) + (np_buffer[4::5] & 0x3)
img[1::4] = (np_buffer[1::5] << 2) + ((np_buffer[4::5] >> 2) & 0x3)
img[2::4] = (np_buffer[2::5] << 2) + ((np_buffer[4::5] >> 4) & 0x3)
img[3::4] = (np_buffer[3::5] << 2) + (np_buffer[4::5] >> 6)
shape = shape if shape is not None else (len(img),)
return img.reshape(shape)
def _unpack_mono12p(buffer: bytearray, shape: tuple | None = None) -> np.ndarray:
"""Unpack the MONO12P format.
The format packs 2 x 12bit into 3 bytes as shown in
https://www.1stvision.com/cameras/IDS/IDS-manuals/en/basics-monochrome-pixel-formats.html
The bytes hold a continuous little-endian bit stream of the pixel values, i.e. for the
two consecutive pixels A and B with bits A0..A11 and B0..B11 (A0 and B0 being MSB) the packing is
| A4..A11 | B8..B11 A0..A3 | B0..B7 |
| byte 0 | byte 1 | byte 2 |
The method returns a uint16 ndarray in the given shape.
Args:
buffer: the buffer/memoryview holding the packed data
shape: shape of the numpy array to return. If none is given a flat array is returned.
"""
np_buffer = np.frombuffer(buffer, dtype=np.uint8).astype(np.uint16)
img = np.empty(int(len(np_buffer) / 3) * 2, dtype=np.uint16)
img[0::2] = np_buffer[0::3] + ((np_buffer[1::3] & 0xF) << 8)
img[1::2] = (np_buffer[2::3] << 4) + (np_buffer[1::3] >> 4)
shape = shape if shape is not None else (len(img),)
return img.reshape(shape)
def _unpack_mono10p(buffer: bytearray, shape: tuple | None = None) -> np.ndarray:
"""Unpack the MONO10P format.
The format packs 4 x 10bit into 5 bytes as shown in
https://www.1stvision.com/cameras/IDS/IDS-manuals/en/basics-monochrome-pixel-formats.html
The bytes hold a continuous little-endian bit stream of the pixel values, i.e. for the
four consecutive pixels A to D with bits A0..A9 to D0..D9 (A0 and D0 being MSB) the packing is
| A2..A9 | B4..B9 A0..A1 | C6..C9 B0..B3 | D8..D9 C0..C5 | D0..D7 |
| byte 0 | byte 1 | byte 2 | byte 3 | byte 4 |
The method returns a uint16 ndarray in the given shape.
Args:
buffer: the buffer/memoryview holding the packed data
shape: shape of the numpy array to return. If none is given a flat array is returned.
"""
np_buffer = np.frombuffer(buffer, dtype=np.uint8).astype(np.uint16)
img = np.empty(int(len(np_buffer) / 5) * 4, dtype=np.uint16)
img[0::4] = np_buffer[0::5] + ((np_buffer[1::5] & 0x3) << 8)
img[1::4] = (np_buffer[1::5] >> 2) + ((np_buffer[2::5] & 0xF) << 6)
img[2::4] = (np_buffer[2::5] >> 4) + ((np_buffer[3::5] & 0x3F) << 4)
img[3::4] = (np_buffer[3::5] >> 6) + (np_buffer[4::5] << 2)
shape = shape if shape is not None else (len(img),)
return img.reshape(shape)
if _ids_peak_available:
_unpackers = {
PixelFormat.MONO_10_GROUPED_40_IDS: _unpack_mono10g40,
PixelFormat.MONO_10_PACKED: _unpack_mono10p,
PixelFormat.MONO_12_GROUPED_24_IDS: _unpack_mono12g24,
PixelFormat.MONO_12_PACKED: _unpack_mono12p,
}
def _convert_nonpacked(ipl_image: "Image") -> np.ndarray:
"""Convert images that are not in packed data format to ndarray.
we rely on the `get_numpy_XX_XX()` methods in the ipl_image objects
here to do the conversion.
Args:
ipl_image: image in a non-packed pixel format
"""
pixel_format = PixelFormat(ipl_image.PixelFormat().PixelFormatName())
# monochrome image format -> return 2D ndarray
if pixel_format.is_single_channel:
if pixel_format.allocated_bits_per_pixel == 8: # noqa: PLR2004
return ipl_image.get_numpy_2D()
return ipl_image.get_numpy_2D_16()
# color image format -> return 3D ndarray
if pixel_format.allocated_bits_per_pixel == 8: # noqa: PLR2004
return ipl_image.get_numpy_3D()
return ipl_image.get_numpy_3D_16()
[docs]
def ipl_image_to_ndarray(ipl_image: "Image") -> np.ndarray:
"""Convert a IDS Peak image to a numpy array and perform pixel format conversion if necessary.
Args:
ipl_image: the IDS peak image object()
"""
pixel_format = PixelFormat(ipl_image.PixelFormat().PixelFormatName())
# special treatment for IDS packed pixel formats
if pixel_format in _unpackers:
img = _unpackers[pixel_format](bytearray(ipl_image.DataView()), (ipl_image.Height(), ipl_image.Width()))
else:
img = _convert_nonpacked(ipl_image)
return img