溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

基于OpenCV的圖像分割是怎樣的

發(fā)布時(shí)間:2021-12-15 18:24:12 來(lái)源:億速云 閱讀:174 作者:柒染 欄目:大數(shù)據(jù)

基于OpenCV的圖像分割是怎樣的,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

數(shù)據(jù)科學(xué)家和醫(yī)學(xué)研究人員可以將這種方法作為模板,用于更加復(fù)雜的圖像的數(shù)據(jù)集(如天文數(shù)據(jù)),甚至一些非圖像數(shù)據(jù)集中。由于圖像在計(jì)算機(jī)中表示為矩陣,我們有一個(gè)專(zhuān)門(mén)的排序數(shù)據(jù)集作為基礎(chǔ)。在整個(gè)處理過(guò)程中,我們將使用 Python 包,以及OpenCV、scikit 圖像等幾種工具。除此之外,我們還將使用 numpy ,以確保內(nèi)存中的值一致存儲(chǔ)。

主要內(nèi)容

去噪

為了消除噪聲,我們使用簡(jiǎn)單的中位數(shù)濾波器來(lái)移除異常值,但也可以使用一些不同的噪聲去除方法或偽影去除方法。這項(xiàng)工件由采集系統(tǒng)決定(顯微鏡技術(shù)),可能需要復(fù)雜的算法來(lái)恢復(fù)丟失的數(shù)據(jù)。工件通常分為兩類(lèi):

1. 模糊或焦點(diǎn)外區(qū)域

2. 不平衡的前景和背景(使用直方圖修改正確)

分割

對(duì)于本文,我們使用Otsu 的方法分割,使用中位數(shù)濾波器平滑圖像后,然后驗(yàn)證結(jié)果。只要分段結(jié)果是二進(jìn)制的,就可以對(duì)任何分段算法使用相同的驗(yàn)證方法。這些算法包括但不限于考慮不同顏色空間的各種循環(huán)閾值方法。

一些示例包括:

1. 李閾值

2. 依賴(lài)于局部強(qiáng)度的自適應(yīng)閾值方法

3. 在生物醫(yī)學(xué)圖像分割中常用的Unet等深度學(xué)習(xí)算法

4. 在語(yǔ)義上對(duì)圖像進(jìn)行分段的深度學(xué)習(xí)方法

驗(yàn)證

我們從已手動(dòng)分割的基礎(chǔ)數(shù)據(jù)集開(kāi)始。為了量化分段算法的性能,我們將真實(shí)數(shù)據(jù)與預(yù)測(cè)數(shù)據(jù)的二進(jìn)制分段進(jìn)行比較,同時(shí)顯示準(zhǔn)確性和更有效的指標(biāo)。盡管真陽(yáng)性 (TP) 或假陰性 (FN) 數(shù)量較低,但精度可能異常高。在這種情況下,F(xiàn)1 分?jǐn)?shù)和 MCC是二進(jìn)制分類(lèi)的更好量化指標(biāo)。稍后我們將詳細(xì)介紹這些指標(biāo)的優(yōu)缺點(diǎn)。

為了定性驗(yàn)證,我們疊加混淆矩陣結(jié)果,即真正的正極、真負(fù)數(shù)、假陽(yáng)性、假負(fù)數(shù)像素正好在灰度圖像上。此驗(yàn)證也可以應(yīng)用于二進(jìn)制圖像分割結(jié)果上的顏色圖像,盡管本文中使用的數(shù)據(jù)是灰度圖像。最后,我們將介紹整個(gè)實(shí)現(xiàn)過(guò)程?,F(xiàn)在,讓我們看看數(shù)據(jù)和用于處理這些數(shù)據(jù)的工具。

Loading and visualizing data

我們將使用以下模塊加載、可視化和轉(zhuǎn)換數(shù)據(jù)。這些對(duì)于圖像處理和計(jì)算機(jī)視覺(jué)算法非常有用,具有簡(jiǎn)單而復(fù)雜的數(shù)組數(shù)學(xué)。如果單獨(dú)安裝,括號(hào)中的模塊名稱(chēng)會(huì)有所幫助。

