【雕爺學程式設計】MicroPython動手做(08)——零基礎學MaixPy之識別顏色

行者花雕發表於2020-06-07

早上用百度搜了一下“顏色識別”,多少有了一點大致的概念,還是老辦法,動手做,多實驗,往前走,還請各位老師多多指點。

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)

  

 

相關文章