2012-04-04 81 views
2

我試圖用我不熟悉的概念解決C++中的一個具有挑戰性的問題。什麼是實際應用過濾器?

我正在嘗試將過濾器應用於矩陣。然而就像我說我很新,在這個和一些調查後,我發現這個鏈接,它顯示應用過濾器基本上是一個乘法

然而,讓我困惑的是,如果我的過濾器是[0,1 ,0],我必須將它應用於5x5矩陣。我將如何能夠做到這一點?

GIMP Filtering with kernel

An alternative to first link

編輯:第二個鏈接真的搞糊塗了。我現在正試圖決定「應用程序」過程。如果我遵循創建一個只有對角線[0,1,0]的3x3矩陣的想法,那麼我會像在第二個鏈接中那樣應用它,或者我必須將它應用於矩陣中的每個單元。或者,如果它真的要成爲一維濾波器,我應該再次將它應用於每個單元或者忽略邊緣和角落?

+0

過濾器'[0,1,0]'將成爲標識轉換,除非不同的值表示_colors_,如[ElKamina建議](http://stackoverflow.com/a/10003402/377270),或其他一些信息丟失。 – sarnold 2012-04-04 00:36:07

+0

我舉了一個例子,我想使用的主要過濾器是[-1,0,1] – Ali 2012-04-04 00:37:31

回答

3

我認爲被忽視的是乘法使用輸入數據的子集重複輸入數組的每個元素。

GIMP的例子展示瞭如何使用一個3×3濾波器用於單個像素來過濾的5×5的圖像:

. . . . .     . . . . . 
. - - - .  . . .  . . . . . 
. - @ - . x . . . -> . . @ . . 
. - - - .  . . .  . . . . . 
. . . . .     . . . . . 

我已經標記的一個輸入像素與@和其鄰國與-。您可以使用較小的矩陣:

- - -  . . . 
- @ - x . . . = 3x3 array 
- - -  . . . 

總結得到的3x3陣列中的數字,並存儲該值裝入圖像,以代替@像素。

藉此來你的榜樣,使用3X1濾波器濾波5x5的圖像時:

. . . . .     . . . . . 
. . . . .     . . . . . 
. - @ - . x . . . -> . . @ . . 
. . . . .     . . . . . 
. . . . .     . . . . . 

您將使用輸入數組的一個較小的子集,以滿足您的內核;

- @ - x . . . = 1x3 array 

然後,再次,總結所得的陣列中的數字,並將該值存儲到新圖像代替@像素。

+0

這很有道理。我會檢查出來,可能會回來更多的問題,但你的帖子爲我開始思考奠定了非常好的基礎。謝謝! :) – Ali 2012-04-04 00:57:56

+0

我再次檢查它,挑戰需要將濾鏡分別應用於x軸和y軸。這是否意味着首先我應該用第一行中的前3個數字,然後從2到4(含),然後是3到5或其他什麼? – Ali 2012-04-04 11:22:14

0

我想你說的是彩色濾光片。從技術上講,5X5圖像實際上是5X5X3(A),其中'3'對應於3種基本色彩(RGB)。現在,用對角線[0,1,0](T)創建一個3X3的矩陣。

現在乘以兩個矩陣(AXT)得到新的5X5X3圖像矩陣。

+0

對不起,因爲在這個'太新',但我有幾個問題。 1)如果我創建了具有對角線[0,1,0]的矩陣,其餘的數字不會產生重大影響? – Ali 2012-04-04 00:42:04

+0

2)我真的不知道如何乘以5x5x3和3x3。三維和二維讓我感到困惑。 – Ali 2012-04-04 00:42:42

+0

1.是的。基本上你的形象將只有綠色色調。 2.乘以5次5X3和3X3矩陣。 – ElKamina 2012-04-04 01:17:30

4

這是一個卷積內核。

這個想法是,你用每個像素和它的鄰居的加權平均值替換每個像素,其中權重由你的卷積核給出。這個過程很好地解釋,例如here

我覺得你有一個一維卷積核(即這將適用於一維圖像),通常用於圖像處理的二維卷積核(其中也採用上方/下方的行中的像素),但這可能是因爲您的算法只需要像素從當前行開始。

+0

我可以考慮一維內核的兩種可能的用途:去隔行可能對3x1矢量(垂直)足夠好,並且可能用1x3矢量(水平)完成_simple_運動模糊。 – sarnold 2012-04-04 01:00:49

+0

你完全正確,它確實是一個卷積內核。我只需要弄清楚應用濾波器過程是否將矩陣中的數字與濾波器相乘。我只是不知道「應用」部分。像應用意味着一行一行,然後逐列,或其他什麼? – Ali 2012-04-04 01:00:56

+0

我讀過這篇文章,其確實令人驚歎。我只是有兩個問題:1)我們是否對矩陣中的每個單數都應用這個過程?(包括邊和角)2)在你看來,當涉及到邊和角時我應該怎麼做(會忽略剩餘的內核會造成很多麻煩?) – Ali 2012-04-04 11:51:37

2

這是混淆你在尋找答案。如果我們讓你的過濾器存儲在std::vector<double>filter和你的形象實在是2D並鍵入std::vector< std::vector<double> >稱爲image,那麼我們可以做以下申請1-d過濾[-1,0,1]假設:

std::vector< std::vector<double> > new_image; 
std::vector<double> filter; 
filter.push_back(-1.0); filter.push_back(0.0); filter.push_back(1.0); 

for(int i = 0; i < image.size(); i++){ 
    for(int j = 0; j < image.at(i).size(); j++){ 

     new_image.at(i).push_back(filter.at(0)*image.at(i).at(j-1) 
            + filter.at(1)*image.at(i).at(j) 
            + filter.at(2)*image.at(i).at(j+1)); 

    } 
} 

如果你想有這樣一個例如

[0 1 0] 
[1 0 1] 
[0 1 0] 

一個2維濾波器那麼我們假設它被存儲爲載體的載體,以及,基本上做的是一樣的。

std::vector< std::vector<double> > new_image; 

for(int i = 0; i < image.size(); i++){ 
    for(int j = 0; j < image.at(i).size(); j++){ 

     top_filter_term = filter.at(0).at(0)*image.at(i-1).at(j-1) 
          + filter.at(0).at(1)*image.at(i-1).at(j) 
          + filter.at(0).at(2)*image.at(i-1).at(j+1); 

     mid_filter_term = filter.at(1).at(0)*image.at(i).at(j-1) 
          + filter.at(1).at(1)*image.at(i).at(j) 
          + filter.at(1).at(2)*image.at(i).at(j+1); 

     bot_filter_term = filter.at(2).at(0)*image.at(i+1).at(j-1) 
          + filter.at(2).at(1)*image.at(i+1).at(j) 
          + filter.at(2).at(2)*image.at(i+1).at(j+1); 

     new_image.at(i).push_back(top_filter_term + mid_filter_term + bot_filter_term); 

    } 
} 

請注意 - 我沒有作任何努力做邊界檢查的濾波器陣列,你真的應該只從圖像的邊緣應用此走,或將代碼添加到任何應用您想要用於過濾器的各種邊界條件。我也沒有對此進行任何優化。對於大多數用途而言,使用矢量是一個好方法,因爲它們可以動態調整大小,並提供足夠的內置支持來執行大量有用的圖像操作。但是對於真正的大規模處理,你會想要優化過濾器操作等。

至於你關於過濾3D數組的問題,有幾點需要考慮。一,確保你真的想過濾整個數組。對於許多圖像處理任務來說,將所有顏色通道分割成各自的2D陣列,進行處理,然後將它們重新組合起來會更好更高效。如果你確實需要一個真正的3D濾鏡,那麼確定你的濾鏡實際上是3D的,也就是說,它將是矢量矢量的矢量。然後,您將使用與上述完全相同的邏輯,但您將爲應用於圖像的每個顏色通道或「切片」的濾鏡部分添加一個附加層次的術語。