基于OpenCV的圖像分割是怎樣的

如果在運(yùn)行示例代碼中,遇到 matplotlib 后端的問(wèn)題,請(qǐng)通過(guò)刪除 plt.ion() 調(diào)用來(lái)禁用交互式模式,或是通過(guò)取消注釋示例代碼中的建議調(diào)用來(lái)在每個(gè)部分的末尾調(diào)用 plt.show()。"Agg"或"TkAgg"將作為圖像顯示的后端。繪圖將顯示在文章中。

代碼導(dǎo)入

import cv2 import matplotlib.pyplot as plt import numpy as np import scipy.misc import scipy.ndimage import skimage.filters import sklearn.metrics # Turn on interactive mode. Turn off with plt.ioff() plt.ion()

在本節(jié)中,我們將加載可視化數(shù)據(jù)。數(shù)據(jù)是小老鼠腦組織與印度墨水染色的圖像,由顯微鏡(KESM)生成。此 512 x 512 圖像是一個(gè)子集,稱(chēng)為圖塊。完整的數(shù)據(jù)集為 17480 x 8026 像素,深度為 799,大小為 10gb。因此,我們將編寫(xiě)算法來(lái)處理大小為 512 x 512 的圖塊,該圖塊只有 150 KB。

各個(gè)圖塊可以映射為在多處理/多線(xiàn)程(即分布式基礎(chǔ)結(jié)構(gòu))上運(yùn)行,然后再縫合在一起即獲得完整的分段圖像。我們不介紹具體的縫合方法。簡(jiǎn)而言之,拼接涉及對(duì)整個(gè)矩陣的索引并根據(jù)該索引將圖塊重新組合。可以使用map-reduce進(jìn)行,Map-Reduce的指標(biāo)例如所有圖塊的所有F1分?jǐn)?shù)之和等。我們只需將結(jié)果添加到列表中,然后執(zhí)行統(tǒng)計(jì)摘要即可。

左側(cè)的黑色橢圓形結(jié)構(gòu)是血管,其余的是組織。因此,此數(shù)據(jù)集中的兩個(gè)類(lèi)是:

? 前景(船只)—標(biāo)記為255

? 背景(組織)—標(biāo)記為0

右下方的最后一個(gè)圖像是真實(shí)圖像。通過(guò)繪制輪廓并填充輪廓以手動(dòng)方式對(duì)其進(jìn)行追蹤,通過(guò)病理學(xué)家獲得真實(shí)情況。我們可以使用專(zhuān)家提供的類(lèi)似示例來(lái)訓(xùn)練深度學(xué)習(xí)網(wǎng)絡(luò),并進(jìn)行大規(guī)模驗(yàn)證。我們還可以通過(guò)將這些示例提供給其他平臺(tái)并讓他們以更大的比例手動(dòng)跟蹤一組不同的圖像以進(jìn)行驗(yàn)證和培訓(xùn)來(lái)擴(kuò)充數(shù)據(jù)。

grayscale = scipy.misc.imread('grayscale.png')grayscale = 255 - grayscalegroundtruth = scipy.misc.imread('groundtruth.png')plt.subplot(1, 3, 1)plt.imshow(255 - grayscale, cmap='gray')plt.title('grayscale')plt.axis('off')plt.subplot(1, 3, 2)plt.imshow(grayscale, cmap='gray')plt.title('inverted grayscale')plt.axis('off')plt.subplot(1, 3, 3)plt.imshow(groundtruth, cmap='gray')plt.title('groundtruth binary')plt.axis('off')

基于OpenCV的圖像分割是怎樣的

前處理

