【雕爷学编程】MicroPython动手做(08)——零基础学MaixPy之识别颜色

早上用百度搜了一下“颜色识别”,多少有了一点大致的概念,还是老办法,动手做,多实验,往前走,还请各位老师多多指点。

OpenCV(百度百科)
是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV用C++语言编写,它的主要接口也是C++语言,但是依然保留了大量的C语言接口。该库也有大量的Python、Java and MATLAB/OCTAVE(版本2.5)的接口。这些语言的API接口函数可以通过在线文档获得。如今也提供对于C#、Ch、Ruby,GO的支持。

OpenCV于1999年由Intel建立,如今由Willow Garage提供支持。OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV 拥有包括 500 多个C函数的跨平台的中、高层 API。它不依赖于其它的外部库——尽管也可以使用某些外部库。OpenCV 为Intel® Integrated Performance Primitives(IPP)提供了透明接口。这意味着如果有为特定处理器优化的 IPP 库,OpenCV 将在运行时自动加载这些库。 (注:OpenCV 2.0版的代码已显著优化,无需IPP来提升性能,故2.0版不再提供IPP接口)

 

OpenCV概述
其全称是Open source Computer Vision Library,开放源代码计算机视觉库。也就是说,它是一套关于计算机视觉的开放源代码的API函数库。这也就意味着:
(1)不管是科学研究,还是商业应用,都可以利用它来作开发;
(2)所有API函数的源代码都是公开的,你可以看到其内部实现的程序步骤;
(3)你可以修改OpenCV的源代码,编译生成你需要的特定API函数。但是,作为一个库,它所提供的,仅仅是一些常用的,经典的,大众化的算法的API。

一个典型的计算机视觉算法,应该包含以下一些步骤:
(1)数据获取(对OpenCV来说,就是图片);
(2)预处理;
(3)特征提取;
(4)特征选择;
(5)分类器设计与训练;
(6)分类判别;
而OpenCV对这六个部分,分别(记住这个词)提供了API。

基于OpenCV的颜色识别

彩色模型
数字图像处理中常用的采用模型是RGB(红,绿,蓝)模型和HSV(色调,饱和度,亮度),RGB广泛应用于彩色监视器和彩色视频摄像机,我们平时的图片一般都是RGB模型。而HSV模型更符合人描述和解释颜色的方式,HSV的彩色描述对人来说是自然且非常直观的。

HSV模型
HSV模型中颜色的参数分别是:色调(H:hue),饱和度(S:saturation),亮度(V:value)。由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。

色调(H:hue):用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
饱和度(S:saturation):取值范围为0.0~1.0,值越大,颜色越饱和。
亮度(V:value):取值范围为0(黑色)~255(白色)。

RGB转成HSV
设 (r, g, b) 分别是一个颜色的红、绿和蓝坐标,它们的值是在 0 到 1 之间的实数。设 max 等价于 r, g 和 b 中的最大者。设 min 等于这些值中的最小者。要找到在 HSV 空间中的 (h, s, v) 值,这里的 h ∈ [0, 360)是角度的色相角,而 s, v ∈ [0,1] 是饱和度和亮度。 OpenCV下有个函数可以直接将RGB模型转换为HSV模型,OpenCV中H∈ [0, 180), S ∈ [0, 255], V ∈ [0, 255]。我们知道H分量基本能表示一个物体的颜色,但是S和V的取值也要在一定范围内,因为S代表的是H所表示的那个颜色和白色的混合程度,也就说S越小,颜色越发白,也就是越浅;V代表的是H所表示的那个颜色和黑色的混合程度,也就说V越小,颜色越发黑。大致识别蓝色的取值是 H在100到140,S和V都在90到255之间。

 

OpenCV颜色识别思路

1、创建滑动条:用来调节阈值,识别出不同颜色。

