Canny edge detector: Difference between revisions

Content added Content deleted
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.
<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>
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 ⟶ 754:
 
<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>