在分割數(shù)據(jù)之前,我們應(yīng)該檢查一下數(shù)據(jù)集,以確定是否存在由于成像系統(tǒng)而造成了偽影。在此示例中,我們僅討論一個(gè)圖像。通過(guò)查看圖像,我們可以看到?jīng)]有任何明顯的偽影會(huì)干擾分割。但是,小伙伴們可以使用中值濾鏡消除離群值噪聲并平滑圖像。中值過(guò)濾器用中值(在給定大小的內(nèi)核內(nèi))替換離群值。

內(nèi)核大小3的中值過(guò)濾器

median_filtered = scipy.ndimage.median_filter(grayscale, size=3) plt.imshow(median_filtered, cmap='gray') plt.axis('off') plt.title("median filtered image")

基于OpenCV的圖像分割是怎樣的

要確定哪種閾值技術(shù)最適合分割,我們可以先通過(guò)閾值確定是否存在將這兩個(gè)類(lèi)別分開(kāi)的獨(dú)特像素強(qiáng)度。在這種情況下,可以使用通過(guò)目視檢查獲得的強(qiáng)度對(duì)圖像進(jìn)行二值化處理。我們使用的圖像許多像素的強(qiáng)度小于50,這些像素與反轉(zhuǎn)灰度圖像中的背景類(lèi)別相對(duì)應(yīng)。

盡管類(lèi)別的分布不是雙峰的,但仍然在前景和背景之間有所區(qū)別,在該區(qū)域中,較低強(qiáng)度的像素達(dá)到峰值,然后到達(dá)谷底。可以通過(guò)各種閾值技術(shù)獲得該精確值。分割部分將詳細(xì)研究一種這樣的方法。

可視化像素強(qiáng)度的直方圖

counts, vals = np.histogram(grayscale, bins=range(2 ** 8)) plt.plot(range(0, (2 ** 8) - 1), counts) plt.title("Grayscale image histogram") plt.xlabel("Pixel intensity") plt.ylabel("Count")

基于OpenCV的圖像分割是怎樣的

基于OpenCV的圖像分割是怎樣的

分割

去除噪聲后,我們可以用skimage濾波器模塊對(duì)所有閾值的結(jié)果進(jìn)行比較,來(lái)確定所需要使用的像素。有時(shí),在圖像中,其像素強(qiáng)度的直方圖不是雙峰的。因此,可能會(huì)有另一種閾值方法可以比基于閾值形狀在內(nèi)核形狀中進(jìn)行閾值化的自適應(yīng)閾值方法更好。Skimage中的函數(shù)可以方便看到不同閾值的處理結(jié)果。

嘗試所有閾值

result = skimage.filters.thresholding.try_all_threshold(median_filtered)

基于OpenCV的圖像分割是怎樣的

最簡(jiǎn)單的閾值處理方法是為圖像使用手動(dòng)設(shè)置的閾值。但是在圖像上使用自動(dòng)閾值方法可以比人眼更好地計(jì)算其數(shù)值,并且可以輕松復(fù)制。對(duì)于本例中的圖像,似乎Otsu,Yen和Triangle方法的效果很好。

在本文中,我們將使用Otsu閾值技術(shù)將圖像分割成二進(jìn)制圖像。Otsu通過(guò)計(jì)算一個(gè)最大化類(lèi)別間方差(前景與背景之間的方差)并最小化類(lèi)別內(nèi)方差(前景內(nèi)部的方差或背景內(nèi)部的方差)的值來(lái)計(jì)算閾值。如果存在雙峰直方圖(具有兩個(gè)不同的峰)或閾值可以更好地分隔類(lèi)別,則效果很好。

Otsu閾值化和可視化

threshold = skimage.filters.threshold_otsu(median_filtered) print("Threshold value is {}".format(threshold)) predicted = np.uint8(median_filtered > threshold) * 255 plt.imshow(predicted, cmap='gray') plt.axis('off') plt.title("otsu predicted binary image")

基于OpenCV的圖像分割是怎樣的

如果上述簡(jiǎn)單技術(shù)不能用于圖像的二進(jìn)制分割,則可以使用UNet,帶有FCN的ResNet或其他各種受監(jiān)督的深度學(xué)習(xí)技術(shù)來(lái)分割圖像。要去除由于前景噪聲分段而產(chǎn)生的小物體,也可以考慮嘗試skimage.morphology.remove_objects()。

驗(yàn)證方式

一般情況下,我們都需要由具有圖像類(lèi)型專(zhuān)長(zhǎng)的人員手動(dòng)生成基本事實(shí),來(lái)驗(yàn)證準(zhǔn)確性和其他指標(biāo),并查看圖像的分割程度。

confusion矩陣

我們sklearn.metrics.confusion_matrix()用來(lái)獲取該矩陣元素,如下所示。假設(shè)輸入是帶有二進(jìn)制元素的元素列表,則Scikit-learn混淆矩陣函數(shù)將返回混淆矩陣的4個(gè)元素。對(duì)于一切都是一個(gè)二進(jìn)制值(0)或其他(1)的極端情況,sklearn僅返回一個(gè)元素。我們包裝了sklearn混淆矩陣函數(shù),并編寫(xiě)了我們自己的這些邊緣情況,如下所示:

基于OpenCV的圖像分割是怎樣的

get_confusion_matrix_elements()

def get_confusion_matrix_elements(groundtruth_list, predicted_list):    """returns confusion matrix elements i.e TN, FP, FN, TP as floats  See example code for helper function definitions    """    _assert_valid_lists(groundtruth_list, predicted_list)
   if _all_class_1_predicted_as_class_1(groundtruth_list, predicted_list) is True:        tn, fp, fn, tp = 0, 0, 0, np.float64(len(groundtruth_list))
   elif _all_class_0_predicted_as_class_0(groundtruth_list, predicted_list) is True:        tn, fp, fn, tp = np.float64(len(groundtruth_list)), 0, 0, 0
   else:        tn, fp, fn, tp = sklearn.metrics.confusion_matrix(groundtruth_list, predicted_list).ravel()        tn, fp, fn, tp = np.float64(tn), np.float64(fp), np.float64(fn), np.float64(tp)
   return tn, fp, fn, tp

準(zhǔn)確性

在二進(jìn)制分類(lèi)的情況下,準(zhǔn)確性是一種常見(jiàn)的驗(yàn)證指標(biāo)。計(jì)算為
基于OpenCV的圖像分割是怎樣的
其中TP =真正,TN =真負(fù),F(xiàn)P =假正,F(xiàn)N =假負(fù)

get_accuracy()

def get_accuracy(groundtruth_list, predicted_list):
   tn, fp, fn, tp = get_confusion_matrix_elements(groundtruth_list, predicted_list)        total = tp + fp + fn + tn    accuracy = (tp + tn) / total        return accuracy

它在0到1之間變化,0是最差的,1是最好的。如果算法將所有東西都檢測(cè)為整個(gè)背景或前景,那么仍然會(huì)有很高的準(zhǔn)確性。因此,我們需要一個(gè)考慮班級(jí)人數(shù)不平衡的指標(biāo)。特別是由于當(dāng)前圖像比背景0具有更多的前景像素(類(lèi)1)。

F1分?jǐn)?shù)從0到1不等,計(jì)算公式為:

基于OpenCV的圖像分割是怎樣的

0是最差的預(yù)測(cè),而1是最好的預(yù)測(cè)?,F(xiàn)在,考慮邊緣情況,處理F1分?jǐn)?shù)計(jì)算。

get_f1_score()

def get_f1_score(groundtruth_list, predicted_list):    """Return f1 score covering edge cases"""
   tn, fp, fn, tp = get_confusion_matrix_elements(groundtruth_list, predicted_list)        if _all_class_0_predicted_as_class_0(groundtruth_list, predicted_list) is True:        f1_score = 1    elif _all_class_1_predicted_as_class_1(groundtruth_list, predicted_list) is True:        f1_score = 1    else:        f1_score = (2 * tp) / ((2 * tp) + fp + fn)
   return f1_score

