处理图像#
图像表示#
在 pypylon 中,图像会作为 NumPy 数组等形式公开,这意味着它们可以直接用于科学计算和机器视觉工作流中。
这是一个典型的工作流:
访问图像数据#
了解何时需要从抓取结果中复制数据以及何时不需要复制至关重要。过度复制会浪费时间,而复制不足则可能导致崩溃或像素数据不正确。
| 代码 | 描述 | 是否需要复制? |
|---|---|---|
.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) |
您可以直接检查形状:
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),uint8PixelType_Mono16→(height, width),uint16PixelType_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 负载
避免这种情况的策略:
- 减小感兴趣区域 (ROI)(请参阅 Configuring Camera Parameters)
- 避免不必要的转换
在处理管线中使用图像#
由于图像是 NumPy 数组,因此可以直接将其与 OpenCV、NumPy Operations 以及 AI/ML Frameworks 一起使用。
这是图像处理管道的通用示意图。
这代表了大多数机器视觉系统的核心数据流。
OpenCV#
NumPy 操作#
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}%")
以下是各个步骤的说明:
-
灰度转换:
-
归一化:
-
阈值化:
-
统计评估:
通用的 NumPy 图像管道如下所示:
核心要点#
- 图像以 NumPy 数组的形式提供。
- 在需要时务必复制缓冲区数据。
- 请确保您使用的是正确的 Pixel Format。
- 后续处理可能需要进行转换。