Canny edge detector: Difference between revisions

Content added Content deleted
Line 677: Line 677:
Edge and non-edge points are represented as zeros and ones respectively. Edges are sets of connected points. Edge points are considered to be connected if within a 3X3 region (or if they are connected to a common third edge point). Edges are represented as points having a common unique identifier.
Edge and non-edge points are represented as zeros and ones respectively. Edges are sets of connected points. Edge points are considered to be connected if within a 3X3 region (or if they are connected to a common third edge point). Edges are represented as points having a common unique identifier.
<lang J>
<lang J>

... implementation goes here ...
NB. 2D convolution, filtering, ...

convolve =: 4 : 'x apply (($x) partition y)'
partition =: 4 : '2 0 3 1 |: ((1{x) ([+\]) (2 0 1|: ((0{x) ([+\]) y)))'
apply =: 4 : '+/"1 (+/"2 (x *"2 y))'
addborder =: (0&,@|:@|.)^:4
normalize =: ]%+/@,
resample =: 4 : '|: (1{-x)(+/%#)\ |: (0{-x)(+/%#)\ y'
crop =: 4 : 0
'h w h0 w0' =: x
|: w{. w0}. |: h{. h0}. y
)
max3x3 =: 3 : '(1{1{y>0) * (>./,y)'"2
attach =: 3 : 'max3x3 (3 3 partition (addborder y))'
unique =: 3 : 'y*i.$y'
connect =: 4 : 'attach^:x unique y'

canny =: 3 : 0
image0 =: y

NB. Step 1 - gaussian smoothing

NB. Gaussian kernel (from Wikipedia article)
<] gaussianKernel =. 5 5$2 4 5 4 2 4 9 12 9 4 5 12 15 12 5 4 9 12 9 4 2 4 5 4 2
gaussianKernel =. gaussianKernel % 159
image1 =: gaussianKernel convolve image0

NB. Step 2 - gradient

<] gradientKernel =. 3 3$0 _1 0 0j_1 0 0j1 0 1 0
image2 =: gradientKernel convolve image1

NB. Step 3 - edge detection

NB. find the octant (eighth of circle) in which the gradient lies
octant =: 3 : '4|(>.(_0.5+((4%(o. 1))*(12&o. y))))'
<(i:6)(4 : 'octant (x j. y)')"0/(i:6)

NB. is this gradient greater than [the projection of] a neighbor?
greaterThan =: 4 : ' (9 o.((x|.y)%y))<1'

NB. is this gradient the greatest of immmediate colinear neighbore?
greatestOf =: 4 : '(x greaterThan y) *. ((-x) greaterThan y)'

NB. relative address of neighbor relevant to grad direction
krnl0 =: _1 0
krnl1 =: _1 _1
krnl2 =: 0 _1
krnl3 =: 1 _1
og =: octant image2

NB. mask for maximum gradient colinear with gradient
ok0 =: (0=og) *. krnl0 greatestOf image2
ok1 =: (1=og) *. krnl1 greatestOf image2
ok2 =: (2=og) *. krnl2 greatestOf image2
ok3 =: (3=og) *. krnl3 greatestOf image2
image3 =: image2 *. (ok0 +. ok1 +. ok2 +. ok3)

NB. Step 4 - Weak edge suppression

NB. weak, strong threshholds
NB. TODO: parameter picker algorithm or helper
threshholds =: 1e14 1e15
nearbyKernel =: 3 3 $ 4 1 4 # 1 0 1
magnitude =. 10&o. image3
weak =: magnitude > 0{threshholds
strong =: magnitude > 1{threshholds
strongs =: addborder (nearbyKernel convolve strong) > 0
image4 =: strong +. (weak *. strongs)
)

}</lang>
}</lang>
The above implementation solves the 'inner problem' of Canny Edge Detection fully in the J language, with no external dependencies. Standard libraries provide necessary additional support including interfaces to image file formats and graphic displays.
The above implementation solves the 'inner problem' of Canny Edge Detection fully in the J language, with no external dependencies. Standard libraries provide necessary additional support including interfaces to image file formats and graphic displays.
Line 683: Line 754:


<lang J>
<lang J>
1!:44'D:/rosettacode/canny'
... usage goes here …
load'canny.ijs'

NB. viewers

require'viewmat plot'
view =: (16b010101*i.256)&viewmat
splot =: 'surface;mesh 0'&plot

NB. image file importers/exporters

require'png jpeg bmp'
NB. image =: readjpeg 'camille.jpg'
NB. image =: readbmp 'chess.bmp'
NB. image =: readpng 'boat1.png'
NB. image =: readpng 'valve.png'
NB. image =: readjpeg 'lena.jpg'
NB. from http://people.sc.fsu.edu/~jburkardt/data/pgmb/pgmb.html,
NB> distributed under the GNU LGPL license.
image =: readpng 'bird.png'

NB. select (or combine) from color channels
NB. if original image is grayscale, take any color channel
red =: <. image % 65538
green =: 256 | <. image % 256
blue =: 256 | image
image =: blue

NB. detect the edges

edges =: canny image
view 1-edges
viewmat 1000 connect edges
</lang>
</lang>