高于0.8的F1分?jǐn)?shù)被認(rèn)為是良好的F1分?jǐn)?shù),表明預(yù)測(cè)表現(xiàn)良好。

客戶(hù)中心

MCC代表馬修斯相關(guān)系數(shù),其計(jì)算公式為:

基于OpenCV的圖像分割是怎樣的

它位于-1和+1之間。-1是實(shí)際情況與預(yù)測(cè)之間絕對(duì)相反的相關(guān)性,0是隨機(jī)結(jié)果,其中某些預(yù)測(cè)匹配,而+1是實(shí)際情況與預(yù)測(cè)之間絕對(duì)匹配,保持正相關(guān)。因此,我們需要更好的驗(yàn)證指標(biāo),例如MCC。

在MCC計(jì)算中,分子僅由四個(gè)內(nèi)部單元(元素的叉積)組成,而分母由混淆矩陣的四個(gè)外部單元(點(diǎn)的積)組成。在分母為0的情況下,MCC將能夠注意到我們的分類(lèi)器方向錯(cuò)誤,并且會(huì)通過(guò)將其設(shè)置為未定義的值(即numpy.nan)進(jìn)行警告。但是,為了獲得有效值,并能夠在必要時(shí)對(duì)不同圖像平均MCC,我們將MCC設(shè)置為-1(該范圍內(nèi)最差的值)。其他邊緣情況包括將MCC和F1分?jǐn)?shù)設(shè)置為1的所有正確檢測(cè)為前景和背景的元素。否則,將MCC設(shè)置為-1且F1分?jǐn)?shù)為0。

想要了解有關(guān)MCC和邊緣案例,以及MCC為什么比準(zhǔn)確性或F1分?jǐn)?shù)更好,可以閱讀下面這篇文章:

https://lettier.github.io/posts/2016-08-05-matthews-correlation-coefficient.html

https://en.wikipedia.org/wiki/Matthews_correlation_coefficient#Advantages_of_MCC_over_accuracy_and_F1_score

get_mcc()

def get_mcc(groundtruth_list, predicted_list):    """Return mcc covering edge cases"""   
   tn, fp, fn, tp = get_confusion_matrix_elements(groundtruth_list, predicted_list)        if _all_class_0_predicted_as_class_0(groundtruth_list, predicted_list) is True:        mcc = 1    elif _all_class_1_predicted_as_class_1(groundtruth_list, predicted_list) is True:        mcc = 1    elif _all_class_1_predicted_as_class_0(groundtruth_list, predicted_list) is True:        mcc = -1    elif _all_class_0_predicted_as_class_1(groundtruth_list, predicted_list) is True :        mcc = -1
   elif _mcc_denominator_zero(tn, fp, fn, tp) is True:        mcc = -1
   # Finally calculate MCC    else:        mcc = ((tp * tn) - (fp * fn)) / (            np.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn)))        return mcc

最后,我們可以按結(jié)果并排比較驗(yàn)證指標(biāo)。

>>> validation_metrics = get_validation_metrics(groundtruth, predicted) {'mcc': 0.8533910225863214, 'f1_score': 0.8493358633776091, 'tp': 5595.0, 'fn': 1863.0, 'fp': 122.0, 'accuracy': 0.9924278259277344, 'tn': 254564.0}

精度接近1,因?yàn)槭纠龍D像中有很多背景像素可被正確檢測(cè)為背景(即,真實(shí)的底片自然更高)。這說(shuō)明了為什么精度不是二進(jìn)制分類(lèi)的好方法。

F1分?jǐn)?shù)是0.84。因此,在這種情況下,我們可能不需要用于二進(jìn)制分割的更復(fù)雜的閾值算法。如果堆棧中的所有圖像都具有相似的直方圖分布和噪聲,則可以使用Otsu并獲得相當(dāng)不錯(cuò)的預(yù)測(cè)結(jié)果。

