Detektor tepi sobel

12

Tugas Anda adalah menulis sebuah program yang mengambil gambar input dan menjalankannya melalui deteksi tepi untuk menjadi gambar keluaran.

Deteksi tepi berfungsi sebagai berikut (jika tidak jelas, lihat deteksi tepi sobel ):

  • Nilai piksel adalah kecerahan total piksel, jadi jika warnanya berwarna, Anda harus mengonversinya menjadi skala abu-abu terlebih dahulu (untuk menjaga hal-hal sederhana dan golf-bisa, Anda dapat mengambil nilai rata-rata untuk R, G dan B).
  • Rumus untuk G x dan G y untuk piksel p (i, j) adalah:
    • 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)
  • Nilai untuk ukuran edge pada pixel tersebut adalah: √ (G x 2 + G y 2 )

Gambar output untuk setiap piksel ukuran tepi √ (G x 2 + G y 2 ) sebagai skala abu-abu.

Bonus:

  • Lakukan gaussian blur untuk menghaluskan gambar sebelum deteksi tepi dilakukan, untuk menghilangkan tepi yang lebih kecil. Ini memberikan bonus -30% pada hasil akhirnya.
  • Ambil sudut dari tepi di akun. Anda memberi piksel keluaran beberapa warna, dengan mengambil nilai skala abu-abu yang sama dan menambahkan warna dari roda warna menggunakan sudut yang diperoleh dari rumus arctan (G y / G x ). Ini memberikan bonus lain sebesar -30% pada hasil akhirnya.

Aturan:

  • Anda dapat menghilangkan nilai edgepixels, dan mengaturnya menjadi hitam, atau Anda dapat menggunakan 0 untuk piksel di luar gambar.
  • Gambar ouput Anda harus dalam format gambar yang dapat dibuka di sebagian besar komputer.
  • Keluaran harus ditulis ke disk atau dapat dikirimkan ke file.
  • Input diberikan sebagai argumen baris perintah, dalam bentuk jalur relatif ke gambar, atau disalurkan dari baris perintah.
  • Ini kode golf, jadi kode terpendek dalam byte menang!
vrwim
sumber
Bisakah Anda menentukan gaussian blur dengan tepat? Apakah input grayscale juga, jika tidak, bagaimana kita menerapkan deteksi tepi ini ke gambar berwarna? Apakah benar bahwa gambar keluaran memiliki ukuran yang sama persis dengan input, tetapi input hanya dilakukan pada piksel bagian dalam (bukan yang kita atur ke nol)?
flawr
Pernahkah Anda melihat video tentang deteksi tepi dari Computerphile ? Saya dapat mencium koneksi di sana :)
GiantTree
@ flawr Saya harus menguji gaussian blur apa yang baik untuk deteksi tepi, jadi saya tidak benar-benar tahu apa nilai yang baik. lebih lanjut tentang Gaussian blur di sini . Gambar input berwarna, dan Anda harus mengubahnya menjadi skala abu-abu terlebih dahulu jika Anda ingin melakukan deteksi tepi. Deteksi tepi dilakukan baik A: pada piksel bagian dalam, dan Anda menetapkan batas 1px luar gambar output menjadi hitam, atau B: pada semua piksel, dan Anda mengambil 0 sebagai nilai untuk piksel di luar gambar.
vrwim
@GiantTree nooooooo videonya sama sekali tidak terkait :)
vrwim
4
Mengapa ini tidak dipilih? Sepertinya itu pertanyaan yang sangat valid.
Addison Crump

Jawaban:

13

J, 166 164 161 154 150 144 143 byte.

Tidak bermain golf terlalu banyak; Saya sebagian besar menciutkan implementasi saya yang lebih lama (lihat di bawah), jadi mungkin ada banyak ruang untuk perbaikan. Menggunakan perpustakaan BMP. Menghemat menghasilkan file o. Saya menangani edgepixels dengan hanya menggunakan sel 3x3 penuh, sehingga gambar akhir memiliki lebar dan tinggi lebih kecil 2 piksel.

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''

Pemakaian:

echo 'image.bmp' | jconsole golf.ijs

Diperluas:

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''

Input dan output sampel:

Asli Deteksi tepi

Adrian17
sumber
Ini adalah contoh yang bagus dari ;._3operator subarray. Saya perhatikan Anda mendefinisikan kata kerja pdengan peringkat 2 untuk beroperasi pada subarrays setelah Anda membuatnya. Sebagai gantinya Anda bisa beroperasi pada setiap subarray saat Anda memotong. Usaha saya menerapkannya berdasarkan pekerjaan Anda 256#.3#"0<.255<.3 3((|:S)&*+&.*:&(+/)&,S&*);._3%&3(3#256)+/@#:. Itu harus membawanya ke total 126 byte.
mil
Saya sudah turun ke 119 byte dengan 'o'writebmp~256#.3#"0<.255<.3 3(*+&.*:&(+/)&,(*|:))&((-,.0,.])1 2 1);._3%&3(3#256)+/@#:readbmp]stdin''asumsi bahwa hanya nama file yang diinput pada stdin. Anda dapat melakukan ini menggunakan echo -nsehingga baris baru tambahan tidak termasuk dalam stdin. Di komputer saya, skrip keluar secara otomatis saat menggunakan input pipa ke skrip yang berarti saya tidak harus menyertakan exit''dan dapat menyimpan 6 byte tambahan, tetapi saya tidak yakin apakah ini benar untuk semua.
mil
1

Python, 161 * 0.7 = 112.7 byte

Dengan bonus Gaussian Blur.

Karena Anda tidak secara eksplisit melarang metode bawaan, berikut adalah 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))

Tanpa bonus, 136 byte

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))
  • Sunting1: Mengganti konstanta yang dinamai dengan nilainya.
  • Sunting2: Sampel yang diunggah

asli tersaring

Karl Napf
sumber
Bisakah Anda memberikan sampel input dan output gambar?
R. Kap
@ R.Kap lebih baik terlambat daripada tidak sama sekali.
Karl Napf
0

MATLAB, 212 * 0.4 = 84.8 byte

Menggunakan kotak alat filter dan ruang warna HSV

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')

atau ungolfed

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')
Jonas
sumber
0

Love2D Lua, 466 Bytes

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()

Mengambil input baris perintah, menghasilkan file bernama "o" di bawah folder data Love2D apps Anda. Love2D tidak akan membiarkan Anda menyimpan file di tempat lain.

Hampir seperti golf yang saya bisa dapatkan, mungkin bisa golf lebih jauh.

Dijelaskan

-- 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()

Uji

Memasukkan Keluaran

Dan...

Meskipun itu tidak benar-benar meningkatkan skor saya (Membuatnya lebih buruk), berikut adalah versi dengan roda warna yang diimplementasikan.

900 - 270 = 630 Bytes

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()

masukkan deskripsi gambar di sini

ATaco
sumber