प्रोफेसर ने एक SMatrix का उपयोग करके 2D गाऊसी कर्नेल का प्रदर्शन किया (नीचे चित्र देखें)। मैं इसी तरह से मनमाने आकार के 1D कर्नेल को लागू करने का प्रयास कर रहा हूं। मैंने नीचे दिए गए कोड की कोशिश की है और इसे शुरू करने के सही तरीके से ऑनलाइन कोई अच्छा संसाधन नहीं ढूंढ पा रहा हूं। प्रारंभ करने के बिंदु पर बहुत स्थिर तत्वों के साथ सभी उदाहरण स्थिर हैं।

begin
    G_1D(i, σ) = ℯ^(-(i^2)/(2*(σ^2)))/sqrt(2*π*(σ^2))
    G_2D(x, y, σ) = ℯ^(-((x^2)+(y^2))/(2*(σ^2)))/sqrt(2*π*(σ^2))
end
begin
    function gaussian_kernel_1D(n, σ = 1)
        if iseven(n)
            mid = n÷2
            kernel = SVector{n}(map(i -> G_1D(i, σ)), CartesianIndex(-mid:mid-1))
            kernel ./ sum(kernel)
            return kernel
        else
            mid = n÷2
            kernel = SVector{n}(map(i -> G_1D(i, σ)), CartesianIndex(-mid:mid))
            kernel ./ sum(kernel)
            return kernel
        end
    end
    
    function gaussian_kernel_2D(n, σ = 1)
        if iseven(n)
            mid = n÷2
            kernel = SMatrix{n,n}(map(x,y -> G_2D(x,y, σ)), CartesianIndices((-mid:mid-1, -mid:mid-1)))
            kernel ./ sum(kernel)
            return kernel
        else
            mid = n÷2
            kernel = SMatrix{n,n}(map(x,y -> G_2D(x,y, σ)), CartesianIndices((-mid:mid-1, -mid:mid-1)))
            kernel ./ sum(kernel)
            return kernel
        end
    end
end
  1. क्या SVector का उपयोग करना सही समाधान है? यदि हां, तो क्या आप इसे प्रारंभ करने के सही तरीके से मेरी सहायता कर सकते हैं?
  2. यदि SVector सही विचार नहीं है, तो आप क्या सुझाव देंगे?

गाऊसी कर्नेल फ़ंक्शन को कॉल करने पर त्रुटि विवरण यहां दिया गया है।

MethodError: no method matching (::Main.workspace68.var"#2#6"{Int64})()
Closest candidates are:
#2(!Matched::Any) at /Users/
map(::Main.workspace68.var"#2#6"{Int64})@abstractarray.jl:2247
gaussian_kernel_1D(::Int64, ::Int64)@Other: 10
gaussian_kernel_1D(::Int64)

मैं अपेक्षाकृत नया सीखने वाला हूं, इसलिए अगर कोड गलत है, तो यह बहुत मददगार होगा।

enter image description here

1
whyharsha 10 सितंबर 2020, 02:20

1 उत्तर

सबसे बढ़िया उत्तर

आपकी समस्या SVector के साथ नहीं है, लेकिन जिस तरह से आप G_1D को कॉल करते हैं, विशेष रूप से, आपको यहां एक त्रुटि मिलती है:

julia> CartesianIndex(-mid:mid)
ERROR: MethodError: no method matching CartesianIndex(::UnitRange{Int64})

आप CartesianIndices का उपयोग कर सकते हैं, लेकिन मुझे समझ नहीं आता कि आप ऐसा क्यों करेंगे। प्रसारण के साथ सीधे -mid:mid का प्रयोग करें। इस तरह:

G_1D.(-mid:mid, σ)

तो फिर

kernel = SVector{n}(G_1D.(-mid:mid, σ))

2D के लिए आप यह कर सकते हैं:

kernel = SMatrix{n,n}(G_2D.(-mid:mid, (-mid:mid)', σ))

हालाँकि, यहाँ एक और समस्या है:

kernel ./ sum(kernel)
return kernel

यह kernel का मान नहीं बदलता है। आप मूल रूप से ऐसा ही कर रहे हैं:

kernel_nonnormalized = kernel
kernel_normalized = kernel ./ sum(kernel)
return kernel_nonnormalized

अगर आप सिर्फ लिखते हैं

return kernel ./ sum(kernel)

तो आपको सामान्यीकृत मूल्य मिलता है।

क्या आप StaticArrays का उपयोग करने में उचित हैं, यह कहना थोड़ा कठिन है। आयाम छोटे होने चाहिए, और आदर्श रूप से उनके आकार को संकलन समय पर जाना जाना चाहिए, जबकि आपके कोड में यह रनटाइम पर निर्धारित किया जाता है। हालांकि यह कोई समस्या नहीं हो सकती है, जब तक कि यह एक अलग जगह पर होता है, उदाहरण के लिए आप गणना की शुरुआत में। बस इसे आजमाएं और देखें।

संपादित करें: BTW, यदि आपको मेरे ऐसा कहने से कोई आपत्ति नहीं है, तो आप अनावश्यक रूप से DRY (डोंट रिपीट योरसेल्फ) सिद्धांत का उल्लंघन कर रहे हैं, और एकाधिक प्रेषण का उपयोग करने से चूक रहे हैं। इससे बचने का एक तरीका यहां दिया गया है (हो सकता है कि यह इष्टतम न हो):

gauss(i, σ) = ℯ^(-(i^2)/(2*(σ^2)))/sqrt(2*π*(σ^2))
gauss(x, y, σ) = ℯ^(-((x^2)+(y^2))/(2*(σ^2)))/sqrt(2*π*(σ^2))

function makekernel(f, n, σ=1)
    ind = (0:n-1) .- (n÷2)
    kernel = SVector{n}(f.(ind, σ))
    return kernel ./ sum(kernel)
end

function makekernel(f, n::NTuple{2}, σ=1)
    ind1 = (0:n[1]-1) .- (n[1]÷2)
    ind2 = (0:n[2]-1) .- (n[2]÷2)
    kernel = SMatrix{n[1], n[2]}(f.(ind1, ind2', σ))
    return kernel ./ sum(kernel)
end

गॉस फ़ंक्शन के लिए आपको केवल एक नाम की आवश्यकता है, 1D और 2D संस्करणों के लिए अलग-अलग नामों की आवश्यकता नहीं है। साथ ही makekernel का दोनों मामलों में एक ही नाम हो सकता है। नाम के अंदर 1D और 2D के साथ अलग-अलग फ़ंक्शन नाम बनाने की आवश्यकता नहीं है।

यह भी ध्यान दें कि आपको सम और विषम लंबाई के लिए अलग कोड पथ की आवश्यकता नहीं है।

यहां बताया गया है कि आप उन्हें कैसे कॉल करेंगे:

kernel1D = makekernel(gauss, 7)  # here's 1D kernel
kernel2D = makekernel(gauss, (7, 6))  # here's a 7x6 2D kernel

अब gauss की तुलना में विभिन्न कार्यों का उपयोग करने के लिए भी जगह है, और आप इसे उच्च आयामों तक विस्तारित करने के लिए एक पैटर्न भी देखते हैं।

3
DNF 10 सितंबर 2020, 14:17