2、颜色空间转换:将RGB转换为HSV模型,于是可以通过不同颜色的HSV的阈值不同来识别出该种颜色。Opencv中使用cvtcolor()可实现。一般彩色图像都是RGB颜色空间,而HSV色彩空间模型是一种在人们生活中甚至更常用的颜色系统,在电视遥控器上、在画画的调色板中、在看电视时调整亮度时都很常见,因为它更符合人们描述颜色的方式——是什么颜色、颜色有多深、颜色有多亮。需要注意的是,在opencv中,H、S、V值范围分别是[0,180),[0,255),[0,255),而非实际模型[0,360],[0,1],[0,1]。

3、直方图均衡化:由于光线的影响,手机读取的每一帧图片可能存在太亮或者太暗的问题,直方图均衡化可以将每个区间的像素点分布更均衡,使图像的层次感更强。Opencv中可以用equalizeHist()函数实现。直方图均衡化就是将原始的直方图拉伸,使之均匀分布在全部灰度范围内,从而增强图像的对比度。直方图均衡化的中心思想是把原始图像的的灰度直方图从比较集中的某个区域变成在全部灰度范围内的均匀分布

4、二值化:将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果。对灰度图像进行二值化处理,可以突出一定范围的信息。它是将像素点颜色值在所设定区间内(如a-b)的设定为255,在范围外的设为0.但是对于ab和的不同取值,二值化的效果会有很大的不同。

5、开操作:用来去除图像中的噪点,即干扰信息。Opencv中可以使用getStructuringElement()函数来进行相应设置。开操作是基于图像的膨胀和腐蚀而言的,膨胀就是对图像高亮部分进行“领域扩张”,效果图拥有比原图更大的高亮区域;腐蚀是原图中的高亮区域被蚕食,效果图拥有比原图更小的高亮区域。而开操作是对图像先腐蚀再膨胀,用来消除小物体。其数学原理是定义一个卷积核B,将其与目标图像进行卷积,就可以达到相应效果。不同形状和大小的核会出现不同的效果。

6、闭操作 :进行开操作之后可能会有一些断开的区域,闭操作可以将这些未联通的区域进行封闭,使图像更完整。闭操作是开操作的相反,先膨胀再腐蚀,用于排除小型黑洞,其原理与开操作相同。

 

手头正好有个魔方,有五种颜色,就拿它当识别颜色的实验道具了。

打开MaixPy IDE,选择工具——机器视觉——阕值编辑器

打开源图像位置,选择帧缓冲区

调整LAB阕值,主要是在二进制图像栏,白色像素是被跟踪的像素

彻底搞懂Lab 颜色空间

名称
在开始之前,先明确一下Lab颜色空间(Lab color space)的名字:
  • Lab的全称是CIELAB,有时候也写成CIE Lab*
  • 这里的CIE代表International Commission on Illumination(国际照明委员会),它是一个关于光照、颜色等的国际权威组织。
通道
Lab是由一个亮度通道(channel)和两个颜色通道组成的。在Lab颜色空间中,每个颜色用L、a、b三个数字表示,各个分量的含义是这样的:
  • L*代表亮度
  • a*代表从绿色到红色的分量
  • b*代表从蓝色到黄色的分量
Perceptual uniform
Lab是基于人对颜色的感觉来设计的,更具体地说,它是感知均匀(perceptual uniform)的。Perceptual uniform的意思是,如果数字(即前面提到的L、a、b这三个数)变化的幅度一样,那么它给人带来视觉上的变化幅度也差不多。Lab相较于RGB与CMYK等颜色空间更符合人类视觉,也更容易调整:想要调节亮度(不考虑Helmholtz–Kohlrausch effect,见下注)就调节L通道,想要调节只色彩平衡就分别调a和b。
注:Helmholtz–Kohlrausch effect是人眼的一种错觉——当色彩饱和度高时,颜色会看起来更亮。
设备无关
Lab有个很好的特性——设备无关(device-independent)。也就是说,在给定了颜色空间白点(white point)(下图中表示了一种颜色空间的白点)之后,这个颜色空间就能明确地确定各个颜色是如何被创建和显示的,与使用的显示介质没有关系。 需要注意的是,Lab定义的是相对于白点的颜色,只有定义完白点是什么颜色(比如定义为CIE standard illuminant D50),我们才能知道其他的颜色。
数值范围
理论上说,L、a、b*都是实数,不过实际一般限定在一个整数范围内:
  • L越大,亮度越高。L为0时代表黑色,为100时代表白色。
  • a和b为0时都代表灰色。
  • a*从负数变到正数,对应颜色从绿色变到红色。
  • b*从负数变到正数,对应颜色从蓝色变到黄色。
  • 我们在实际应用中常常将颜色通道的范围-100~+100或-128127之间。
