Примечание. Эта информация основана на FAQ по SICK TriSpector , который находится на форумах поддержки SICK (недоступен для общего доступа, но вы можете запросить доступ).
Изображения PNG сгенерированный SICK TriSpector хранит конкатенацию двух пиксельных буферов:
- 8-битное изображение с интенсивностью
- 16-битное (с прямым порядком байтов) изображение карты высот
Полученное PNG-изображение имеет ту же ширину, что и каждый компонент, и в три раза больше высоты (поскольку PNG является 8-битным, и у нас есть 3 байта для каждой позиции пикселя).
Давайте рассмотрим Простой пример, где компоненты имеют 3 строки и 4 столбца. Данные, хранящиеся в PNG, будут иметь следующую структуру:
Первый шаг, как показано выше, состоит в том, чтобы разделить изображение на два компонента. , PNG содержит 9 строк, треть из которых - 3 строки, поэтому строки 0-2 содержат интенсивность, а остальные - карту высот. Изображение интенсивности можно использовать напрямую, карта высот нуждается в дальнейшей обработке.
Если мы используем архитектуру с прямым порядком байтов и не заботимся о переносимости, мы можем воспользоваться макетом в памяти и просто переосмыслить пиксельный буфер в виде 16-битных целых чисел без знака (в Python numpy.ndarray.view
, в C ++ создайте новый Mat
обертывание буфера).
Более гибкий, хотя и более медленный метод заключается в объединить части вручную. Измените массив таким образом, чтобы он содержал правильное количество строк, а затем разбейте его на основе нечетного или четного номера столбца (пропустите индексирование в Python). Преобразуйте каждый вложенный массив в 16-битные целые числа без знака и, наконец, объедините их по формуле LSB + 256 * HSB
.
Пример сценария в Python:
import cv2
import numpy as np
img = cv2.imread('combined.png', cv2.IMREAD_GRAYSCALE)
height, width = img.shape
# Determine the actual height of the component images
real_height = height/3
# Extract the top (intensity) part
intensity_img = img[:real_height,...]
# Extract the botton (heightmap) part
# Since this has two values per pixel, also reshape it to have the correct number of rows
heightmap_raw = img[real_height:,...].reshape(real_height,-1)
# The heightmap is 16 bit, two subsequent 8 bit pixels need to be combined
# ABCD -> A+256*B, C+256*D
# Quick but non-portable (needs little-endian architecture)
heightmap_img = heightmap_raw.view(np.uint16)
# Slower but portable
heightmap_a = heightmap_raw[...,::2].astype(np.uint16)
heightmap_b = heightmap_raw[...,1::2].astype(np.uint16)
heightmap_img = heightmap_a + 256 * heightmap_b
# Note: intensity is np.uint8, heightmap is np.uint16
cv2.imwrite('intensity.png', intensity_img)
cv2.imwrite('heightmap.png', heightmap_img)
Извлеченное изображение интенсивности:
Извлеченное изображение карты высот (обратите внимание, что оригинал данные были уменьшены в 256 раз при сохранении этого для иллюстрации, потеряв много деталей):