2

我有来自 SICK Trispector 深度激光扫描仪的图像。图片格式为PNG。SICK 称之为 Trispector 2.5D PNG。根据 SICK 的文档,这些图像包含反射数据和深度数据。但 SICK 不会提供有关如何在不使用其或合作伙伴的软件的情况下使用这些数据的信息。本质上,我需要的是深度数据。反射数据可能很好,但不是必需的。我得到的结果图像是单色的。图像顶部似乎有反射数据,底部有重叠高度数据。扫描的对象是一箱带瓶盖的啤酒瓶。你可以在这里看到一个例子:

扫描图像

我尝试在许多不同的图像查看器中打开图像并查找有关 2.5D 的信息,但它似乎与此无关。在 Matlab 图像预览中,我分别获得了高度数据的一侧,但我不知道如何使用这些信息。从 Matlab 预览中查看以下图像:

扫描图像的 Matlab 预览

有谁知道如何从这样的图像中推断高度数据?可能有人以前用过 SICK 的 SOPAS 或 SICK 扫描仪,了解这种 SICK 称之为“2.5D PNG”的格式。OpenCV 解决方案会很好。

编辑:正如@DanMašek 评论的那样,问题在于将两个不同位深度的图像从一个PNG 中分离出来。他提供了对该问题的进一步洞察,并提供了一个出色的 OpenCV 解决方案,用于将强度和深度图像分别分离为 8 位和 16 位:

使用@DanMašek 的方法正确分离强度和深度图像

4

1 回答 1

1

注意:此信息基于 SICK 支持论坛上的SICK TriSpector 常见问题解答(不可公开访问,但您可以请求访问)。


SICK TriSpector 生成的 PNG 图像存储两个像素缓冲区的串联:

  • 8 位强度图像
  • 16 位(小端)高度图图像

生成的 PNG 图像与每个组件具有相同的宽度,而高度是其三倍(因为 PNG 是 8 位的,每个像素位置总共有 3 个字节)。

让我们考虑一个简单的示例,其中组件有 3 行和 4 列。存储在 PNG 中的数据将具有以下结构:

源 PNG 的布局以及将其拆分为两个组件的方式

如上图所示,第一步是将图像拆分为两个组件。PNG 包含 9 行,其中三分之一是 3 行——因此第 0-2 行包含强度,其余的是高度图。强度图直接可用,高度图需要进一步处理。

如果我们使用 little-endian 架构并且不关心可移植性,我们可以利用内存中的布局并将像素缓冲区重新解释为 16 位无符号整数(在 Pythonnumpy.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 倍,同时保存以作说明,丢失了很多细节):

示例缩小的高度图图像

于 2020-03-26T00:52:20.307 回答