image --- 机器视觉

image 模块是 OpenMV 机器视觉栈的核心。它提供了 Image 类——所有绘制、滤波、变换和特征提取例程所操作的内存像素缓冲区——以及这些例程所返回的相关结果对象(BlobLineCircleRectQRCodeAprilTagDataMatrixBarCode、……),以及用于配置它们的辅助类(ThresholdHistogramStatisticsHaarCascadeSimilarityPercentileDisplacementImageIO)。

获取图像

有四种方式可以将 Image 加载到 RAM 中:

  • 从摄像头传感器实时捕获。 调用 csi.CSI.snapshot() 将下一帧直接捕获到帧缓冲区中;返回的 Image 引用了该缓冲区。

  • 从文件加载。 将路径传递给 Image 构造函数(image.Image("/sd/photo.jpg"));支持的磁盘格式有 BMP、PPM/PGM、JPEG、PNG 以及 OpenMV 的 ImageIO 录制格式。

  • 从 ndarray 加载。 将一个 float32 类型的 (h, w)(h, w, 3) ndarray 传递给 Image 构造函数。像素值会从 0.0 -- 255.0 分别缩放为 GRAYSCALE 或 RGB565 图像。可用此方式将 ml(或任何 ulab 流水线)的张量输出转换回可绘制的图像。

  • 空缓冲区。 以给定的尺寸和像素格式构造一个 Imageimage.Image(320, 240, image.RGB565)),以便从零开始绘制,或用作图像运算的临时表面。

像素格式

每个 Image 都具有以下某一种像素格式;该选择需要在内存、处理开销以及可运行哪些算法之间进行权衡。在构造图像或配置摄像头传感器时,使用 BINARYGRAYSCALERGB565BAYERYUV422JPEGPNG 作为 pixformat 参数:

  • BINARY (1 bpp) —— 每像素一位。最小的格式;由阈值化和形态学例程在内部使用,但很少直接从传感器捕获。

  • GRAYSCALE (8 bpp) —— 每像素一字节(YUV422 的 Y 通道)。对大多数机器视觉算法(AprilTag、边缘检测、光流)而言是最快的格式。

  • RGB565 (16 bpp) —— 每像素两字节,5 位红色 / 6 位绿色 / 5 位蓝色。默认的颜色格式。

  • BAYER (8 bpp) —— 直接来自传感器的原始拜耳模式颜色数据。适用于自定义去马赛克处理,或在按需去拜耳之前以更少的内存存储更多像素。

  • YUV422 (16 bpp) —— 4:2:2 色度二次采样的颜色,每像素两字节。当你想使用特定于色度的算法而又不必承担完整 RGB 开销时很有用。

  • JPEG / PNG —— 压缩缓冲区。最适合用于存储和网络传输。像素级操作需要先调用 Image.to_grayscale()Image.to_rgb565()

处理结果

Image 上的检测 / 特征提取方法会返回可供你迭代和组合的对象——一次 Image.find_blobs() 调用返回一个 Blob 列表,一次 Image.find_apriltags() 调用返回一个 AprilTag 列表,依此类推。每个结果类都暴露了该检测的几何属性(质心、边界框、面积、码值等),因此你可以直接对它们进行操作,或将它们传回绘制方法(Image.draw_rectangle()Image.draw_string()、……)。

色彩空间辅助函数

该模块还提供了一些小型纯函数,用于在二值 / 灰度 / RGB / LAB / YUV 色彩空间之间转换单个像素值。当你需要在 Python 中转换阈值或调色板条目,然后再将其传入图像操作时,这些函数很有用——对于整幅图像的转换,请使用 Imageto_* 方法,它们比在循环中调用这些辅助函数要快得多。

函数

色彩空间转换辅助函数

下面的每个 X_to_Y 函数执行单个像素值的转换。它们都以 OpenMV 的规范范围取值/返回值:

  • 二值 —— int 0 -- 1。

  • 灰度 —— int 0 -- 255。

  • RGB —— 由 8 位整数组成的 (r, g, b) 元组(每个为 0 -- 255)。

  • LAB —— (l, a, b) 元组,其中 L 取值 0 -- 100,A/B 取值 -128 -- 127。

  • YUV —— (y, u, v) 元组,其中 Y 取值 0 -- 255,U/V 取值 -128 -- 127。

对于整幅图像的转换,请使用 Imageto_* 方法,它们比在循环中调用这些辅助函数要快得多。

image.binary_to_grayscale(value: int) int

将二值值转换为灰度值。

image.binary_to_rgb(value: int) Tuple[int, int, int]

将二值值转换为 RGB 元组。

image.binary_to_lab(value: int) Tuple[int, int, int]

将二值值转换为 LAB 元组。

image.binary_to_yuv(value: int) Tuple[int, int, int]

将二值值转换为 YUV 元组。

