前言
作者在第一部分向大家介紹了圖像處理的基礎(chǔ)知識(shí),第二部分介紹了圖像運(yùn)算和圖像增強(qiáng),接下來(lái)第三部分我們將詳細(xì)講解圖像分割及圖像處理經(jīng)典案例,該部分屬于高階圖像處理知識(shí),能進(jìn)一步加深我們的理解和實(shí)踐能力。圖像分割是將圖像分成若干具有獨(dú)特性質(zhì)的區(qū)域并提取感興趣目標(biāo)的技術(shù)和過(guò)程,它是圖像處理和圖像分析的關(guān)鍵步驟。主要分為基于閾值的分割方法、基于區(qū)域的分割方法、基于邊緣的分割方法和基于特定理論的分割方法。這篇文章將詳細(xì)講解基于顏色的圖像分割方法。
一、基于顏色的圖像分割
顏色分割是圖像處理中的一種重要技術(shù),它可以將圖像中的不同顏色分割出來(lái),用于目標(biāo)檢測(cè)、圖像識(shí)別等應(yīng)用場(chǎng)景。
顏色分割的算法原理比較簡(jiǎn)單,它通?;陬伾臻g的變換來(lái)實(shí)現(xiàn)。常用的顏色空間有RGB、HSV、LAB等,其中HSV顏色空間比較適合顏色分割任務(wù)。HSV顏色空間將顏色分成三個(gè)通道:色調(diào)(Hue)、飽和度(Saturation)和亮度(Value)。
- 色調(diào):表示顏色的種類或類型,例如紅色、藍(lán)色、綠色等。
- 飽和度:表示顏色的純度,越飽和的顏色越鮮艷,反之亦然。
- 亮度:指顏色的明暗程度。在顏色中,亮度越高,顏色就越明亮;亮度越低,顏色就越暗淡。
顏色分割的基本思路是通過(guò)閾值來(lái)分割不同顏色的像素。具體地,我們可以將圖像從RGB顏色空間轉(zhuǎn)換到HSV顏色空間,然后選擇合適的閾值(通常是色調(diào)、飽和度、亮度的最大值最小值),將圖像分成黑白兩部分。
在opencv hsv顏色空間中
-
色調(diào)(Hue)的最大值是179度,最小值是0度,代表了顏色在色輪上的位置。
-
飽和度(Saturation)的最大值是255,最小值是0,代表了顏色的純度和灰度。
-
亮度(Brightness)的最大值是255,最小值是0,代表了顏色的明暗程度。
實(shí)現(xiàn)步驟
基于上述算法原理,我們可以進(jìn)行如下步驟來(lái)實(shí)現(xiàn)顏色分割:
- 將圖像從RGB顏色空間轉(zhuǎn)換到HSV顏色空間。
- 分別計(jì)算色調(diào)、飽和度、亮度的最大值和最小值
- 設(shè)置閾值,將圖像分割成黑白兩部分。
- 使用形態(tài)學(xué)操作去除噪點(diǎn),得到最終的分割結(jié)果。
本文利用OpenCV中的cv2.inRange()函數(shù),對(duì)圖像中目標(biāo)進(jìn)行基于顏色的分割。
mask = cv2.inRange(src, lowerb, upperb[, dst])
— src 參數(shù)是輸入圖像,可以是單通道或多通道的,數(shù)據(jù)類型為 np.uint8
— mask是輸出圖像,為單通道圖像(二值圖像),數(shù)據(jù)類型和輸入圖像相同
—lowerb 是指定的下限,類型為 Scalar,可以是單個(gè)值或者一個(gè)包含多個(gè)值的元組或列表
—upperb 是指定的上限,類型為 Scalar,可以是單個(gè)值或者一個(gè)包含多個(gè)值的元組或列表
注:
mask代表了與指定顏色范圍匹配的像素點(diǎn)的位置信息,即在指定顏色范圍內(nèi)的像素點(diǎn)在二值圖像中對(duì)應(yīng)的像素值為255,不在指定顏色范圍內(nèi)的像素點(diǎn)在二值圖像中對(duì)應(yīng)的像素值為0。因此,通過(guò)使用這個(gè)掩膜,我們可以選擇性地對(duì)圖像進(jìn)行操作,只對(duì)指定顏色范圍內(nèi)的像素點(diǎn)進(jìn)行處理,而不影響其他像素點(diǎn)
下面是基于上述算法原理實(shí)現(xiàn)簡(jiǎn)單的顏色分割代碼(掩碼自己給定范圍):
import cv2
import numpy as np
# 讀入圖片
img = cv2.imread( "C:/Users/Administrator/Desktop/flower.png")
# 轉(zhuǎn)換顏色空間
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 定義綠色范圍
lower_green = np.array([40, 50, 50])
upper_green = np.array([90, 255, 255])
# 定義黃色范圍
lower_yellow = np.array([15, 50, 50])
upper_yellow = np.array([40, 255, 255])
# 根據(jù)顏色范圍創(chuàng)建掩碼
mask_green = cv2.inRange(hsv, lower_green, upper_green)
mask_yellow = cv2.inRange(hsv, lower_yellow, upper_yellow)
# 合并掩碼
mask = cv2.bitwise_or(mask_green, mask_yellow)
# 應(yīng)用掩碼
result = cv2.bitwise_and(img, img, mask=mask)
# 顯示結(jié)果
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
運(yùn)行結(jié)果如圖1-1所示,圖中較好的分割出了向日葵,但草地部分也被分割了出來(lái)
以下是一些常見(jiàn)顏色的HSV大致范圍:
紅色:(0, 70, 50) - (10, 255, 255) 或者 (156, 70, 50) - (179, 255, 255)
橙色:(10, 70, 50) - (25, 255, 255)
黃色:(25, 70, 50) - (35, 255, 255)
綠色:(35, 70, 50) - (85, 255, 255)
青色:(85, 70, 50) - (100, 255, 255)
藍(lán)色:(100, 70, 50) - (130, 255, 255)
紫色:(130, 70, 50) - (170, 255, 255)
黑色: (0, 0, 0) - (180, 255, 46)
白色:(0, 0, 221) - (180, 30, 255)
灰色:(0,0,46) - (180,43,220)
二、通過(guò)觀察直方圖確定顏色取值范圍
當(dāng)要分割的顏色目標(biāo)在圖像中無(wú)較大干擾時(shí),可以通過(guò)觀察色調(diào)(Hue)分量的直方圖來(lái)確定顏色目標(biāo)的取值范圍,以作為我們分割的界限標(biāo)準(zhǔn)。
代碼示例如下:
import cv2
import numpy as np
from matplotlib import pyplot as plt
#通過(guò)OpenCV讀取圖片信息
img = cv2.imread("C:/Users/Administrator/Desktop/scenery.jpg")
# BGR圖轉(zhuǎn)為HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 提取hsv中H通道數(shù)據(jù)
h = hsv[:, :, 0].ravel()
# 直方圖顯示
plt.hist(h, 180, [0, 180])
plt.show()
得到直方圖,如圖2-1所示:
根據(jù)上訴所說(shuō)的常見(jiàn)顏色的HSV范圍,直方圖中30到70部分出現(xiàn)了大量數(shù)據(jù),由此可以確定綠色的H分量上下限為30-70,SV的界限可以根據(jù)上訴所提的HSV范圍先大致設(shè)置,具體可以在提取掩模的時(shí)候調(diào)整確定
下面通過(guò)HSV的綠色界限生成mask掩模。代碼如下:
import cv2
import numpy as np
from matplotlib import pyplot as plt
#通過(guò)OpenCV讀取圖片信息
img = cv2.imread("C:/Users/Administrator/Desktop/scenery.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# HSV 的下界限
lower_red = np.array([35,70,50])
# HSV 的上界限
upper_red = np.array([70,255,255])
# 通過(guò)上下限提取范圍內(nèi)的掩模mask
mask = cv2.inRange(hsv, lower_red, upper_red)
img = cv2.resize(img,(500,500))
mask = cv2.resize(mask,(500,500))
cv2.imshow("img", img)
cv2.imshow("mask", mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
運(yùn)行結(jié)果如圖2-2所示
可以發(fā)現(xiàn),草地的大體輪廓已被提取出來(lái),但在場(chǎng)地上存在許多黑點(diǎn),這是因?yàn)榇蟛糠趾邳c(diǎn)處于暗處,我們可以通過(guò)降低V值的下限來(lái)濾除掉,在這里V值下限由原來(lái)的50調(diào)整為15
效果如下:
此時(shí)有些黑點(diǎn)已經(jīng)無(wú)法通過(guò)V的調(diào)整來(lái)去除了,我們可以采用膨脹、腐蝕等手段來(lái)消除獨(dú)立的白點(diǎn)或黑點(diǎn)。
消除黑點(diǎn)代碼如下:
import cv2
import numpy as np
from matplotlib import pyplot as plt
#通過(guò)OpenCV讀取圖片信息
img = cv2.imread("C:/Users/Administrator/Desktop/scenery.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# HSV 的下界限
lower_green = np.array([35,70,15])
# HSV 的上界限
upper_green = np.array([70,255,255])
# 通過(guò)上下限提取范圍內(nèi)的掩模mask
mask = cv2.inRange(hsv, lower_green, upper_green)
# 定義結(jié)構(gòu)元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 35))
# 圖像閉運(yùn)算
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2)
img = cv2.resize(img,(500,500))
mask = cv2.resize(mask,(500,500))
cv2.imshow("img", img)
cv2.imshow("mask", mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果如圖2-3所示
可以看到黑色的點(diǎn)被消除了,然后我們?cè)偈褂胏v2.bitwise_and()把原圖與mask進(jìn)行位與摳出草地的圖片:
顏色替換
通過(guò)上面的操作我們已經(jīng)可以準(zhǔn)確的分割出我們指定的顏色了,在次基礎(chǔ)上就可以對(duì)他的顏色進(jìn)行更改了,比如改成黃色,這個(gè)同樣也是要在HSV顏色空間操作的,不過(guò)這次就不需要對(duì)mask進(jìn)行閉運(yùn)算了。
在這里使用createTrackbar函數(shù)對(duì)hsv進(jìn)行進(jìn)行調(diào)整
cv2.createTrackbar(trackbarName, windowName, value, count, onChange)
- trackbarName:可拖動(dòng)條的名稱,字符串類型。
- windowName:可拖動(dòng)條所在的窗口名稱,字符串類型。
- value:可拖動(dòng)條的默認(rèn)值,整型。
- count:可拖動(dòng)條的最大值,整型。
- onChange:當(dāng)可拖動(dòng)條的值發(fā)生變化時(shí)調(diào)用的回調(diào)函數(shù),函數(shù)類型。
代碼如下:
import cv2
import numpy as np
def nothing(x):
pass
#通過(guò)OpenCV讀取圖片信息
img = cv2.imread("C:/Users/Administrator/Desktop/scenery.jpg")
img = cv2.resize(img,(500,500))
cv2.namedWindow('img',cv2.WINDOW_NORMAL)
cv2.imshow("img", img)
# HSV 的下界限
lower_green = np.array([35,70,15])
# HSV 的上界限
upper_green = np.array([70,255,255])
cv2.namedWindow('img2',cv2.WINDOW_NORMAL)
cv2.createTrackbar('H','img2',140,180,nothing)
cv2.createTrackbar('S','img2',100,180,nothing)
cv2.createTrackbar('V','img2',117,180,nothing)
rows,cols,channels = img.shape
while(1):
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_green, upper_green)
#將制定像素點(diǎn)的數(shù)據(jù)設(shè)置為0, 要注意的是這三個(gè)參數(shù)對(duì)應(yīng)的值是Blue, Green, Red。
h = cv2.getTrackbarPos('H', 'img2')
s = cv2.getTrackbarPos('S', 'img2')
v = cv2.getTrackbarPos('V', 'img2')
for r in range(rows):
for c in range(cols):
if mask[r, c] == 255:
hsv.itemset((r, c, 0), hsv.item(r, c, 0) -h)
hsv.itemset((r, c, 1), hsv.item(r, c, 1) +90-s)
hsv.itemset((r, c, 2), hsv.item(r, c, 2) +90-v)
img2 = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
#將圖像進(jìn)行輸出,使用show()也是可以顯示的。
img = cv2.resize(img, (500, 500))
cv2.imshow("img2", img2)
k = cv2.waitKey(1)&0xFF
if k == 27: #esc exit
break
#cv2.waitKey(0)
cv2.destroyAllWindows()
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-509993.html
三、總結(jié)
本篇博客介紹了如何使用Python與OpenCV進(jìn)行顏色分割,其中使用了HSV顏色空間和閾值分割的算法。實(shí)現(xiàn)顏色分割的步驟包括:讀取圖像文件、轉(zhuǎn)換顏色空間、計(jì)算閾值、分割圖像、去除噪點(diǎn)等。通過(guò)實(shí)例的代碼,我們可以更加深入地了解顏色分割的實(shí)現(xiàn)過(guò)程。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-509993.html
到了這里,關(guān)于python 圖像處理——圖像分割及經(jīng)典案例篇之基于顏色的圖像分割的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!