Opencv 如何从单个PNG中分离大小为8和16的两个位图

Opencv 如何从单个PNG中分离大小为8和16的两个位图,opencv,image-processing,png,2.5d,Opencv,Image Processing,Png,2.5d,我有一个病态的三心深度激光扫描仪的图像。图像格式为PNG。SICK称之为Trispist 2.5D PNG。根据SICK的文档,这些图像包含反射数据和深度数据。但是,如果没有使用他们或合作伙伴的软件,SICK将不会提供如何使用这些数据的信息。本质上,我需要的是深度数据。反射数据可能是一个很好的选择,但不是必需的。我得到的结果图像是单色的。它似乎在图像的顶部有反射数据,在底部有重叠的高度数据。扫描对象是一箱带瓶盖的啤酒瓶。您可以在此处看到一个示例: 我曾尝试在许多不同的图像查看器中打开图像,并在

我有一个病态的三心深度激光扫描仪的图像。图像格式为PNG。SICK称之为Trispist 2.5D PNG。根据SICK的文档,这些图像包含反射数据和深度数据。但是,如果没有使用他们或合作伙伴的软件,SICK将不会提供如何使用这些数据的信息。本质上,我需要的是深度数据。反射数据可能是一个很好的选择,但不是必需的。我得到的结果图像是单色的。它似乎在图像的顶部有反射数据,在底部有重叠的高度数据。扫描对象是一箱带瓶盖的啤酒瓶。您可以在此处看到一个示例:

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

有人知道如何从这样的图像中推断高度数据吗?也许有人以前使用过SICK的SOPA或SICK扫描仪,并且理解SICK称之为“2.5D PNG”的格式。一个OpenCV解决方案会很好

编辑:正如@DanMašek评论的那样,问题在于从一个PNG中分离两个不同比特深度的图像。他进一步深入了解了这个问题,并提供了一个很棒的OpenCV解决方案,分别将强度图像和深度图像分离为8位和16位:


注意:此信息基于位于SICK support Forum(不可公开访问,但您可以请求访问)上的


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

  • 8位强度图像
  • 16位(小端)高度贴图图像
生成的PNG图像与每个组件具有相同的宽度,是高度的三倍(因为PNG是8位的,每个像素位置总共有3个字节)

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

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

如果我们在一个小的EnDead架构,不关心可移植性,我们可以利用内存布局,重新解释像素缓冲区为16位无符号整数(在Python中,C++中创建一个新的<代码>垫/代码>包缓冲区)。 更灵活但速度较慢的方法是手动组合零件。重新调整数组的形状以获得正确的行数,然后根据奇数或偶数列数将其拆分(在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倍,同时将其保存为插图,丢失了大量细节):


我想告诉他们,您正在寻找一家新的扫描仪供应商,该供应商实际上可以让您了解扫描仪提供的数据。来源:“这是正常的。三色胸肌的.png图像分为两部分,顶部为8位强度图像,底部为16位高度图。由于.png图像是8位的,因此高度贴图需要png图像中每个真实像素有两个像素。因此,它变大了一倍,看起来已经损坏了。如果要查看图像,请使用Trispist仿真器加载它。“|还有一点,但让我先吃完午餐:)这里有一个简单的Python脚本,演示如何从PNG中分离这两个组件:投票重新打开这个问题——我认为问题陈述是完整的,这只是一个有点模糊的硬件特性。我已经准备好了一个带插图的答案(基于SICK的官方信息)以及Python的概念证明(见上文——没有Matlab可用)。@DanMašek我同意,您提供了一个很好的解决方案,并说明我的问题更多地与从单个PNG中分离大小为8和16的两个位图有关。如果我能把你的问题标记为答案,我会的。我显然是新来的,所以让我知道我能做什么。谢谢