跳转到内容
STAGING SERVER
DEVELOPMENT SERVER

处理图像#

本主题介绍图像数据在 pypylon 中的表示方式、如何安全地访问这些图像数据,以及如何准备将其用于进一步处理(例如使用 NumPy、OpenCV 或 AI 框架)。

图像表示#

在 pypylon 中,图像会作为 NumPy 数组等形式公开,这意味着它们可以直接用于科学计算和机器视觉工作流中。

这是一个典型的工作流:

Camera → GrabResult → Buffer → NumPy Array

访问图像数据#

了解何时需要从抓取结果中复制数据以及何时不需要复制至关重要。过度复制会浪费时间,而复制不足则可能导致崩溃或像素数据不正确。

代码 描述 是否需要复制?
.Array 返回一个 NumPy 副本 否(已经是副本)
.GetMemoryView() 返回缓冲区视图 是
.GetArrayZeroCopy() 返回零拷贝数组 是
  • grab_result.Array 是内部缓冲区的副本。
  • grab_result.GetMemoryView() 是一个 指向内部缓冲区的视图 (像素类型除外,其中 pylon.IsPacked(grab_result.PixelType) 为 True)。
  • grab_result.GetArrayZeroCopy() 是一个 指向内部缓冲区的视图 提供一个不进行拷贝的 NumPy 数组(适用于以下像素格式: pylon.IsPacked(grab_result.PixelType) 为 True)。
  • 抓取结果缓冲区会在离开以下代码块 with 或 grab_result.Release() 被调用。
  • 在缓冲区释放后访问 Memory 视图或零拷贝数组可能会导致无效的 Memory 访问。

正确用法:

with camera.RetrieveResult(5000) as grab_result:
    if grab_result.GrabSucceeded():
        image = grab_result.Array

图像形状与格式#

数组的形状取决于 Pixel Format:

Pixel Format 形状示例
Mono8 (高度,宽度)
RGB8/BGR8 (高度,宽度,3)

您可以直接检查形状:

print(image.shape)

Pixel Format 转换#

根据相机配置,原始图像格式可能不适用,需要进行转换。

示例:转换为 BGR(兼容 OpenCV)

converter = pylon.ImageFormatConverter()
converter.OutputPixelFormat = pylon.PixelType_BGR8packed

image = converter.Convert(grab_result).GetArray()

信息

在 ImageFormatConverter, OutputPixelFormat 是一个存储像素类型值的普通属性,而不是 Property 节点。请直接赋值(converter.OutputPixelFormat = pylon.PixelType_BGR8packed)。它没有 .Value 访问器。

直接转换为 NumPy 数组(ConvertToArray)#

converter.Convert(src) 返回一个 PylonImage。使用 .Array (或 .GetArray()读取其像素),会对已转换的缓冲区进行 额外拷贝 。如果您只需要将结果作为 NumPy 数组,请改用 converter.ConvertToArray(src) 。这会预先分配一个具有正确形状和数据类型的 NumPy 数组,并让转换器将转换后的像素写入其中 直接存入该数组,从而避免了额外的复制。

converter = pylon.ImageFormatConverter()
converter.OutputPixelFormat = pylon.PixelType_BGR8packed

# Equivalent result to converter.Convert(grab_result).Array, but without the extra copy.
image = converter.ConvertToArray(grab_result)

ConvertToArray 接受与 Convert (抓取结果、 PylonImage、数据组件或任何 IImage)相同的源类型,且生成的数组形状和数据类型反映了 OutputPixelFormat:

  • PixelType_Mono8 → (height, width), uint8
  • PixelType_Mono16 → (height, width), uint16
  • PixelType_RGB8packed / PixelType_BGR8packed → (height, width, 3), uint8

位域打包的输出格式(即 pylon.IsPacked(pixel_type) 为 True 的格式)没有明确的 NumPy 形状/数据类型,因此 ConvertToArray 会默认对其 ValueError 引发异常。请传入 raw=True ,以便将转换后的字节作为一维 uint8 数组获取:

# raw=True returns a flat uint8 array of the converted bytes,
# which is also how to handle bit-packed output formats.
raw_bytes = converter.ConvertToArray(grab_result, raw=True)
方法 结果 是否有额外复制?
converter.Convert(src).Array 通过中间 PylonImage 是
converter.ConvertToArray(src) 生成的 NumPy 数组(原地写入) 无
converter.ConvertToArray(src, raw=True) 一维 uint8 数组(也适用于打包格式) 无

为什么需要转换#

  • 相机通常输出原始格式或 Bayer 格式。
  • 应用程序通常期望:
    • BGR (OpenCV)
    • RGB(可视化)

常见陷阱#

在缓冲区释放后使用数据#

with camera.RetrieveResult(...) as grab_result:
    image = grab_result.Array # NumPy array
    memory_view = grab_result.GetMemoryView()
    with grab_result.GetArrayZeroCopy() as zero_copy_array:
        ... process zero_copy_array (NumPy array) ...

这样做是不安全的,因为 memory_view 现在可能引用无效的 Memory。如果需要在代码块外部使用,请务必使用 result.Array 或者保留 grab_result 保持活动状态。

忽略 Pixel Format#

请务必验证或明确设置 Pixel Format。忽略这一点可能会导致以下后果:

  • 错误的色彩解释
  • 不正确的处理结果

性能开销#

以下操作可能会降低性能:

  • 复制大图像需要耗费时间
  • 转换会增加 CPU 负载

避免这种情况的策略:

在处理管线中使用图像#

由于图像是 NumPy 数组,因此可以直接将其与 OpenCV、NumPy Operations 以及 AI/ML Frameworks 一起使用。

这是图像处理管道的通用示意图。

Camera → GrabResult → NumPy Array → Processing → Output

这代表了大多数机器视觉系统的核心数据流。

OpenCV#

import cv2

cv2.imshow("image", image)
cv2.waitKey(1)

NumPy 操作#

mean = image.mean()

AI/ML 框架#

  • PyTorch
  • TensorFlow

使用 NumPy 的示例图像处理管线#

NumPy 能够直接对采集到的图像进行快速的矢量化图像处理。

以下示例是一个使用 NumPy 的小巧但真实的图像处理管道。

示例代码#

import numpy as np
from pypylon import pylon

with pylon.InstantCamera(pylon.FirstFound) as camera:

    camera.StartGrabbingMax(100)

    while camera.IsGrabbing():
        with camera.RetrieveResult(5000) as grab_result:
            if grab_result.GrabSucceeded():
                image = grab_result.Array

                # Do something with the image data.

                if image.ndim == 3:
                    gray = image.mean(axis=2)
                else:
                    gray = image

                norm = gray / 255.0

                binary = norm > 0.5

                mean_intensity = norm.mean()
                bright_pixel_ratio = binary.mean()

                print(f"Mean intensity: {mean_intensity:.3f}")
                print(f"Bright pixels: {bright_pixel_ratio*100:.1f}%")

以下是各个步骤的说明:

  • 灰度转换:

    gray = image.mean(axis=2)
    
  • 归一化:

    norm = gray / 255.0
    
  • 阈值化:

    binary = norm > 0.5
    
  • 统计评估:

    mean_intensity = norm.mean()
    bright_pixel_ratio = binary.mean()
    

通用的 NumPy 图像管道如下所示:

Raw Image → NumPy Array → Processing → Features → Decision

核心要点#

  • 图像以 NumPy 数组的形式提供。
  • 在需要时务必复制缓冲区数据。
  • 请确保您使用的是正确的 Pixel Format。
  • 后续处理可能需要进行转换。