Sobel kenar dedektörü


12

Göreviniz bir girdi görüntüsü alan bir program yazmak ve bir çıktı görüntüsü olmak için kenar algılaması ile çalıştırmaktır.

Kenar algılama aşağıdaki gibi çalışır (net değilse, sobel kenar algılamasına bakın ):

  • Bir pikselin değeri bir pikselin toplam parlaklığıdır, bu nedenle renkli ise, önce gri tonlamaya dönüştürmeniz gerekir (işleri basit ve golf yapabilmek için R, G ve B).
  • G formül x ve G, Y piksel p (i, j) şunlardır:
    • G x = -1 * p (i-1, j-1) - 2 * p (i-1, j) - 1 * p (i-1, j + 1) + 1 * p (i + 1, j -1) + 2 * p (i + 1, j) + 1 * p (i + 1, j + 1)
    • G y = -1 * p (i-1, j-1) - 2 * p (i, j-1) - 1 * p (i + 1, j-1) + 1 * p (i-1, j +1) + 2 * p (i, j + 1) + 1 * p (i + 1, j + 1)
  • Bu pikseldeki kenarın boyutu için değer şu şekildedir: √ (G x 2 + G y 2 )

Çıktı görüntüsü her piksel için √ (G x 2 + G y 2 ) kenarının gri skalası boyutundadır .

Bonuslar:

  • Daha küçük kenarları atlamak için kenar algılama devreye girmeden önce görüntüyü yumuşatmak için bir gauss bulanıklığı gerçekleştirin. Bu, sonuçta% -30 bonus verir.
  • Hesabın kenar açısını dikkate alın. Aynı gri tonlama değerini alarak ve arktan formülünden (G y / G x ) elde edilen açıyı kullanarak bir renk tekerleğinden renk ekleyerek çıktı pikseline biraz renk verirsiniz . Bu, sonuçta% -30'luk başka bir bonus verir.

Kurallar:

  • Kenar piksellerinin değerini atlayabilir ve siyah olarak ayarlayabilir veya görüntünün dışındaki herhangi bir piksel için 0 kullanabilirsiniz.
  • Çıkış görüntünüzün çoğu bilgisayarda açılabilecek bir görüntü biçiminde olması gerekir.
  • Çıktı diske yazılmalı veya bir dosyaya aktarılabilir olmalıdır.
  • Giriş, bir komut satırı bağımsız değişkeni olarak, görüntüye göreli bir yol şeklinde verilir veya komut satırından aktarılır.
  • Bu kod golf, bayt çok kısa kod kazanır!

Gauss bulanıklığını tam olarak belirleyebilir misiniz? Giriş gri tonlaması da var mı? Hayır ise, bu kenar algılamayı renkli görüntülere nasıl uygulamalıyız? Çıktı görüntüsünün girişle aynı boyuta sahip olması doğru mu, ancak giriş yalnızca iç piksellerde (sıfıra ayarladığımız görüntüde değil) gerçekleştiriliyor mu?
flawr

Computerphile'in kenar tespiti hakkındaki videoları gördünüz mü ? Orada bir bağlantı kokusunu alabiliyorum :)
GiantTree

@flawr Kenar algılaması için hangi gauss bulanıklığının iyi olduğunu test etmeliyim, bu yüzden iyi bir değerin ne olduğunu gerçekten bilmiyorum. Gauss bulanıklığı hakkında daha fazla bilgi . Giriş görüntüsü renklidir ve kenar algılamayı gerçekleştirmek istiyorsanız önce gri tonlamaya dönüştürmeniz gerekir. Kenar algılama ya iç piksellerde A: yapılır ve çıkış görüntüsünün dış 1 piksel kenarlığını siyaha, tüm piksellerde B: olarak ayarlarsınız ve görüntünün dışındaki pikseller için 0 değerini alırsınız.
vrwim

@GiantTree nooooooo video tamamen ilgili değil :)
vrwim

4
Bu neden oylandı? Çok geçerli bir soru gibi görünüyor.
Addison Crump

Yanıtlar:


13

J, 16616416415541451431414 bayt.

Çok fazla golf değil; Çoğunlukla uzun uygulamamı daralttım (aşağıya bakın), bu yüzden muhtemelen iyileştirmek için çok fazla alan var. BMP kütüphanesini kullanır. Sonucu dosyaya kaydeder o. Kenar piksellerini yalnızca tam 3x3 hücre kullanarak ele aldım, böylece son görüntünün genişliği ve yüksekliği 2 piksel daha küçüktür.