可视化
可以看到,Lab*一共有三个分量,因此可以在三维空间中呈现。 在二维空间中,常用chromaticity diagram来可视化它,也就是固定亮度L,看a和b的变化。注意,这些可视化不是精确的,只是能帮助人理解。

LAB颜色模型

是根据Commission International Eclairage(CIE)在1931年所制定的一种测定颜色的国际标准建立的。于1976年被改进,并且命名的一种色彩模式。Lab颜色模型弥补了RGB和CMYK两种色彩模式的不足。它是一种设备无关的颜色模型,也是一种基于生理特征的颜色模型。 Lab颜色模型由三个要素组成,一个要素是亮度(L),a 和b是两个颜色通道。a包括的颜色是从深绿色(低亮度值)到灰色(中亮度值)再到亮粉红色(高亮度值);b是从亮蓝色(低亮度值)到灰色(中亮度值)再到黄色(高亮度值)。因此,这种颜色混合后将产生具有明亮效果的色彩。

Lab模式既不依赖光线,也不依赖于颜料,它是CIE组织确定的一个理论上包括了人眼可以看见的所有色彩的色彩模式。Lab模式弥补了RGB和CMYK两种色彩模式的不足。同RGB颜色空间相比,Lab是一种不常用的色彩空间。它是在1931年国际照明委员会(CIE)制定的颜色度量国际标准的基础上建立起来的。1976年,经修改后被正式命名为CIELab。它是一种设备无关的颜色系统,也是一种基于生理特征的颜色系统。这也就意味着,它是用数字化的方法来描述人的视觉感应。Lab颜色空间中的L分量用于表示像素的亮度,取值范围是[0,100],表示从纯黑到纯白;a表示从红色到绿色的范围,取值范围是[127,-128];b表示从黄色到蓝色的范围,取值范围是[127,-128]。下图所示为Lab颜色空间的图示;

Lab颜色空间比计算机显示器甚至比人类视觉的色域都要大  ,表示为Lab的位图比RGB或CMYK位图获得同样的精度需要要求更多的像素数据。Lab模式所定义的色彩最多,且与光线及设备无关并且处理速度与RGB模式同样快,比CMYK模式快很多。因此,可以放心大胆的在图象编辑中使用Lab模 式。而且,Lab模式在转换成CMYK模式时色彩没有丢失或被替换。因此,最佳避免色彩损失的方法是:应用Lab模式编辑图象,再转换为CMYK模式打印 输出。

 

#MicroPython动手做(08)——零基础学MaixPy之识别颜色

#实验程序之一:find red blob 动态识别红色块

 

尝试选择最佳的颜色跟踪阙值,通过滑动条来调节阈值,在二进制图像上红色块高亮(显示白色)。

实测得出的LAB值为:55, 70, 42, 65, 52, 8

 

#MicroPython动手做(08)——零基础学MaixPy之识别颜色
#实验程序之一:find red blob 动态识别红色块

#MicroPython动手做(08)——零基础学MaixPy之识别颜色

#实验程序:find red blob 动态识别红色块

 

import sensor

import image

import lcd

import time

 

lcd.init(freq=15000000)

sensor.reset()

sensor.set_pixformat(sensor.RGB565)

sensor.set_framesize(sensor.QVGA)

sensor.run(1)

red_threshold  = (55, 70, 42, 65, 52, 8) 

while True:

    img=sensor.snapshot()

    blobs = img.find_blobs([green_threshold])

    if blobs:    

        for b in blobs:

            tmp=img.draw_rectangle(b[0:4]) 

            tmp=img.draw_cross(b[5], b[6]) 

            c=img.get_pixel(b[5], b[6])

    lcd.display(img)

  

