2012-11-08 73 views
8

我從磁盤加載RGB圖像與JuicyPixels-repa。不幸的是,圖像的陣列表示是Array F DIM3 Word8,其中內部維度是RGB像素。這與現有的repa圖像處理算法有些不兼容,其中RGB圖像是Array U DIM2 (Word8, Word8, Word8)用repa計算圖像直方圖

我要計算圖像的直方圖RGB,我在尋找一個函數簽名:

type Hist = Array U DIM1 Int 
histogram:: Array F DIM3 Word8 -> (Hist, Hist, Hist) 

我怎麼可以摺疊我的3D陣列以獲得每個colorchannel一維數組?

編輯:

的主要問題不在於我無法從DIM3轉換爲DIM2每通道(容易切片完成)。問題是我必須迭代源圖像DIM2DIM3,並且必須積累到不同的Shape(Z:.256)範圍內的DIM1陣列。 所以我不能使用repa的foldS,因爲它減少了一個維度,但程度相同。

我也嘗試過traverse,但它遍歷目標圖像的範圍,提供從源圖像獲取像素的函數,這會導致效率非常低的代碼,計算每個顏色值的相同像素。

的一個好方法是在與所述直方圖類型作爲儲液器的一個Vector簡單的摺疊,但不幸的是我沒有U(無盒裝)或V(矢量)基於陣列,從中我能夠有效地得到一個Vector。我有一個Array F(外部指針)。

+3

你有什麼試過? (如果數組的類型是'Array U DIM2(Word8,Word8,Word8)',你可以這樣做嗎?如果是,你可以寫一個轉換函數Array U DIM3 Word8 - > Array U DIM2(Word8,Word8,Word8) ?) – huon

+1

明天我會試着看看這個。與此同時,如果圖像表示之間存在基本轉換,您認爲這對JP-repa有用,則可隨時發送補丁。 –

+0

@FalcoHirschenberger你有沒有得到大津閾值完成?我喜歡它,但我想避免任何重複的工作。 –

回答

7

好的,我找了幾分鐘。下面,我介紹了四種解決方案,並提出了最糟糕的解決方案(中間兩項,涉及O(n)數據轉換)對您來說非常簡單。

讓我們確認阿呆解決方案

這是合理的,先從明顯。你可以使用Data.List.foldl遍歷行和列,從最初的零個陣列建立你的直方圖(未經測試/部分代碼如下):

foldl (\(histR, histG, histB) (row,col) -> 
      let r = arr ! (Z:.row:.col:.0) 
       g = arr ! (Z:.row:.col:.1) 
       b = arr ! (Z:.row:.col:.2) 
      in (incElem r histR, incElem g histG, incElem b histB) 
     (zero,zero,zero) 
     [ (row,col) | row <- [0..nrRow-1], col <- [0..nrCol-1] ] 
... 
where (Z:.nrRow:.nrCol:._) = extent arr 

我不知道如何有效的,這將是,但懷疑它會做太多的邊界檢查。切換到unsafeIndex應該是合理的,假設延遲陣列hist*做得很好,但由於您選擇實施incElem

你可以建立數組你想要

使用traverse你其實可以轉換JP-惹巴風格的數組爲DIM2陣列,元組的元素:

main = do 
    let arr = R.fromFunction (Z:.a:.b:.c) (\(Z:.i:.j:.k) -> i+j-k) 
     a =4 :: Int 
     b = 4 :: Int 
     c= 4 :: Int 
     new = R.traverse arr 
         (\(Z:.r:.c:._) -> Z:.r:.c) -- the extent 
         (\l idx -> (l (idx:.0) 
            ,l (idx:.1) 
            ,l (idx :. 2))) 
    print (R.computeS new :: R.Array R.U DIM2 (Int,Int,Int)) 

你能指出我的身體你談到的代碼使用這種格式?將JP-Repa修補爲包含這種類型的功能很簡單。

可以建立無盒裝矢量你提到

你提到一個簡單的解決方案是摺疊裝箱載體,但感嘆JP-repA的不提供裝箱陣列。幸運的是,轉換很簡單:

toUnboxed :: Img a -> VU.Vector Word8 
toUnboxed = R.toUnboxed . R.computeUnboxedS . R.delay . imgData 

我們可以補丁惹巴

這是真的只有一個問題,因爲惹巴沒有什麼,我認爲一個正常traverse功能。 Repa的遍歷更像是一個數組構造,它恰好爲另一個數組提供索引函數。我們希望以下形式進行遍歷:

newTraverse :: Array r sh e -> a -> (a -> sh -> e -> a) -> a 

但粗糙的這其實只是一個畸形的摺疊。所以讓我們將其重命名和重新排列參數:

foldAllIdxS :: (sh -> a - > e -> a) -> a -> Array r sh e -> a 

它與(預先存在的)foldAllS操作很好的對比:

foldAllS :: (a -> a -> a) -> a -> Array r sh a -> a 

通知我們的新折怎麼有兩個重要的特點。結果類型不需要匹配元素類型,所以我們可以從一個直方圖元組開始。其次,我們的摺疊版本通過索引,它允許您選擇要更新的元組中的哪個直方圖(如果有的話)。

您可以懶洋洋地使用最新的JuicyPixels-惹巴

爲了獲得您的首選惹巴陣列格式,或獲取未裝箱載體,你可以使用新上載JuicyPixels-惹巴-0.6。

someImg <- readImage path :: IO (Either String (Img RGBA)) 
let img = either (error "Blah") id someImg 
    uvec = toUnboxed img 
    tupleArr = collapseColorChannel img 

現在您可以直接摺疊向量或使用元組數組了,就像您最初所期望的那樣。

我也參加了一個醜陋的刺在充實第一,可怕的天真,解決方法:

histograms :: Img a -> (Histogram, Histogram, Histogram, Histogram) 
histograms (Img arr) = 
    let (Z:.nrRow:.nrCol:._) = R.extent arr 
     zero = R.fromFunction (Z:.256) (\_ -> 0 :: Word8) 
     incElem idx x = RU.unsafeTraverse x id (\l i -> l i + if i==(Z:.fromIntegral idx) then 1 else 0) 
    in Prelude.foldl (\(hR, hG, hB, hA) (row,col) -> 
      let r = R.unsafeIndex arr (Z:.row:.col:.0) 
       g = R.unsafeIndex arr (Z:.row:.col:.1) 
       b = R.unsafeIndex arr (Z:.row:.col:.2) 
       a = R.unsafeIndex arr (Z:.row:.col:.3) 
      in (incElem r hR, incElem g hG, incElem b hB, incElem a hA)) 
      (zero,zero,zero,zero) 
      [ (row,col) | row <- [0..nrRow-1], col <- [0..nrCol-1] ] 

我太警惕這種代碼的性能(每指數3個遍歷......我必須是累了)把它扔進JP-Repa,但如果你發現它運作良好,然後讓我知道。

+0

感謝您的awsome答案。我會盡快嘗試你的建議。我嘗試實現Otsu自動閾值算法。關於您的問題,'repa-algorithms'中的算法以'Array U DIM2 a'的形式表示多路圖像,並提供'rgb8OfFloat ::(Float,Float,Float) - >形式的像素轉換函數(Word8,Word8 ,Word8)'。 –