load'bmp'
S=:s,.0,.-s=:1 2 1
p=:([:*:[:+/[:,*)"2
'o'writebmp~256#.3#"0<.255<.%:(S&p+(|:S)&p)3 3,.;._3(3%~])+/"1(3#256)#:readbmp}:stdin''
exit''

Kullanımı:

echo 'image.bmp' | jconsole golf.ijs

Expanded:

load 'bmp'

sobel1 =: 3 3 $ 1 0 _1 2 0 _2 1 0 _1
NB. transposed
sobel2 =: |: sobel1
NB. read image
image =: readbmp }: stdin''
NB. convert default representation to R,G,B arrays
rgbimage =: (3 # 256) #: image
NB. convert to grayscale
greyimage =: 3 %~ (+/"1) rgbimage
NB. 3x3 cells around each pixel
cells =: 3 3 ,.;._3 greyimage
NB. multiply 3x3 cell by 3x3 sobel, then sum all values in it
partial =: 4 : '+/"1 +/"1 x *"2 y'
NB. square partial (vertical and horizontal) results, sum and root
combine =: [: %: *:@[ + *:@]
NB. limit RGB values to 255
limit =: 255 <. ]
newimage =: limit (sobel1&partial combine sobel2&partial) cells
NB. convert back to J-friendly representation
to_save =: 256 #. 3 #"0 <. newimage
to_save writebmp 'out.bmp'
NB. jconsole stays open by default
exit''

Örnek giriş ve çıkış:

orijinal Kenar algılama


Bu, ;._3alt dizi operatörünün güzel bir örneğidir . Bunları poluşturduktan sonra alt diziler üzerinde çalışmak üzere 2. sıraya sahip bir fiil tanımladığınızı fark ettim . Bunun yerine her alt dizide kesim yaptığınızda çalışabilirsiniz. İşinize dayalı olarak uygulamayı denemem 256#.3#"0<.255<.3 3((|:S)&*+&.*:&(+/)&,S&*);._3%&3(3#256)+/@#:. Bu toplam 126 bayta indirilmelidir.
mil

'o'writebmp~256#.3#"0<.255<.3 3(*+&.*:&(+/)&,(*|:))&((-,.0,.])1 2 1);._3%&3(3#256)+/@#:readbmp]stdin''Stdin'e sadece dosya adının girildiğini varsayarak 119 bayta kadar düştüm . Bunu, echo -nstdin'e fazladan bir yeni satır eklenmeyecek şekilde kullanarak yapabilirsiniz . Bilgisayarımda, bir betiğe borulu bir girdi kullanıldığında komut dosyası otomatik olarak çıkar; bu, eklemek zorunda olmadığım exit''ve fazladan 6 bayt kaydedebileceğim anlamına gelir , ancak bunun herkes için doğru olup olmadığından emin değilim.
mil

1

Python, 161 * 0.7 = 112.7 bayt

Gauss Bulanıklığı bonusu ile.

Yerleşik yöntemleri açıkça yasaklamadığınız için, işte OpenCV:

from cv2 import*
from numpy import*
g=GaussianBlur(cvtColor(imread(raw_input()),6),(3,3),sigmaX=1)
x,y=Sobel(g,5,1,0),Sobel(g,5,0,1)
imwrite('s.png',sqrt(x*x+y*y))

Bonus olmadan, 136 bayt

from cv2 import*
from numpy import*
g=cvtColor(imread(raw_input()),6)
x,y=Sobel(g,5,1,0),Sobel(g,5,0,1)
imwrite('s.png',sqrt(x*x+y*y))
  • Edit1: Adlandırılmış sabitleri değerleriyle değiştirdi.
  • Edit2: Yüklenen örnekler

orijinal süzülmüş


Örnek bir giriş ve çıkış görüntüsü verebilir misiniz?
R. Kap

@ R.Kap hiç olmadığı kadar iyi.
Karl Napf

0

MATLAB, 212 * 0,4 = 84,8 bayt

Filtre araç kutusunu ve HSV renk aralığını kullanma

function f(x);f=@(i,x)imfilter(i,x);s=@(x)fspecial(x);S=s('sobel');A=f(double(rgb2gray(imread(x)))/255,s('gaussian'));X=f(A,S);Y=f(A,S');imwrite(hsv2rgb(cat(3,atan2(Y,X)/pi/2+0.5,0*A+1,sqrt(X.^2+Y.^2))),'t.png')

veya dinsiz

function f(x)
f=@(i,x)imfilter(i,x);
s=@(x)fspecial(x);
S=s('sobel');
A=f(double(rgb2gray(imread(x)))/255,s('gaussian'));
X=f(A,S);
Y=f(A,S');
imwrite(hsv2rgb(cat(3,atan2(Y,X)/pi/2+0.5,0*A+1,sqrt(X.^2+Y.^2))),'t.png')

0

Love2D Lua, 466 Bayt

A=arg[2]i=love.image.newImageData q=math t=i(A)g=i(t:getWidth()-2,t:getHeight()-2)m={{-1,-2,-1},{0,0,0},{1,2,1}}M={{-1,0,1},{-2,0,2},{-1,0,1}}t:mapPixel(function(_,_,r,g,b)a=(r+g+b)/3 return a,a,a end)g:mapPixel(function(x,y)v=0 for Y=0,2 do for X=0,2 do v=v+(t:getPixel(x+X,y+Y)*m[Y+1][X+1])end end V=0 for Y=0,2 do for X=0,2 do V=V+(t:getPixel(x+X,y+Y)*M[Y+1][X+1])end end v=q.max(q.min(q.sqrt(V^2+v^2),255),0)return v,v,v end)g:encode('png',"o")love.event.quit()

Komut satırı girişini alır, Love2D appsdata klasörünüzün altındaki "o" adlı bir dosyaya çıkar. Love2D Dosyaları başka bir yere kaydetmenize izin vermez.

Hemen alabilirim gibi golfed, muhtemelen daha fazla golf olabilir.

Açıklaması

-- Assign the Input to A
A=arg[2]


-- Assign some macros to save FUTURE BYTES™
i=love.image.newImageData
q=math

-- t is the original image, g is the new output image. g is two pixels smaller, which is easier and better looking than a border.
t = i(A)
g = i(t:getWidth()-2,t:getHeight()-2)

-- m and M are our two sobel kernals. Fairly self explanitary.
m = {{-1,-2,-1}
    ,{0,0,0}
    ,{1,2,1}}

M = {{-1,0,1}
    ,{-2,0,2}
    ,{-1,0,1}}

-- Convert t to grayscale, to save doing this math later.
t:mapPixel(function(_,_,r,g,b)a=(r+g+b)/3 return a,a,a end)

-- Execute our kernals
g:mapPixel(function(x,y)
    -- v refers to the VERTICAL output of the Kernel m.
    v=0
    for Y=0,2 do
        for X=0,2 do
            v=v+(t:getPixel(x+X,y+Y)*m[Y+1][X+1])
        end
    end

    -- V is the HORIZONTAL of M
    V=0
    for Y=0,2 do
        for X=0,2 do
            V=V+(t:getPixel(x+X,y+Y)*M[Y+1][X+1])
        end
    end

    -- Clamp the values and sum them.
    v = q.max(q.min(q.sqrt(V^2 + v^2),255),0)
    -- Return the grayscale.
    return v,v,v
end)

-- Save, renaming the file. The golfed version just outputs as 'o'
g:encode('png',"S_".. A:gsub("(.*)%....","%1.png"))

-- Quit. Not needed, but I'm a sucker for self contained LOVE2D
love.event.quit()

Ölçek

Giriş Çıktı

Ve...

Puanımı gerçekten artırmasa da (daha da kötüsü yapar), renk tekerleğinin uygulandığı sürüm.

900-270 = 630 Bayt

A=arg[2]i=love.image.newImageData q=math t=i(A)g=i(t:getWidth()-2,t:getHeight()-2)m={{-1,-2,-1},{0,0,0},{1,2,1}}M={{-1,0,1},{-2,0,2},{-1,0,1}}function T(h,s,v)if s <=0 then return v,v,v end h,s,v=h*6,s,v/255 local c=v*s local x=(1-q.abs((h%2)-1))*c local m,r,g,b=(v-c),0,0,0 if h < 1 then r,g,b=c,x,0 elseif h < 2 then r,g,b=x,c,0 elseif h < 3 then r,g,b=0,c,x elseif h < 4 then r,g,b=0,x,c elseif h < 5 then r,g,b=x,0,c else r,g,b=c,0,x end return(r+m)*255,(g+m)*255,(b+m)*255 end t:mapPixel(function(_,_,r,g,b)a=(r+g+b)/3 return a,a,a end)g:mapPixel(function(x,y)v=0 for Y=0,2 do for X=0,2 do v=v+(t:getPixel(x+X,y+Y)*m[Y+1][X+1])end end V=0 for Y=0,2 do for X=0,2 do V=V+(t:getPixel(x+X,y+Y)*M[Y+1][X+1])end end h=v H=V v=q.max(q.min(q.sqrt(V^2+v^2),255),0)h=q.atan2(H,h)/q.pi*2 return T(h,1,v,255)end)g:encode('png',"S_".. A:gsub("(.*)%....","%1.png"))G=love.graphics.newImage(g)love.event.quit()

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.