2012-11-08 4 views
8

디스크에서 RGB 이미지를 JuicyPixels-repa으로로드하고 있습니다. 안타깝게도 이미지의 Array 표현은 Array F DIM3 Word8이고 내부 치수는 RGB 픽셀입니다. RGB 이미지가 Array U DIM2 (Word8, Word8, Word8) 인 기존의 repa 이미지 처리 알고리즘과 약간 호환되지 않습니다. 나는 이미지의 RGB 히스토그램을 계산하려는 리팩토로 이미지 히스토그램 계산

, 나는 서명 기능을 찾고 있어요 :

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

어떻게 내 3 차원 배열을 접을 수있는 각 colorchannel에 대한 1 차원 배열을 얻을?

편집 :

가장 큰 문제는 내가 (쉬운 슬라이스로 수행) 각 채널에 대해 DIM2DIM3에서 변환 할 수 아니에요 없습니다. 문제는 소스 이미지 DIM2 또는 DIM3을 반복해야하고 다른 Shape(Z:.256) 범위의 DIM1 배열에 누적해야한다는 것입니다. 그래서 repa의 foldS은 크기를 1 줄이기 때문에 사용할 수는 있지만 크기는 같습니다.

나는 또한 traverse으로 실험했지만 소스 이미지에서 픽셀을 가져 오는 기능을 제공하여 매우 비효율적 인 코드로 이어지고 각 색상 값에 대해 동일한 픽셀을 계산하는 대상 이미지의 범위를 반복합니다.

좋은 방법은 누산기로서 히스토그램 유형의 Vector 위에 간단한 접는 것이지만, 불행히도 제가 효율적 Vector을 얻을 수있는 더 U 박스 없음 또는 V (벡터)에 기초하여 배열을 없다. 나는 Array F (foreign pointer)을 가지고있다.

+3

무엇을 시도 했습니까? (배열에 'Array U DIM2 (Word8, Word8, Word8)'타입이 있다면 할 수 있습니까? 그렇다면 변환 함수 'Array U DIM3 Word8 -> Array U DIM2 (Word8, Word8, Word8) ?) – huon

+1

나는 내일 이것을 보려고 노력할 것이다. 그 동안 JP-repa에서 유용하다고 생각되는 이미지 표현 사이에 기본적인 변환이 있다면 패치를 보내주십시오. –

+0

@FalcoHirschenberger 오츠 (Otsu) thresholding을 완성 했습니까? 나는 그것을 원하지만 어떤 중복 작업도 피하고 싶다. –

답변

7

좋아, 몇 분을 찾았습니다. 아래에서는 4 가지 솔루션을 다루고 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을 구현하도록 선택했기 때문에 가능합니다.

당신은 당신은

는 당신이 실제로 요소 튜플로 DIM2 배열로 JP-바디 수리 스타일의 배열을 변환 할 수 있습니다 traverse를 사용하여 원하는 배열을 구축 할 수 있습니다 :

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-바디 수리가 언 박싱 배열을 제공하지 않음을 한탄. 다행히, 변환은 간단하다 :

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 

하지만 실제로는 형식이 잘못되었습니다. 그래서 인수를 이름을 변경하고 다시 정렬 할 수 있습니다 다음 (기존) foldAllS 작업과 잘 대조

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

: 우리의 새로운 배는 두 가지 중요한 특징을 가지고 어떻게

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

공지 사항. 결과 유형은 요소 유형과 일치 할 필요가 없으므로 히스토그램의 튜플로 시작할 수 있습니다. 두 번째로, 우리 버전의 fold는 인덱스를 전달합니다.이 튜플은 업데이트 할 튜플 (있는 경우)을 선택할 수있게 해줍니다.

당신은 게으르게 원하는 바디 수리 배열 형식을 획득하려면 최신 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 자동 thresholding 알고리즘을 구현하려고합니다. 귀하의 질문에 관해서,'repa-algorithms'의 알고리즘은'Array U DIM2 a' 형태의 mutichannel 이미지를 표현하고'rgb8OfFloat :: (Float, Float, Float) -> (Word8, Word8) 형식의 픽셀 변환 함수를 제공합니다. , Word8)'. –