人若无名 便可潜心练剑.|

hazy1k

园龄:7个月粉丝:13关注:0

2025-02-21 12:31阅读: 3评论: 0推荐: 0

第18章 颜色识别

第十八章 颜色识别

1. RGB与LAB

LAB是一种基于人眼感知设计的颜色表示方式,由三个通道组成:

  • L通道:表示亮度,范围从黑到白,0表示黑,100表示白。
  • A通道:表示从绿色到红色的颜色范围,范围是-128到127。负值靠近绿色,正值靠近红色。
  • B通道:表示从蓝色到黄色的颜色范围,范围是-128到127,负值靠近蓝色,正值靠近黄色。

相比RGB色彩空间,LAB色彩空间将“亮度”和“颜色”完全分离,更适合颜色分析和处理。

RGB虽然是摄像头捕获图像的默认格式,但在颜色识别中存在以下问题:

  • 光照敏感 :RGB值会因光照强度的变化而波动,同一颜色在强光或弱光下的RGB值会有显著差异。
  • 颜色混叠 :RGB将亮度和颜色信息混合在一起,不容易单独分析颜色。
  • 非直观性 :人眼感知的颜色与RGB值的关系并不直观,例如浅红和深红的RGB值相差较大,但肉眼看起来很接近,在LAB色彩空间中它们的A通道值会更接近。

但是LAB色彩空间克服了这些问题,他有以下优点:

  • 光照鲁棒性:颜色(A和B通道)与亮度(L通道)分离,可以忽略光照的影响,只专注于颜色本身。
  • 能直观的进行颜色描述:A通道和B通道直接描述颜色范围,更接近人眼对颜色的感知。
  • 更大色域:LAB的色域比RGB更大,可以表示更多的颜色,识别效果更精准。

2. find_blobs(寻找图像中的色块)

image.find_blobs(thresholds[, invert=False[, roi[, x_stride=2[, y_stride=1[, area_threshold=10[, pixels_threshold=10[, merge=False[, margin=0[, threshold_cb=None[, merge_cb=None]]]]]]]]]])

参数 thresholds 必须为元组列表,形式为 [(lo, hi), (lo, hi), ...],用于定义需要追踪的颜色范围。

  • 对于灰度图像,每个元组应包含两个值:最小灰度值和最大灰度值。函数将仅考虑落在这些阈值之间的像素区域。

  • 对于 RGB565 图像(彩色图像),每个元组需要包含六个值 (l_lo, l_hi, a_lo, a_hi, b_lo, b_hi),分别对应 LAB 色彩空间中的 L、A 和 B 通道的最小和最大值。该函数会自动纠正最小值和最大值的交换情况。如果元组包含超过六个值,则其余值将被忽略;若元组不足,则假定缺失的阈值为最大范围。

  • invert 参数用于反转阈值操作,使得仅在已知颜色范围之外的像素被匹配。

  • roi 参数为感兴趣区域的矩形元组 (x, y, w, h)。若未指定,ROI 将默认为整个图像的矩形。操作仅限于该区域内的像素。

  • x_stride 为查找色块时需要跳过的 x 像素数量。在找到色块后,直线填充算法将精确处理该区域。如果已知色块较大,可以增加 x_stride 以提高查找速度。

  • y_stride 为查找色块时需要跳过的 y 像素数量。在找到色块后,直线填充算法将精确处理该区域。如果已知色块较大,可以增加 y_stride 以提高查找速度。

  • area_threshold 用于过滤掉边界框区域小于此值的色块。

  • pixels_threshold 用于过滤掉像素数量少于此值的色块。

  • merge 若为 True,则合并所有未被过滤的色块,这些色块的边界矩形互相重叠。margin 可用于在合并测试中增大或减小色块边界矩形的大小。例如,边缘为 1 的两个重叠色块将被合并。

合并色块可实现颜色代码的追踪。每个色块对象具有一个 code 值,该值为一个位向量。例如,若在 image.find_blobs 中输入两个颜色阈值,则第一个阈值对应的代码为 1,第二个为 2(第三个代码为 4,第四个代码为 8,以此类推)。合并色块时,所有的 code 通过逻辑或运算进行合并,以指示产生它们的颜色。这使得同时追踪两种颜色成为可能,若两个颜色得到同一个色块对象,则可能对应于某一种颜色代码。

