gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 16:09:31 26 4
gpt4 key购买 nike

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

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

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

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

Correctly separated intensity and depth images using @DanMašek's approach

最佳答案

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

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

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

  • 生成的PNG图像的宽度与每个分量的宽度相同,并且高度为原来的三倍(因为PNG为8位,并且每个像素位置共有3个字节)。

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

    Layout of the source PNG and way to split it into the two components

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

    如果我们使用的是Little-endian架构,并且不关心可移植性,则可以利用内存中的布局,只需将像素缓冲区重新解释为16位无符号整数(在Python numpy.ndarray.view 中,在C++中,创建新的 Mat包装缓冲区)。

    较灵活但较慢的方法是手动组合零件。调整数组的形状以使其具有正确的行数,然后根据奇数或偶数列号将其拆分(Python中的跳过索引)。将每个子数组转换为16位无符号整数,最后根据 LSB + 256 * HSB公式将其组合。

    Illustration of splitting the height-map into sub-components

    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)

    提取强度图像:

    Example extracted intensity image

    提取的高度图图像(请注意,将原始数据缩小了256倍,同时将其保存下来用于说明,从而失去了很多细节):

    Example downscaled heightmap image

    关于opencv - 如何从单个PNG分离大小为8和16的两个位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60848588/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com