image.grayscale_to_binary(value: int) int

将灰度值转换为二值值。

image.grayscale_to_rgb(value: int) Tuple[int, int, int]

将灰度值转换为 RGB 元组。

image.grayscale_to_lab(value: int) Tuple[int, int, int]

将灰度值转换为 LAB 元组。

image.grayscale_to_yuv(value: int) Tuple[int, int, int]

将灰度值转换为 YUV 元组。

image.rgb_to_binary(value: Tuple[int, int, int]) int

将 RGB 元组转换为二值值。

image.rgb_to_grayscale(value: Tuple[int, int, int]) int

将 RGB 元组转换为灰度值。

image.rgb_to_lab(value: Tuple[int, int, int]) Tuple[int, int, int]

将 RGB 元组转换为 LAB 元组。

image.rgb_to_yuv(value: Tuple[int, int, int]) Tuple[int, int, int]

将 RGB 元组转换为 YUV 元组。

image.lab_to_binary(value: Tuple[int, int, int]) int

将 LAB 元组转换为二值值。

image.lab_to_grayscale(value: Tuple[int, int, int]) int

将 LAB 元组转换为灰度值。

image.lab_to_rgb(value: Tuple[int, int, int]) Tuple[int, int, int]

将 LAB 元组转换为 RGB 元组。

image.lab_to_yuv(value: Tuple[int, int, int]) Tuple[int, int, int]

将 LAB 元组转换为 YUV 元组。

image.yuv_to_binary(value: Tuple[int, int, int]) int

将 YUV 元组转换为二值值。

image.yuv_to_grayscale(value: Tuple[int, int, int]) int

将 YUV 元组转换为灰度值。

image.yuv_to_rgb(value: Tuple[int, int, int]) Tuple[int, int, int]

将 YUV 元组转换为 RGB 元组。

image.yuv_to_lab(value: Tuple[int, int, int]) Tuple[int, int, int]

将 YUV 元组转换为 LAB 元组。

特征描述符

image.HaarCascade(path: str, stages: int = -1) Cascade

加载一个 Haar 级联并返回一个 Cascade 句柄,供 Image.find_features() 使用。

path 可以是:

  • 字面字符串 "frontalface""eye",用于加载固件 ROM 中内置的两个级联之一,或者

  • 指向由 OpenMV 级联转换工具生成的自定义 .cascade 二进制文件的文件系统路径。

stages 选择在检测时评估多少个级联阶段。-1 使用文件中存储的每一个阶段。减小该值可加快检测速度,但代价是产生更多误报。

image.load_descriptor(path: str) kp_desc | lbp_desc

path 处的文件加载一个描述符并返回它。文件内部的类型标签决定了重建哪个描述符类:

image.save_descriptor(descriptor: kp_desc | lbp_desc, path: str) None

descriptor(一个 ORB 关键点或 LBP 描述符)以 OpenMV 描述符文件格式序列化到 path 处的文件。该文件之后可通过 image.load_descriptor() 重新加载。

image.match_descriptor(descriptor0, descriptor1, threshold: int = 85, filter_outliers: bool = False) int | kptmatch

匹配两个相同类型的描述符。

  • 对于两个 LBP 描述符 —— 返回它们之间的整数汉明距离(越低表示匹配越接近)。

  • 对于两个 ORB 关键点描述符 —— 返回一个 kptmatch,描述匹配的关键点簇;如果没有匹配通过 threshold,则返回 None

threshold(0 -- 100)设置 ORB 匹配在接受关键点对时的严格程度。较低的值通过拒绝弱的最近邻匹配来收紧匹配。

filter_outliers 在匹配的关键点集合上启用 RANSAC 风格的离群点剔除。当你预期两个视图之间存在单一刚性变换时使用它;当匹配的关键点跨越多个物体时禁用它。

色块几何辅助函数

这些辅助函数接收一个 Blob(由 Image.find_blobs() 返回)并按需计算额外的几何属性。它们位于模块作用域——而不在 Blob 上——因此基本的 find_blobs() 路径除非你主动调用,否则不会为它们付出开销。

image.get_solidity(blob: blob) float

返回 blob 的实度(blob.pixels / convex_hull_area)。浮点数,0 -- 1;1.0 表示色块完全填满了它的凸包。

image.get_convexity(blob: blob) float

返回 blob 的凸度(convex_hull_perimeter / blob.perimeter)。浮点数,0 -- 1;1.0 表示一个完全凸的色块。

image.get_major_axis_line(blob: blob) line

返回沿 blob 主轴的一条 Line(最小面积旋转矩形的两条主轴中较长的一条)。

image.get_minor_axis_line(blob: blob) line

返回沿 blob 次轴的一条 Line(最小面积旋转矩形的两条主轴中较短的一条)。

image.get_enclosing_circle(blob: blob) circle