所述MCC 0.85高時(shí),也表示地面實(shí)況和預(yù)測(cè)圖像具有高的相關(guān)性,從在上一節(jié)的預(yù)測(cè)圖像圖片清楚地看到。

現(xiàn)在,讓我們可視化并查看混淆矩陣元素TP,F(xiàn)P,F(xiàn)N,TN在圖像周?chē)姆植嘉恢?。它向我們顯示了在不存在閾值(FP)的情況下閾值正在拾取前景(容器),在未檢測(cè)到真實(shí)血管的位置(FN),反之亦然。

驗(yàn)證可視化

為了可視化混淆矩陣元素,我們精確地找出混淆矩陣元素在圖像中的位置。例如,我們發(fā)現(xiàn)TP陣列(即正確檢測(cè)為前景的像素)是通過(guò)找到真實(shí)情況和預(yù)測(cè)陣列的邏輯“與”。同樣,我們使用邏輯布爾運(yùn)算通常稱(chēng)為FP,F(xiàn)N,TN數(shù)組。

get_confusion_matrix_intersection_mats()

def get_confusion_matrix_intersection_mats(groundtruth, predicted):    """ Returns dict of 4 boolean numpy arrays with True at TP, FP, FN, TN    """
   confusion_matrix_arrs = {}
   groundtruth_inverse = np.logical_not(groundtruth)    predicted_inverse = np.logical_not(predicted)
   confusion_matrix_arrs['tp'] = np.logical_and(groundtruth, predicted)    confusion_matrix_arrs['tn'] = np.logical_and(groundtruth_inverse, predicted_inverse)    confusion_matrix_arrs['fp'] = np.logical_and(groundtruth_inverse, predicted)    confusion_matrix_arrs['fn'] = np.logical_and(groundtruth, predicted_inverse)
   return confusion_matrix_arrs

然后,我們可以將每個(gè)數(shù)組中的像素映射為不同的顏色。對(duì)于下圖,我們將TP,F(xiàn)P,F(xiàn)N,TN映射到CMYK(青色,品紅色,黃色,黑色)空間。同樣可以將它們映射到(綠色,紅色,紅色,綠色)顏色。然后,我們將獲得一張圖像,其中所有紅色均表示錯(cuò)誤的預(yù)測(cè)。CMYK空間使我們能夠區(qū)分TP,TN。

get_confusion_matrix_overlaid_mask()

def get_confusion_matrix_overlaid_mask(image, groundtruth, predicted, alpha, colors):    """    Returns overlay the 'image' with a color mask where TP, FP, FN, TN are    each a color given by the 'colors' dictionary    """    image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)    masks = get_confusion_matrix_intersection_mats(groundtruth, predicted)    color_mask = np.zeros_like(image)    for label, mask in masks.items():        color = colors[label]        mask_rgb = np.zeros_like(image)        mask_rgb[mask != 0] = color        color_mask += mask_rgb    return cv2.addWeighted(image, alpha, color_mask, 1 - alpha, 0)
alpha = 0.5confusion_matrix_colors = {   'tp': (0, 255, 255),  #cyan   'fp': (255, 0, 255),  #magenta   'fn': (255, 255, 0),  #yellow   'tn': (0, 0, 0)     #black   }validation_mask = get_confusion_matrix_overlaid_mask(255 - grayscale, groundtruth, predicted, alpha, confusion_matrix_colors)print('Cyan - TP')print('Magenta - FP')print('Yellow - FN')print('Black - TN')plt.imshow(validation_mask)plt.axis('off')plt.title('confusion matrix overlay mask')

我們?cè)诖颂幨褂肙penCV將此顏色蒙版作為透明層覆蓋到原始(非反轉(zhuǎn))灰度圖像上。這稱(chēng)為Alpha合成:

基于OpenCV的圖像分割是怎樣的

關(guān)于基于OpenCV的圖像分割是怎樣的問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI