簡體   English   中英

Julia 從零開始實現卷積

[英]Implementing convolution from scratch in Julia

我正在嘗試在Julia中手動實現卷積。我對圖像處理或Julia不太熟悉,所以可能我咬得太多了。

無論如何,當我將此方法應用於 3*3 邊緣過濾器時edge = [0 -1 0; -1 4 -1; 0 -1 0] edge = [0 -1 0; -1 4 -1; 0 -1 0] edge = [0 -1 0; -1 4 -1; 0 -1 0]作為convolve(img, edge) ,我收到一條錯誤消息,指出我的值超出了 RGBA 類型的允許值。

代碼

function convolve(img::Matrix{<:Any}, kernel)
    (half_kernel_w, half_kernel_h) = size(kernel) .÷ 2
    (width, height) = size(img)
    cpy_im = copy(img)
    for row ∈ 1+half_kernel_h:height-half_kernel_h
        for col ∈ 1+half_kernel_w:width-half_kernel_w
            from_row, to_row = row .+ (-half_kernel_h, half_kernel_h)
            from_col, to_col = col .+ (-half_kernel_h, half_kernel_h)
            cpy_im[row, col] = sum((kernel .* RGB.(img[from_row:to_row, from_col:to_col])))
        end
    end
    cpy_im
end

錯誤(原創)

ArgumentError: element type FixedPointNumbers.N0f8 is an 8-bit type representing 256 values from 0.0 to 1.0, but the values (-0.0039215684f0, -0.007843137f0, -0.007843137f0, 1.0f0) do not lie within this range.
See the READMEs for FixedPointNumbers and ColorTypes for more information.

我能夠確定一個可能發生此類錯誤的簡單情況(白色像素被所有黑色像素包圍,反之亦然)。 我嘗試按照另一個 stackoverflow 問題的建議來“解決”這個問題,但我得到了更多關於Math on colors is deliberately undefined in ColorTypes, but see the ColorVectorSpace package.

嘗試應用其他 SO 問題的解決方案的代碼

function convolve(img::Matrix{<:Any}, kernel)
    (half_kernel_w, half_kernel_h) = size(kernel) .÷ 2
    (width, height) = size(img)
    cpy_im = copy(img)
    for row ∈ 1+half_kernel_h:height-half_kernel_h
        for col ∈ 1+half_kernel_w:width-half_kernel_w
            from_row, to_row = row .+ [-half_kernel_h, half_kernel_h]
            from_col, to_col = col .+ [-half_kernel_h, half_kernel_h]
            cpy_im[row, col] = sum((kernel .* RGB.(img[from_row:to_row, from_col:to_col] ./ 2 .+ 128)))
        end
    end
    cpy_im
end

對應錯誤

MethodError: no method matching +(::ColorTypes.RGBA{Float32}, ::Int64)
Math on colors is deliberately undefined in ColorTypes, but see the ColorVectorSpace package.

Closest candidates are:
+(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:591
+(!Matched::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:87
+(!Matched::ChainRulesCore.AbstractThunk, ::Any) at ~/.julia/packages/ChainRulesCore/a4mIA/src/tangent_arithmetic.jl:122

現在,我可以嘗試使用convert等,但是當我看大圖時,我開始想知道在 Julia 中解決這個問題的慣用方法是什么。 這就是我的問題。 如果您必須從頭開始手動實現卷積,那么這樣做的好方法是什么?

編輯:這是一個有效的實現,盡管它可能不是慣用的

function convolve(img::Matrix{<:Any}, kernel)
    (half_kernel_h, half_kernel_w) = size(kernel) .÷ 2
    (height, width) = size(img)
    cpy_im = copy(img)
    # println(Dict("width" => width, "height" => height, "half_kernel_w" => half_kernel_w, "half_kernel_h" => half_kernel_h, "row range" => 1+half_kernel_h:(height-half_kernel_h), "col range" => 1+half_kernel_w:(width-half_kernel_w)))
    for row ∈ 1+half_kernel_h:(height-half_kernel_h)
        for col ∈ 1+half_kernel_w:(width-half_kernel_w)
            from_row, to_row = row .+ (-half_kernel_h, half_kernel_h)
            from_col, to_col = col .+ (-half_kernel_w, half_kernel_w)
            vals = Dict()
            for method ∈ [red, green, blue, alpha]
                x = sum((kernel .* method.(img[from_row:to_row, from_col:to_col])))
                if x > 1
                    x = 1
                elseif x < 0
                    x = 0
                end
                vals[method] = x
            end
            cpy_im[row, col] = RGBA(vals[red], vals[green], vals[blue], vals[alpha])
        end
    end
    cpy_im
end

首先是報錯

colors 上的 Math 在 ColorTypes 中故意未定義,但請參閱 ColorVectorSpace package。

應該指導您閱讀ColorVectorSpace package 的文檔,您將在其中了解到using ColorVectorSpace現在將啟用 RGB 類型的數學運算。 (沒有默認支持是故意的,因為圖像處理社區處理 RGB 的方式在色度上是錯誤的。但每個人都同意不關心,因此 ColorVectorSpace package。)

第二,

ArgumentError:元素類型 FixedPointNumbers.N0f8 是一個 8 位類型,表示從 0.0 到 1.0 的 256 個值,但值(-0.0039215684f0、-0.007843137f0、-0.007843137f0、1.0f0)不在此范圍內。

表示您正在嘗試使用不支持此類值的元素類型N0f8編寫否定條目。 代替cpy_im = copy(img) ,考慮像cpy_im = [float(c) for c in img]這樣的東西,這將保證可以支持負值的浮點表示。

第三,我建議避免像RGB.(img...)這樣的步驟,因為您的 function 沒有任何其他內容可以解決圖像是數字、灰度還是顏色的問題。 從根本上說,您需要的唯一操作是標量乘法和加法,最好只一般地利用這兩個屬性來編寫您的算法。

Tim Holy 上面的回答是正確的——保持簡單,避免在不需要時依賴第三方包。

我可能會指出您可能沒有考慮過的另一種選擇是使用不同的算法。 您正在實施的是朴素的方法,而許多卷積例程針對不同的大小使用不同的算法,例如im2col和 Winograd(您可以查看這兩個,我有一個網站涵蓋了兩者背后想法)。

im2col例程可能值得做,因為基本上您可以將例程分成幾部分:

  • 展開圖像的所有“區域”以使用過濾器/內核進行點積,並將它們堆疊在一起成為一個矩陣。
  • 對展開的輸入和過濾器/內核進行矩陣乘法。
  • 將 output 卷回正確的形狀。

整體上可能更復雜,但每個部分都更簡單,因此您可能會發現這更容易做到。 矩陣乘法例程絕對很容易實現。 對於圖像和過濾器具有相同順序(即 NCHW 圖像和 FCHW 過濾器)的 1x1(單像素)卷積,第一步和最后一步是微不足道的,因為基本上不需要滾動/展開。

最后一點建議 - 從更簡單的開始並添加代碼來處理邊緣情況,使用卷積肯定會很麻煩。

希望這可以幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM