2013-12-12 33 views
5

我正在使用OpenCV(Java)處理一些葉子圖像。葉子是在一張白紙上捕獲和一些有陰影像這樣的:在白色背景上刪除科爾物體陰影的自動方法?

enter image description here

。當然,這是莫名其妙的極端情況下(有溫和的陰影)。

現在,我想閾值葉,也刪除陰影(同時保留葉的細節)。


我的電流流動是這樣的:

1)轉換爲HSV並提取飽和信道:

Imgproc.cvtColor(colorMat, colorMat, Imgproc.COLOR_RGB2HSV); 
ArrayList<Mat> channels = new ArrayList<Mat>(); 
Core.split(colorMat, channels); 
satImg = channels.get(1); 

2)去噪(中位數)和施加adaptiveThreshold :

Imgproc.medianBlur(satImg , satImg , 11); 
Imgproc.adaptiveThreshold(satImg , satImg , 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 401, -10); 

,結果是這樣的:

enter image description here

它看起來不錯,但陰影造成沿左邊界一些異常。此外,我有這種感覺,我不使用白色背景對我有利。

現在,我有2個問題:
1)如何改善結果並擺脫陰影?

2)如果不使用飽和通道,我可以獲得好的結果嗎?。我問的原因是,在我的大部分圖像上,L通道(從HLS)給出了更好的結果(當然除了陰影之外)。


更新:使用色相通道使得threshdolding更好,反而使得陰影的情況更糟:

enter image description here


UPDATE2:在某些情況下,假設陰影比葉片暗並不總是持有。所以,在強度上工作不會有幫助。我正在更加註重色彩通道方法。

+1

由於葉子是綠色的,背景是白色/陰影,因此可以在色調通道上工作。 – GilLevi

+0

@GilLevi,查看更新。它無助於消除陰影。 – Mahm00d

+0

嗯,我真的不確定。也許使用不同的色彩空間,比如LAB?對不起,我不能進一步幫助。 – GilLevi

回答

2

我不使用opencv,而是嘗試使用matlab圖像處理工具箱來提取葉子。希望opencv具有所有處理功能。請看下面我的結果。我在原始圖像頻道3和頻道1中完成了所有操作。

首先我使用頻道3,將它與100(左上方)進行比較。然後刪除邊界上的區域和像素大小小於100的區域,填充葉子中的孔,結果顯示在右上方。

接下來我使用了你的頻道1,和我在頻道3中做的一樣,結果顯示在左下角。然後我發現連接區域(在左下圖中只能看到兩個區域),刪除區域較小的區域(如右下方所示)。

enter image description here

假設右上方圖像是I1,與右底部圖像是I,葉片是由實施~I && I1萃取。葉是:

enter image description here

希望它能幫助。由於

+0

真的很好的做法。儘管這樣做有兩個問題:1)我不知道陰影的靜態閾值,2)沒有擔保,最大的部分是陰影,而不是其他部分(葉子的一部分)。 – Mahm00d

+1

謝謝Mahm00d。圖像處理中的閾值總是很棘手,這就是爲什麼您可能需要選擇以最大強度邊緣來分離葉子和陰影的通道。您可能需要幾個樣本來粗略估計通道和閾值。關於連接組件,根的強度比葉片更接近陰影。這就是爲什麼通常檢測到兩個連接部分的原因。有時根可能會在葉中攜帶一些微小的部分,但最大的部分將是影子的假設是最真實的。 – lennon310

+0

你是對的棘手的部分。我有一個深綠色的葉子樣本。在這種情況下,幾乎不可能找到一個不包含葉子部分的靜態閾值。更糟糕的是,有時候葉子可能比陰影更暗!所以,我認爲在頻道上而不是強度上工作會是更好的方法。 – Mahm00d

1

我嘗試了兩種不同的東西: 1.其他閾值上飽和通道 2.試圖找到兩個輪廓:陰影和葉

我使用C++這樣你的代碼片段看起來有點不同。

試圖大津的閾值,而不是自適應閾值:

cv::threshold(hsv_imgs,mask,0,255,CV_THRESH_BINARY|CV_THRESH_OTSU); 

導致下面的圖像(在飽和通道只是Otsu閾值):

enter image description hereenter image description here

另一件事是計算梯度信息(我用sobel,看到oppenCV文檔),閾值和開幕後的運營商我用findContours給這樣的東西,不可用(梯度輪廓的方法):

enter image description hereenter image description here

0

我試圖做蝴蝶的照片同樣的事情,但更多的不均衡和不可預測的背景,如this。一旦你確定了背景的一個很好的部分(例如通過閾值處理,或者像我們一樣,從隨機點填充),最好的辦法是使用GrabCut算法來獲得你在初始通過時可能會錯過的所有位。在Python中,假設你仍然希望通過閾值上飽和通道,以確定背景的初始區域,嘗試像

import cv2 
import numpy as np 

img = cv2.imread("leaf.jpg") 
sat = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)[:,:,1] 
sat = cv2.medianBlur(sat, 11) 
thresh = cv2.adaptiveThreshold(sat , 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 401, 10); 
cv2.imwrite("thresh.jpg", thresh) 

h, w = img.shape[:2] 
bgdModel = np.zeros((1,65),np.float64) 
fgdModel = np.zeros((1,65),np.float64) 
grabcut_mask = thresh/255*3 #background should be 0, probable foreground = 3 
cv2.grabCut(img, grabcut_mask,(0,0,w,h),bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK) 
grabcut_mask = np.where((grabcut_mask ==2)|(grabcut_mask ==0),0,1).astype('uint8') 

cv2.imwrite("GrabCut1.jpg", img*grabcut_mask[...,None]) 

這實際上擺脫在這種情況下,陰影給你的,因爲陰影的邊緣實際上具有較高的飽和度,因此被包含在抓取刪除中。 (我會發布圖片,但沒有足夠的聲望)

但是,通常情況下,您不能相信背景檢測中會包含陰影。在這種情況下,您可能想要使用由Horprasert等人提出的色度失真度量來比較圖像中的區域與現在已知的背景的顏色。人。 (1999),「實時穩健背景減法和陰影檢測的統計方法」。這一措施考慮到了對於不飽和的顏色,色相不是相關的措施。

請注意,您在網上找到的預印本的pdf在等式6中有一個錯誤(無+符號)。您可以使用在Rodriguez-Gomez et al (2012),等式1 & 2中重新引用的版本。或者你可以使用我下面的Python代碼:

def brightness_distortion(I, mu, sigma): 
    return np.sum(I*mu/sigma**2, axis=-1)/np.sum((mu/sigma)**2, axis=-1) 


def chromacity_distortion(I, mu, sigma): 
    alpha = brightness_distortion(I, mu, sigma)[...,None] 
    return np.sqrt(np.sum(((I - alpha * mu)/sigma)**2, axis=-1)) 

可以養活已知的背景意味着& STDEV作爲chromacity_distortion函數的最後兩個參數,以及RGB像素圖像作爲第一個參數,它應該告訴你的是陰影與背景基本上是相同的色度,並且與葉子非常不同。在下面的代碼中,我已經對chromacity進行了閾值處理,並且完成了另一次抓取通過。此作品去除陰影,即使第一grabcut通不(例如,如果您最初閾值處理的色調)

mean, stdev = cv2.meanStdDev(img, mask = 255-thresh) 
mean = mean.ravel() #bizarrely, meanStdDev returns an array of size [3,1], not [3], so flatten it 
stdev = stdev.ravel() 
chrom = chromacity_distortion(img, mean, stdev) 
chrom255 = cv2.normalize(chrom, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX).astype(np.uint8)[:,:,None] 
cv2.imwrite("ChromacityDistortionFromBackground.jpg", chrom255) 

thresh2 = cv2.adaptiveThreshold(chrom255 , 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 401, 10); 
cv2.imwrite("thresh2.jpg", thresh2) 

grabcut_mask[...] = 3 
grabcut_mask[thresh==0] = 0 #where thresh == 0, definitely background, set to 0 
grabcut_mask[np.logical_and(thresh == 255, thresh2 == 0)] = 2 #could try setting this to 2 or 0 
cv2.grabCut(img, grabcut_mask,(0,0,w,h),bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK) 
grabcut_mask = np.where((grabcut_mask ==2)|(grabcut_mask ==0),0,1).astype('uint8') 
cv2.imwrite("final_leaf.jpg", grabcut_mask[...,None]*img) 

恐怕與我試過的參數,這仍然去除莖,雖然。我認爲這是因爲GrabCut認爲它看起來與陰影類似。讓我知道如果你找到一個方法來保持它。