เครื่องตรวจจับขอบ Sobel


12

งานของคุณคือการเขียนโปรแกรมที่ถ่ายภาพอินพุทและเรียกใช้งานผ่านการตรวจจับขอบเพื่อให้ได้ภาพออกมา

การตรวจจับขอบทำงานดังต่อไปนี้ (หากไม่ชัดเจนโปรดดูการตรวจจับขอบ sobel ):

  • ค่าสำหรับพิกเซลคือความสว่างทั้งหมดของพิกเซลดังนั้นหากเป็นสีคุณจะต้องแปลงเป็นสีเทาก่อน (เพื่อให้สิ่งต่าง ๆ เรียบง่ายและเล่นกอล์ฟได้คุณสามารถใช้ค่าเฉลี่ยสำหรับ R, G และ B)
  • สูตรสำหรับ G xและ G yสำหรับพิกเซล p (i, j)คือ:
    • 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)
  • ค่าของขนาดของขอบที่พิกเซลนั้นคือ: √ (G x 2 + G y 2 )

ภาพที่ส่งออกสำหรับแต่ละพิกเซลขนาดของขอบ√ (G x 2 + G y 2 ) เป็นเฉดสีเทา

โบนัส:

  • ทำการเบลอเกาส์เพื่อทำให้ภาพราบรื่นขึ้นก่อนที่จะทำการตรวจจับขอบเพื่อไม่ให้ขอบเล็กลง สิ่งนี้ให้โบนัส -30% ในผลลัพธ์สุดท้าย
  • พิจารณามุมของขอบในบัญชี คุณให้พิกเซลเอาต์พุตบางสีโดยใช้ค่าเฉดสีเทาเท่ากันและเพิ่มสีจากวงล้อสีโดยใช้มุมที่ได้จากสูตรอาร์คตัน (G y / G x ) สิ่งนี้จะให้โบนัสเพิ่มอีก -30% จากผลลัพธ์สุดท้าย

กฎ:

  • คุณอาจละเว้นค่าสำหรับ edgepixels และตั้งค่าเป็นสีดำหรือคุณอาจใช้ 0 สำหรับพิกเซลใด ๆ ที่อยู่นอกภาพ
  • รูปภาพ ouput ของคุณต้องอยู่ในรูปแบบภาพที่สามารถเปิดได้ในคอมพิวเตอร์ส่วนใหญ่
  • เอาต์พุตต้องถูกเขียนไปยังดิสก์หรือสามารถไพพ์ไปยังไฟล์ได้
  • อินพุตถูกกำหนดเป็นอาร์กิวเมนต์ commandline ในรูปแบบของพา ธ ที่สัมพันธ์กับรูปภาพหรือไพพ์จาก commandline
  • นี่คือรหัสกอล์ฟดังนั้นรหัสที่สั้นที่สุดในหน่วยไบต์ชนะ!

คุณสามารถระบุ Gaussian Blur ได้ไหม? อินพุทเป็นสีเทาหรือไม่ถ้าไม่เราจะใช้การตรวจจับขอบนี้กับภาพสีได้อย่างไร? ถูกต้องหรือไม่ว่าภาพที่ส่งออกมีขนาดที่แน่นอนเหมือนกับอินพุต แต่อินพุตนั้นดำเนินการกับพิกเซลด้านในเท่านั้น (ไม่ใช่ภาพที่เราตั้งค่าเป็นศูนย์) ใช่หรือไม่
ข้อบกพร่อง

คุณเคยเห็นวิดีโอเกี่ยวกับการตรวจจับขอบจากComputerphileหรือไม่? ผมได้กลิ่นการเชื่อมต่อมี :)
GiantTree

@flawr ฉันต้องทดสอบสิ่งที่ gaussian blur ดีสำหรับการตรวจจับขอบดังนั้นฉันไม่รู้จริง ๆ ว่าอะไรคือค่าที่ดี เพิ่มเติมเกี่ยวกับ Gaussian Blur ที่นี่ ภาพอินพุตเป็นสีและคุณจะต้องแปลงเป็นสีเทาก่อนหากคุณต้องการทำการตรวจจับขอบ การตรวจจับขอบจะดำเนินการ A: กับพิกเซลด้านในและคุณตั้งค่าขอบด้านนอก 1px ของรูปภาพที่ส่งออกเป็นสีดำหรือ B: บนพิกเซลทั้งหมดและคุณใช้ 0 เป็นค่าสำหรับพิกเซลใด ๆ ที่อยู่นอกภาพ
vrwim

