2013-03-22 121 views
25

什麼是快速和可靠的方式閾值圖像可能模糊和不均勻的亮度?快速圖像閾值

實施例(模糊但均勻的亮度):

enter image description here

因爲圖像是不能保證有均勻的亮度,這是不可行的使用固定的閾值。自適應閾值的作品還好,但由於模糊的它在功能產生斷裂和扭曲(在這裏,最重要的特點是獨位):

enter image description here

我也用直方圖均衡化嘗試(使用OpenCV的equalizeHist函數)。它增加對比度而不減少亮度差異。

我發現的最好的解決方案是將圖像的形態學關閉(歸功於this post)以使亮度一致,然後重新歸一化,然後使用固定閾值(使用Otsu算法選擇最佳閾值水平) :

enter image description here

這裏是OpenCV的此代碼的Android:

Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(19,19)); 
Mat closed = new Mat(); // closed will have type CV_32F 
Imgproc.morphologyEx(image, closed, Imgproc.MORPH_CLOSE, kernel); 
Core.divide(image, closed, closed, 1, CvType.CV_32F); 
Core.normalize(closed, image, 0, 255, Core.NORM_MINMAX, CvType.CV_8U); 
Imgproc.threshold(image, image, -1, 255, Imgproc.THRESH_BINARY_INV 
    +Imgproc.THRESH_OTSU); 

這個偉大的工程,但閉合動作很慢。減小結構元素的尺寸會提高速度,但會降低精度。

編輯:基於DCS的建議,我嘗試使用高通濾波器。我選擇了拉普拉斯濾波器,但我希望Sobel和Scharr濾波器有類似的結果。該濾波器在不包含特徵的區域中拾取高頻噪聲,並且由於模糊而遭受與自適應閾值類似的失真。它也需要與關閉操作一樣長。下面是一個15×15濾波器的例子:

enter image description here

編輯2:基於AruniRC的回答中,我使用Canny邊緣檢測的圖像上的與所述建議的參數:

double mean = Core.mean(image).val[0]; 
Imgproc.Canny(image, image, 0.66*mean, 1.33*mean); 

我不確定如何自動自動微調參數獲取連接數字。

enter image description here

+0

假設brigthness變化發生在低頻率,您可以嘗試在高通濾波圖像上設置閾值。但是,我不知道這些過濾器操作在移動設備上的速度有多快,而且我認爲您需要一個相當大的內核。 – DCS 2013-03-22 08:42:35

+0

@DCS不幸的是,我不認爲高通濾波器可以工作。看到我的編輯到上面的帖子。 – 2013-03-22 22:25:37

+2

由於您感興趣的功能涵蓋多個像素,因此如何將圖像先降低至較低分辨率?然後,您可以返回並以原始分辨率獲取更多細節,並使用較低分辨率的版本作爲蒙版。 – 2013-03-24 03:49:17

回答

18

使用Vaughn Cato和Theraot的建議,在關閉圖像之前縮小圖像,然後將封閉圖像縮放至常規尺寸。我也按比例縮小了內核大小。

Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(5,5)); 
Mat temp = new Mat(); 

Imgproc.resize(image, temp, new Size(image.cols()/4, image.rows()/4)); 
Imgproc.morphologyEx(temp, temp, Imgproc.MORPH_CLOSE, kernel); 
Imgproc.resize(temp, temp, new Size(image.cols(), image.rows())); 

Core.divide(image, temp, temp, 1, CvType.CV_32F); // temp will now have type CV_32F 
Core.normalize(temp, image, 0, 255, Core.NORM_MINMAX, CvType.CV_8U); 

Imgproc.threshold(image, image, -1, 255, 
    Imgproc.THRESH_BINARY_INV+Imgproc.THRESH_OTSU); 

下面的圖像示出了結果爲3種不同的方法並排側:

左 - 規則尺寸關閉(432個像素),尺寸19的內核

中東 - 半尺寸閉(216個像素),尺寸9內核

右 - 四分之一大小關閉(108個像素),大小5內核

enter image description here

隨着用於關閉的圖像大小變小,圖像質量惡化,但惡化不足以影響特徵識別算法。對於四分之一尺寸的關閉,速度稍微增加16倍以上,即使調整大小也是如此,這表明關閉時間大致與圖像中的像素數成正比。

任何有關如何進一步改進此想法的建議(無論是進一步降低速度還是降低圖像質量的惡化)都非常受歡迎。

+0

您應該使用adaptiveThreshold而不是閾值。 自適應閾值將在黑暗圖像的情況下提供更好的結果。 – AnkitRox 2015-02-17 06:24:16

+0

請讓我知道,如果你想要自適應閾值的代碼.. – AnkitRox 2015-02-17 06:24:40

+0

@AnkitRox我在這個問題中討論自適應閾值。 – 2015-02-17 15:46:35

2

替代做法:

假設你的意圖是必須明確二值化的數字...您的重點轉向組件,而不是整個圖像。

這裏有一個很簡單的方法:

  1. 執行圖像上的坎尼edgemap。首先嚐試使用Canny函數的參數在低閾值到0.66 * [平均值]和高閾值到1.33 * [平均值]的範圍內。 (意思是greylevel值的平均值)。
  2. 您需要一點一點地調整參數以獲取主要組件/數字清晰可見的圖像,作爲單獨的組件。在這個階段,接近完美就足夠了。
  3. 考慮到每個Canny邊緣是一個連通的組件(即使用cvFindContours()或它的C++對應物,無論哪個)可以估計前景和背景灰度並達到閾值。

    最後一點,請看this paper的第2部分和第3部分。跳過大部分非必要的理論部分,在OpenCV中實現它不應該太難。

    希望這有助於!

編輯1:

基於Canny邊緣的閾值這裏是一個非常粗略的想法剛好足夠微調值。 high_threshold控制邊緣在檢測到之前必須有多強。基本上,邊緣的梯度幅度必須大於high_threshold才能被首先檢測到。所以這是邊緣的初始檢測。

現在,low_threshold處理連接附近的邊緣。它控制着多少附近斷開的邊將被組合到一個邊中。更好的主意,請閱讀this webpage的「步驟6」。嘗試設置一個非常小的low_threshold並查看事情是如何發生的。如果它不適用於這些圖像,您可以丟棄0.66 * [平均值]的東西 - 無論如何它只是一個經驗法則。

+1

有趣的方法,但請參閱我的問題編輯2。 – 2013-03-24 17:14:47

+0

hmm。好吧,這種玩閾值的遊戲需要時間,但並不是不可能獲得一系列值得大量圖像體面的結果。嘗試'low_threshold = 50,high_threshold = 150'。一般low_threshold:high_threshold應按Canny的原始文件大約1:3。小提琴! :) – AruniRC 2013-03-25 06:47:44

+0

對不起,我應該更確切。我擔心可靠性,因爲如果Canny在數字中創建了一個小小的斷點,該方法就會失敗。另一方面,如果我的關閉方法運行不正常,這些數字格式不正確,但仍可以通過計算機檢測到。如果您認爲我可以在一系列照明條件和模糊情況下獲得具有固定坎尼閾值的可靠結果,我會試一試。這篇論文的結果似乎相當令人印象深刻。 – 2013-03-25 15:29:21

0

如果你知道你有一個很好的網格作物,你可以嘗試在每個平鋪的基礎上工作。處理9個子圖像而不是整個圖像將最有可能在每個子圖像上產生更均勻的亮度。如果你的剪裁是完美的,你甚至可以嘗試單獨的每個數字單元;但這一切都取決於你的作物的可靠性。

+0

我其實已經在做:) – 2013-03-30 14:31:23

+0

很酷;如果每個細胞都有完美的作物,並且可以輕鬆地分離每個數字,那麼模板匹配可能會在一定程度上起作用......這些細胞上只有10種可能的內容。我覺得這可以在良好的訓練中運作良好;你是否期望所有的輸入使用相同的字體? – amadillu 2013-03-31 12:07:20

+0

不一定。我使用面向梯度直方圖將每個數字的重要特徵分離爲「特徵向量」,然後使用支持向量機對向量進行分類。 [我被告知](http://stackoverflow.com/a/13319850/1397061)這是做數字識別最可靠的方法。 – 2013-03-31 15:57:40

2

我們使用Bradleys算法來解決非常類似的問題(從背景中分割字母,使用不均勻的光線和不均勻的背景色),如下所示:http://people.scs.carleton.ca:8008/~roth/iit-publications-iti/docs/gerh-50002.pdf,這裏的C#代碼:http://code.google.com/p/aforge/source/browse/trunk/Sources/Imaging/Filters/Adaptive+Binarization/BradleyLocalThresholding.cs?r=1360。它適用於積分圖像,可以使用OpenCV的integral函數進行計算。它非常可靠和快速,但本身並未在OpenCV中實現,但易於移植。

另一個選擇是openCV中的adaptiveThreshold方法,但我們沒有試一試:http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#adaptivethreshold。 MEAN版本與bradleys相同,只是它使用常量來修改平均值而不是百分比,我認爲這是更好的。

而且,好文章是在這裏:https://dsp.stackexchange.com/a/2504

0

橢圓形狀複雜,如果比較扁平的形狀來計算。 嘗試改變:

Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(19,19)); 

到:

Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(19,19)); 

可以加快你的低影響精度足夠的解決方案。