做实验的魔方,有5种颜色

运行后可看到框圈和+号,已能准确识别

阴天里窗户前的实验场景

#MicroPython动手做(08)——零基础学MaixPy之识别颜色

#实验程序之二:find green blob 动态识别绿色块

 

获取绿色的LAB阙值为 0, 88, -42, -6, -9, 13

#MicroPython动手做(08)——零基础学MaixPy之识别颜色

#实验程序之二:find green blob 动态识别绿色块

 

import sensor

import image

import lcd

import time

 

lcd.init(freq=15000000)

sensor.reset()

sensor.set_pixformat(sensor.RGB565)

sensor.set_framesize(sensor.QVGA)

sensor.run(1)

green_threshold  = (0, 88, -42, -6, -9, 13) 

while True:

    img=sensor.snapshot()

    blobs = img.find_blobs([green_threshold])

    if blobs:    

        for b in blobs:

            tmp=img.draw_rectangle(b[0:4]) 

            tmp=img.draw_cross(b[5], b[6]) 

            c=img.get_pixel(b[5], b[6])

    lcd.display(img)

  

#MicroPython动手做(08)——零基础学MaixPy之识别颜色
#实验程序之三:find orange blob 动态识别橙色块

获取橙色的LAB阙值为 0, 80, 66, -20, 80, 50(与红色有交集)

#MicroPython动手做(08)——零基础学MaixPy之识别颜色

#实验程序之三:find orange blob 动态识别橙色块

 

import sensor

import image

import lcd

import time

 

lcd.init(freq=15000000)

 

sensor.reset()

sensor.set_pixformat(sensor.RGB565)

sensor.set_framesize(sensor.QVGA)

sensor.run(1)

 

orange_threshold  = (0, 80, 66, -20, 80, 50)

 

while True:

    img=sensor.snapshot()

    blobs = img.find_blobs([orange_threshold])

    if blobs:

        for b in blobs:

            tmp=img.draw_rectangle(b[0:4])

            tmp=img.draw_cross(b[5], b[6])

            c=img.get_pixel(b[5], b[6])

 

    lcd.display(img)

  

蓝色的LAB阙值为 0, 80, -128, 35, -128, -18

黄色的LAB阙值为 88, 95, 0, -44, 93, 48

说明:
本实验案例以一只普通魔方的色彩为准(阴天光线),得出的实验数据(LAB阙值)仅供参考

 

蓝色 (0, 80, -128, 35, -128, -18)
红色 (55, 70, 42, 65, 52, 8)  
绿色 (0, 88, -42, -6, -9, 13) 
橙色 (0, 80, 66, -20, 80, 50)  
黄色 (88, 95, 0, -44, 93, 48)

#MicroPython动手做(08)——零基础学MaixPy之识别颜色

#实验程序之四:识别图片上的红心和花心部分

 

打开MaixPy IDE,选择工具——机器视觉——阕值编辑器——源图像位置——图像文件(识别电脑上的图片)

 

细心调整六个滑动条的数值,参考结果见下图二进制图像

识别红心和花心的LAB阙值为 (0, 80, 90, 24, 75, -10)

#MicroPython动手做(08)——零基础学MaixPy之识别颜色

#实验程序之四:识别图片上的红心和花心部分

 

import sensor

import image

import lcd

import time

 

lcd.init(freq=15000000)

 

sensor.reset()

sensor.set_pixformat(sensor.RGB565)

sensor.set_framesize(sensor.QVGA)

sensor.run(1)

 

Five_threshold  = (0, 80, 90, 24, 75, -10)

 

while True:

    img=sensor.snapshot()

    blobs = img.find_blobs([Five_threshold])

    if blobs:

        for b in blobs:

            tmp=img.draw_rectangle(b[0:4])

            tmp=img.draw_cross(b[5], b[6])

            c=img.get_pixel(b[5], b[6])

 

    lcd.display(img)