@GiantTree nooooooo วิดีโอไม่เกี่ยวข้องโดยสิ้นเชิง :)
vrwim

4
ทำไมสิ่งนี้ถึงถูกโหวต? ดูเหมือนว่าจะเป็นคำถามที่ถูกต้องสมบูรณ์
Addison Crump

คำตอบ:


13

J, 166 164 161 154 150 144 143 ไบต์

ไม่เล่นกอล์ฟมากเกินไป ฉันส่วนใหญ่ยุบการใช้งานอีกต่อไปของฉัน (ดูด้านล่าง) ดังนั้นอาจมีห้องจำนวนมากสำหรับการปรับปรุง ใช้ไลบรารี BMP oบันทึกผลในแฟ้ม ฉันจัดการ edgepixels โดยใช้เซลล์ 3x3 เต็มรูปแบบเท่านั้นดังนั้นภาพสุดท้ายจึงมีความกว้างและความสูงน้อยกว่า 2 พิกเซล

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

การใช้งาน:

echo 'image.bmp' | jconsole golf.ijs

ขยาย:

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

ตัวอย่างอินพุตและเอาต์พุต:

เป็นต้นฉบับ การตรวจจับขอบ


นี่เป็นตัวอย่างที่ดีของ;._3โอเปอเรเตอร์ย่อย ฉันสังเกตเห็นว่าคุณได้นิยามคำกริยาที่pมีอันดับ 2 เพื่อใช้งานบน subarrays หลังจากที่คุณสร้างมันขึ้นมา คุณสามารถทำงานแทนในแต่ละ subarray เมื่อคุณตัด 256#.3#"0<.255<.3 3((|:S)&*+&.*:&(+/)&,S&*);._3%&3(3#256)+/@#:ลองของฉันที่ดำเนินการนั้นขึ้นอยู่กับการทำงานของคุณคือ ที่ควรจะลงรวมถึง 126 ไบต์
ไมล์

ฉันได้มันลงไปที่ 119 bytes โดย'o'writebmp~256#.3#"0<.255<.3 3(*+&.*:&(+/)&,(*|:))&((-,.0,.])1 2 1);._3%&3(3#256)+/@#:readbmp]stdin''สมมติว่ามีเพียงชื่อไฟล์เท่านั้นที่ป้อนเข้า stdin คุณสามารถทำได้โดยใช้echo -nเพื่อไม่ให้มีการขึ้นบรรทัดใหม่ใน stdin ในคอมพิวเตอร์ของฉันสคริปต์จะออกโดยอัตโนมัติเมื่อใช้อินพุต piped กับสคริปต์ซึ่งหมายความว่าฉันไม่จำเป็นต้องรวมexit''และสามารถบันทึกเพิ่มอีก 6 ไบต์ แต่ฉันไม่แน่ใจว่าสิ่งนี้เป็นจริงสำหรับทุกคนหรือไม่
ไมล์

1

Python, 161 * 0.7 = 112.7 ไบต์

ด้วยโบนัส Gaussian Blur

เนื่องจากคุณไม่ได้ห้ามวิธีการในตัวไว้อย่างชัดเจนนี่คือ 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))

ไม่มีโบนัส 136 ไบต์

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))
  • แก้ไข 1: แทนที่ค่าคงที่ของชื่อด้วยค่าของมัน
  • แก้ไข 2: ตัวอย่างที่อัปโหลด

เป็นต้นฉบับ กรอง


คุณสามารถให้ภาพตัวอย่างและภาพออกได้หรือไม่?
R. Kap

@ R.Kap ดีกว่าไม่สาย
Karl Napf

0

MATLAB, 212 * 0.4 = 84.8 ไบต์

การใช้กล่องเครื่องมือตัวกรองและพื้นที่สี 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')

หรือไม่ดี

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

รับอินพุตบรรทัดคำสั่งเอาต์พุตไปยังไฟล์ชื่อ "o" ภายใต้โฟลเดอร์ Love2D appsdata ของคุณ Love2D ไม่ให้คุณบันทึกไฟล์ได้ทุกที่

พอฉันเล่นกอล์ฟได้ฉันก็อาจจะเล่นกอล์ฟต่อไปได้

อธิบาย

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

ทดสอบ

อินพุต เอาท์พุต

และ...

แม้ว่ามันจะไม่ปรับปรุงคะแนนของฉัน (ทำให้แย่ลง) แต่นี่เป็นเวอร์ชั่นที่มีวงล้อสีนำมาใช้

900 - 270 = 630 ไบต์

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

ป้อนคำอธิบายรูปภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.