返回一个包围 blobCircle

image.get_enclosed_ellipse(blob: blob) Tuple[int, int, int, int, int]

返回一个 5 元组 (cx, cy, a, b, rotation),描述内接于 blob 周围最小面积旋转矩形的椭圆:

  • cx / cy —— 椭圆中心,以像素为单位(整数)。

  • a / b —— 半轴长度,以像素为单位(整数)。

  • rotation —— 椭圆旋转角度,以度为单位(整数)。

这是一个普通元组,而非 attrtuple,因此其字段只能通过索引访问。

常量

像素格式

将以下任意一项作为 pixformat 参数传递给 Image 构造函数或 csi.CSI.pixformat()

image.BINARY: int

每像素 1 位的位图。最小的格式 —— 由阈值化和形态学在内部使用,很少直接从传感器捕获。

image.GRAYSCALE: int

每像素 8 位的灰度(每像素一字节)。对大多数机器视觉算法(AprilTag、边缘检测、光流)而言是最快的格式。

image.RGB565: int

每像素 16 位的颜色,打包为 5 位红色 / 6 位绿色 / 5 位蓝色。默认的颜色格式。

image.BAYER: int

直接来自传感器的每像素 8 位原始拜耳数据。大多数图像处理方法在拜耳图像上不可用;当你想按需去拜耳或以更少内存存储更多像素时使用它。

image.YUV422: int

4:2:2 色度二次采样的颜色,每像素两字节,每个像素对打包为 Y1, U, Y2, V。只有部分图像处理方法能直接在 YUV422 上工作。

image.JPEG: int

压缩的 JPEG 缓冲区。像素级操作需要先调用 Image.to_grayscale()Image.to_rgb565()

image.PNG: int

压缩的 PNG 缓冲区。像素级操作需要先调用 Image.to_grayscale()Image.to_rgb565()

颜色调色板

将以下任意一项传递给 Image.to_rainbow()Image.to_ironbow()Image.draw_image()color_palette=)或 csi.CSI.color_palette(),以对灰度图像进行着色。

image.PALETTE_RAINBOW: int

平滑的彩虹色轮。OpenMV 用于热成像的默认调色板。

image.PALETTE_IRONBOW: int

非线性的“铁红(ironbow)”调色板,模仿 FLIR Lepton 热成像取景器的外观。

image.PALETTE_DEPTH: int

深度图像调色板。仅在支持深度传感器的构建版本上可用(ToF 流水线——例如 OpenMV Cam AE3 或任何连接了 ToF Pmod 的摄像头)。

image.PALETTE_EVT_DARK: int

用于在深色背景上可视化 GENX320 事件相机帧的调色板。将其传递给 csi.CSI.color_palette,可让 GENX320 驱动在直方图模式下输出着色的 RGB565 帧;或在对灰度事件图像着色时传递给 Image.draw_image()color_palette=

仅在支持 GENX320 的构建版本上可用(OpenMV Cam AE3 和 GENX320 Pmod)。

image.PALETTE_EVT_LIGHT: int

用于在浅色背景上可视化 GENX320 事件相机帧的调色板。其分发方式和可用性与 PALETTE_EVT_DARK 相同。

缩放模式

将以下任意一项作为 hint 参数传递给 Image.draw_image()Image.scale() 或类似的缩放方法。

image.AREA: int

面积平均缩放器。在缩小时使用;放大时使用最近邻(Nearest-Neighbor)。

image.BILINEAR: int

双线性缩放器。缩小时进行二次采样。

image.BICUBIC: int

双三次缩放器。质量高于 BILINEAR 但更慢。缩小时进行二次采样。

绘制 / draw_image 提示

将以下任意几项按位或(Bit-OR)组合在一起,作为 Image.draw_image()hint 参数传递。

image.VFLIP: int

绘制时垂直翻转源图像。

image.HMIRROR: int

绘制时水平镜像源图像。

image.TRANSPOSE: int

绘制时转置(交换 x/y)源图像。

image.CENTER: int

将源图像在目标上居中。此后任何显式的 x/y 偏移都将变成相对于中心而非左上角的偏移。

image.EXTRACT_RGB_CHANNEL_FIRST: int

通过 Image.draw_image() 提取某个 RGB 通道时,在缩放之前提取该通道。若无此提示,则在缩放之后提取该通道。

image.APPLY_COLOR_PALETTE_FIRST: int

通过 Image.draw_image() 应用颜色调色板时,在缩放之前应用该调色板。若无此提示,则在缩放之后应用该调色板。

image.SCALE_ASPECT_KEEP: int

在保持宽高比的同时缩放源图像以适配目标内部(当宽高比不同时进行信箱式留边)。

image.SCALE_ASPECT_EXPAND: int

在保持宽高比的同时缩放源图像以填满目标(当宽高比不同时进行裁剪)。