在使用严格的颜色范围时,可能无法完全追踪目标对象的所有像素,此时可考虑合并色块。若希望合并色块但不希望不同阈值的色块被合并,可以分别调用两次 image.find_blobs

  • threshold_cb 可设置为在每个色块经过阈值筛选后调用的回调函数,以从即将合并的色块列表中过滤出特定色块。回调函数将接收一个参数:待筛选的色块对象。若希望保留色块,回调函数应返回 True,否则返回 False
  • merge_cb 可设置为在两个即将合并的色块间调用的回调函数,以控制合并的批准或禁止。回调函数将接收两个参数,即两个待合并的色块对象。若希望合并色块,应返回 True,否则返回 False

注意: 此功能不支持压缩图像和 Bayer 图像。

3. 寻找特定颜色色块

import time, os, sys
from media.sensor import *
from media.display import *
from media.media import *

sensor_id = 2
sensor = None
# 处理尺寸
picture_width = 400
picture_height = 240

DISPLAY_MODE = "LCD"

# 根据模式设置显示宽高
if DISPLAY_MODE == "VIRT":
    # 虚拟显示器模式
    DISPLAY_WIDTH = ALIGN_UP(1920, 16)
    DISPLAY_HEIGHT = 1080
elif DISPLAY_MODE == "LCD":
    # 3.1寸屏幕模式
    DISPLAY_WIDTH = 800
    DISPLAY_HEIGHT = 480
elif DISPLAY_MODE == "HDMI":
    # HDMI扩展板模式
    DISPLAY_WIDTH = 1920
    DISPLAY_HEIGHT = 1080
else:
    raise ValueError("未知的 DISPLAY_MODE,请选择 'VIRT', 'LCD' 或 'HDMI'")

try:
    sensor = Sensor(id=sensor_id,width=1920, height=1080)
    sensor.reset()

    sensor.set_framesize(width=picture_width, height=picture_height, chn=CAM_CHN_ID_0)
    sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_0)

    # 根据模式初始化显示器
    if DISPLAY_MODE == "VIRT":
        Display.init(Display.VIRT, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, fps=60)
    elif DISPLAY_MODE == "LCD":
        Display.init(Display.ST7701, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)
    elif DISPLAY_MODE == "HDMI":
        Display.init(Display.LT9611, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)

    MediaManager.init()
    sensor.run()

    # 颜色阈值[min_L, max_L, min_A, max_A, min_B, max_B]
    color_threshold = [(0, 79, 31, 67, 26, 60)]
    while True:
        os.exitpoint()
        # 捕获通道0的图像
        img = sensor.snapshot(chn=CAM_CHN_ID_0)
        # 寻找特定的颜色阈值
        blobs = img.find_blobs(color_threshold, area_threshold=2000)

        if blobs:
            for blob in blobs:
                # 画出矩形框
                img.draw_rectangle(blob[0:4])
                img.draw_cross(blob[5], blob[6])
                print("Blo Center: X={}, Y={}".format(blob[5], blob[6]))

        # 显示捕获到的图像
        Display.show_image(img)

except KeyboardInterrupt as e:
    print("用户停止: ", e)
except BaseException as e:
    print(f"异常: {e}")
finally:
    if isinstance(sensor, Sensor):
        sensor.stop()
    # 反初始化显示模块
    Display.deinit()
    os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
    time.sleep_ms(100)
    MediaManager.deinit()

4. 阈值调节

首先运行一个能够在帧缓冲区显示图像的程序,将庐山派的摄像头对准你需要调节颜色阈值的对象,然后点击帧缓冲区右上角的【禁用】,先把图像固定,方便后续步骤。 位置如下图所示

单击CanMV IDE K230上方菜单栏中的【工具】->【机器视觉】->【阈值编辑器】

在新弹出来的对话框中单击【帧缓冲区】,设定图像来源为帧缓冲区。

弹出来的框就是阈值编辑器,在下面的六个通道中来回拖动选定,需要注意的是左边是原图像,右边图像中展示为白色的就是我们要跟踪的图像。

首先需要确定你需要提取的颜色阈值范围,我这里选定的是图中的红色,也就是左边图像中从上往下数的第三个方块。上图中的阈值范围是我已经调节好的,我们如果要寻找红色,其实就是让右边这个二进制图像中显示白色的位置和左边的源图像中的红色位置是一致的。

在调节的过程中,要实时观察右边的二进制图像。从默认的LAB值范围开始,逐步缩小或扩大值的范围,直到目标区域完全呈现为白色,背景为黑色。然后记录最下面的LAB阈值,在这里是(0, 79, 31, 67, 26, 60),就是当前环境下我的屏幕上红色的阈值。具体调节的效果可以看下面这个动图:

本文作者:hazy1k

本文链接:https://www.cnblogs.com/hazy1k/p/18729011

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hazy1k  阅读(3)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起