image.SCALE_ASPECT_IGNORE: int

缩放源图像以填满目标,忽略宽高比。

image.BLACK_BACKGROUND: int

告诉 alpha 混合路径目标已知为黑色,从而可以跳过对目标像素的回读。在刚清空的缓冲区上可加快 alpha 效果。

image.ROTATE_90: int

VFLIP | TRANSPOSE 的快捷方式(顺时针旋转 90 度)。

image.ROTATE_180: int

HMIRROR | VFLIP 的快捷方式(旋转 180 度)。

image.ROTATE_270: int

HMIRROR | TRANSPOSE 的快捷方式(顺时针旋转 270 度)。

JPEG 二次采样

在写入 JPEG 时,将以下任意一项作为 subsampling 参数传递给 Image.to_jpeg()Image.compress()Image.save()

image.JPEG_SUBSAMPLING_AUTO: int

根据 JPEG 质量设置自动选择色度二次采样。

image.JPEG_SUBSAMPLING_444: int

强制 4:4:4 色度二次采样(无色度压缩)。

image.JPEG_SUBSAMPLING_422: int

强制 4:2:2 色度二次采样。当向那些在 4:2:0 下表现异常的第三方视频播放器流式传输 MJPEG 时推荐使用。

image.JPEG_SUBSAMPLING_420: int

强制 4:2:0 色度二次采样。

模板匹配

将以下任意一项作为 search 参数传递给 Image.find_template()

image.SEARCH_EX: int

穷举搜索 —— 评估 ROI 中的每个位置。最慢,但保证找到最佳匹配。

image.SEARCH_DS: int

菱形搜索 —— 由粗到细的搜索,比 SEARCH_EX 快得多,但在高度自相似的模板上可能错过全局最优解。

边缘检测

将以下任意一项作为 algorithm 参数传递给 Image.find_edges()

image.EDGE_CANNY: int

Canny 边缘检测器 —— 梯度幅值 + 非极大值抑制 + 滞后阈值。质量更高,更慢。

image.EDGE_SIMPLE: int

阈值化高通滤波边缘检测器。比 EDGE_CANNY 更快,但产生的边缘更粗、噪声更多。

ORB 角点检测器

将以下任意一项作为 corner_detector 参数传递给 Image.find_keypoints()

image.CORNER_FAST: int

FAST 角点检测器。比 CORNER_AGAST 更快但精度较低。

image.CORNER_AGAST: int

AGAST 角点检测器。比 CORNER_FAST 更慢但产生的关键点更稳定。

AprilTag 家族

将以下任意组合按位或(Bit-OR)后作为 families 参数传递给 Image.find_apriltags()。每个家族在固件中由其各自的构建选项控制;不支持的家族在运行时是缺失的,而非始终为零。

image.TAG16H5: int

AprilTag 16h5 家族(30 个唯一 ID,0 位纠错)。

image.TAG25H9: int

AprilTag 25h9 家族(35 个唯一 ID,最多 3 位纠错)。

image.TAG36H10: int

AprilTag 36h10 家族(2320 个唯一 ID,最多 3 位纠错)。

image.TAG36H11: int

AprilTag 36h11 家族(587 个唯一 ID,最多 4 位纠错)。最常用的家族。

image.TAGCIRCLE21H7: int

AprilTag Circle21h7 家族。

image.TAGCIRCLE49H12: int

AprilTag Circle49h12 家族。

image.TAGCUSTOM48H12: int

AprilTag Custom48h12 家族。

image.TAGSTANDARD41H12: int

AprilTag Standard41h12 家族。

image.TAGSTANDARD52H13: int

AprilTag Standard52h13 家族。

条形码符号体系

Image.find_barcodes() 返回的条目在 BarCode.type 中所报告的值。

image.EAN2: int

EAN-2 补充条形码。

image.EAN5: int

EAN-5 补充条形码。

image.EAN8: int

EAN-8 条形码。

image.UPCE: int

UPC-E 条形码。

image.ISBN10: int

ISBN-10 条形码。

image.UPCA: int

UPC-A 条形码。

image.EAN13: int

EAN-13 条形码。

image.ISBN13: int

ISBN-13 条形码。

image.I25: int

Interleaved 2-of-5 条形码。

image.DATABAR: int

GS1 DataBar 条形码。

image.DATABAR_EXP: int

GS1 DataBar Expanded 条形码。

image.CODABAR: int

Codabar 条形码。

image.CODE39: int

Code 39 条形码。

image.PDF417: int

PDF417 二维堆叠条形码。该常量为完整起见而存在,但条形码解码器目前并未实现 PDF417 —— Image.find_barcodes() 不会返回此类型的检测结果。

image.CODE93: int

Code 93 条形码。

image.CODE128: int

Code 128 条形码。