Canny edge detector: Difference between revisions
Content added Content deleted
m (→{{header|J}}) |
|||
Line 681: | Line 681: | ||
</ul> |
</ul> |
||
<lang J>NB. 2D convolution, filtering, ... |
|||
<lang J> |
|||
NB. 2D convolution, filtering, ... |
|||
convolve =: 4 : 'x apply (($x) partition y)' |
convolve =: 4 : 'x apply (($x) partition y)' |
||
partition=: 4 : '2 1 3 0 |: (1{x) ]\ 2 1 0 |: (0{x) ]\ y' |
|||
partition =: 4 : '2 0 3 1 |: ((1{x) ([+\]) (2 0 1|: ((0{x) ([+\]) y)))' |
|||
apply=: 4 :'+/+/x*y' |
|||
apply =: 4 : '+/"1 (+/"2 (x *"2 y))' |
|||
max3x3 =: 3 : '(1{1{y>0) * (>./,y)'"2 |
|||
partition=: 2 1 3 0 |: {:@[ ]\ 2 1 0 |: {.@[ ]\ ] |
|||
apply=: [: +/ [: +/ * |
|||
max3x3 =: 3 : '(0<1{1{y) * (>./>./y)' |
|||
addborder =: (0&,@|:@|.)^:4 |
addborder =: (0&,@|:@|.)^:4 |
||
normalize =: ]%+/@, |
normalize =: ]%+/@, |
||
resample =: 4 : '|: (1{-x)(+/%#)\ |: (0{-x)(+/%#)\ y' |
resample =: 4 : '|: (1{-x)(+/%#)\ |: (0{-x)(+/%#)\ y' |
||
attach =: 3 : 'max3x3 (3 3 partition (addborder y))' |
|||
unique =: 3 : 'y*i.$y' |
|||
connect =: 3 : 'attach^:_ unique y' |
|||
NB. on low memory devices, cropping may be needed |
|||
crop =: 4 : 0 |
crop =: 4 : 0 |
||
'h w h0 w0' =: x |
'h w h0 w0' =: x |
||
|: w{. w0}. |: h{. h0}. y |
|: w{. w0}. |: h{. h0}. y |
||
) |
) |
||
NB. on small screen devices, image may need to be expanded for viewing |
|||
attach =: 3 : 'max3x3 (3 3 partition (addborder y))' |
|||
inflate1 =: 4 : 0 |
|||
'h w' =: $y |
|||
r =: ,y |
|||
octant =: 3 : '4|(>.(_0.5+((4%(o. 1))*(12&o. y))))' NB. eighth of circle |
|||
c =: #r |
|||
rr =: (c$x) # r |
|||
(h,x*w)$rr |
|||
) |
|||
inflate =: 4 : '|: x inflate1 (|: x inflate1 y)' |
|||
NB. Step 1 - gaussian smoothing |
NB. Step 1 - gaussian smoothing |
||
step1 =: 3 : 0 |
|||
NB. Gaussian kernel (from Wikipedia article) |
NB. Gaussian kernel (from Wikipedia article) |
||
gaussianKernel = |
<] 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 |
|||
gaussianKernel convolve y |
|||
) |
|||
NB. Step 2 - gradient |
NB. Step 2 - gradient |
||
step2 =: 3 : 0 |
|||
gradientKernel = |
<] gradientKernel =: 3 3$0 _1 0 0j_1 0 0j1 0 1 0 |
||
gradientKernel convolve y |
|||
) |
|||
NB. Step 3 - edge detection |
NB. Step 3 - edge detection |
||
step3 =: 3 : 0 |
|||
NB. find the octant (eighth of circle) in which the gradient lies |
|||
NB. test pattern <(i:6)(4 : 'octant (x j. y)')"0/(i:6) |
|||
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? |
NB. is this gradient greater than [the projection of] a neighbor? |
||
greaterThan =: 4 : ' (9 o.((x|.y)%y))<1' |
greaterThan =: 4 : ' (9 o.((x|.y)%y))<1' |
||
NB. is this gradient the greatest of immmediate colinear neighbore? |
NB. is this gradient the greatest of immmediate colinear neighbore? |
||
greatestOf =: 4 : '(x greaterThan y) *. ((-x) greaterThan y)' |
greatestOf =: 4 : '(x greaterThan y) *. ((-x) greaterThan y)' |
||
NB. find the octant (eighth of circle) in which the gradient lies |
|||
og =: octant image2 |
|||
NB. relative address of neighbor, per gradient direction |
|||
nbr =: 4 2 $ _1 0, _1 _1, 0 _1, 1 _1 |
|||
NB. relative address of neighbor relevant to grad direction |
|||
NB. mask for maximum colinear gradient |
|||
krnl0 =. _1 0 |
|||
ok0 =: (0=og) *. (0{nbr) greatestOf image2 |
|||
krnl1 =. _1 _1 |
|||
ok1 =: (1=og) *. (1{nbr) greatestOf image2 |
|||
krnl2 =. 0 _1 |
|||
ok2 =: (2=og) *. (2{nbr) greatestOf image2 |
|||
krnl3 =. 1 _1 |
|||
ok3 =: (3=og) *. (3{nbr) greatestOf image2 |
|||
image3 =: image2 *. (ok0 +. ok1 +. ok2 +. ok3) |
|||
NB. Step 4 - Weak edge suppression |
|||
image =. y |
|||
og =. octant image |
|||
NB. mask for maximum gradient colinear with gradient |
|||
ok0 =. (0=og) *. krnl0 greatestOf image |
|||
ok1 =. (1=og) *. krnl1 greatestOf image |
|||
ok2 =. (2=og) *. krnl2 greatestOf image |
|||
ok3 =. (3=og) *. krnl3 greatestOf image |
|||
image *. (ok0 +. ok1 +. ok2 +. ok3) |
|||
) |
|||
NB. Step 4 - Weak edge suppression |
|||
step4 =: 3 : 0 |
|||
magnitude =. 10&o. y |
|||
NB. weak, strong threshholds |
NB. weak, strong threshholds |
||
NB. TODO: parameter picker algorithm or helper |
|||
threshholds =. 1e14 1e15 |
threshholds =. 1e14 1e15 |
||
nearbyKernel = |
nearbyKernel =. 3 3 $ 4 1 4 # 1 0 1 |
||
magnitude =. 10&o. image3 |
|||
weak =. magnitude > 0{threshholds |
weak =. magnitude > 0{threshholds |
||
strong =. magnitude > 1{threshholds |
strong =. magnitude > 1{threshholds |
||
strongs =. addborder (nearbyKernel convolve strong) > 0 |
strongs =. addborder (nearbyKernel convolve strong) > 0 |
||
strong +. (weak *. strongs) |
|||
) |
|||
NB. |
NB. find the edges |
||
step5 =: connect |
|||
canny =: 3 : 0 |
|||
image5 =: connect image4 |
|||
image =. y |
|||
image =. step1 image |
|||
image =. step2 image |
|||
image =. step3 image |
|||
image =. step4 image |
|||
image =. step5 image |
|||
) |
) |
||
</lang> |
|||
<p>The above implementation solves the 'inner problem' of Canny Edge Detection in the J language, with no external dependencies. Standard libraries provide additional support including interfaces to image file formats and graphic displays. </p> |
|||
</lang> |
|||
<p>Image file libraries for different image formats import into and export from a generalized data structure, an array of pixels with three or four color channels. The following code invokes these standard libraries, and also converts between the import format and the monochromatic representation used here for edge detection.</p> |
|||
<p>The above implementation solves the 'inner problem' of Canny Edge Detection in the J language, with no external dependencies. J's Qt IDE provides additional support including interfaces to image file formats, graphic displays, and the user. The following code exercises these features</p> |
|||
<p>The file 'valve.png' referenced in this code is from one of several Wikipedia articles on edge detection. It can be viewed at [https://upload.wikimedia.org/wikipedia/commons/2/2e/Valve_gaussian_%282%29.PNG[https://upload.wikimedia.org/wikipedia/commons/2/2e/Valve_gaussian_%282%29.PNG]]</p> |
<p>The file 'valve.png' referenced in this code is from one of several Wikipedia articles on edge detection. It can be viewed at [https://upload.wikimedia.org/wikipedia/commons/2/2e/Valve_gaussian_%282%29.PNG[https://upload.wikimedia.org/wikipedia/commons/2/2e/Valve_gaussian_%282%29.PNG]]</p> |
||
<lang J> |
<lang J> |
||
require 'gl2' |
|||
NB. viewers |
|||
coclass 'edge' |
|||
require'viewmat' |
|||
coinsert'jgl2' |
|||
view =: (16b010101*i.256)&viewmat |
|||
PJ=: jpath '~Projects/edges/' NB. optionally install and run as project under IDE |
|||
NB. image file importers |
|||
load PJ,'canny.ijs' |
|||
require'png jpeg bmp' |
|||
run=: 3 : 0 |
|||
NB. sample images |
|||
wd 'pc form;pn canny' |
|||
NB. image =: readbmp 'chess.bmp' |
|||
wd 'cc txt static;cn "Canny in J";' |
|||
NB. image =: readpng 'boat1.png' |
|||
wd 'cc png isidraw' |
|||
NB. image =: readjpeg 'lena.jpg' |
|||
wd 'cc inc button;cn "Next";' |
|||
wd 'pshow' |
|||
NB. select or combine from color channels |
|||
glclear'' |
|||
NB. if original image is grayscale, take any color channel |
|||
image =: readimg_jqtide_ PJ,'valve.png' |
|||
red =: <. image % (256^2) |
|||
image =: 240 360 120 150 crop image |
|||
edges =: canny 256 | image |
|||
ids =: }. ~.,edges |
|||
image =: blue |
|||
nids =: # ids |
|||
case =: 0 |
|||
) |
|||
form_inc_button =: 3 : 0 |
|||
NB. detect the edges |
|||
select. case |
|||
case. 0 do. |
|||
wd 'set txt text "original image";' |
|||
img =: 255 setalpha image |
|||
case. 1 do. |
|||
wd 'set txt text "points on edges";' |
|||
img =: edges>0 |
|||
img =: 1-img |
|||
img =: img * (+/ 256^i.3) * 255 |
|||
img =: 255 setalpha img |
|||
ix =: 0 |
|||
case. 2 do. |
|||
wd 'set txt text "... iterating over edges ...";' |
|||
img =: edges=ix{ids |
|||
whilst. (num<75) *. (ix<nids) do. |
|||
img =: edges=ix{ids |
|||
num =: +/,img |
|||
ix=:>:ix |
|||
if. ix=#ids do. case=:_1 end. |
|||
end. |
|||
img =: 1-img |
|||
img =: img * (+/ 256^i.3) * 255 |
|||
img =: 255 setalpha img |
|||
ix =: (#ids)|(>:ix) |
|||
end. |
|||
if. case<2 do. case =: >: case end. |
|||
glfill 255 128 255 |
|||
glpixels 0 0,(|.$img), ,img |
|||
glpaint'' |
|||
) |
|||
form_close=: exit bind 0 |
|||
load'canny.ijs' |
|||
edges =: canny image |
|||
viewmat edges |
|||
NB. get identifiers of edges |
|||
run''</lang> |
|||
NB. show edge identifiers |
|||
}.~.,edges |
|||
1 13963 12701 2564 8279 5752 60 3262 114 7175 13520 221 860 236 12958 1220 14609 14217 18983 47035 4648 3386 22878 11578 7160 12015 8285 7791 12257 9550 10363 11360 12901 12080 17305 13895 17056 30593 24059 17064 27897 27920 19674 19824 23010 17118 17995 2... |
|||
NB. how many edges? |
|||
#~.,edges |
|||
895 |
|||
NB. display part of one |
|||
</lang> |
|||
Image uploads [temporarily?] blocked; fall back to ascii art: |
|||
<font size="1"> |
|||
<lang j> |
|||
((284035&=)" 0 (80 {. 375 }. edges)){' #' |
|||
### ## ... |
|||
### ## ... |
|||
# ... |
|||
## ... |
|||
## ... |
|||
### ... |
|||
## ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
#### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
## ... |
|||
#### ... |
|||
#### ... |
|||
### ... |
|||
## ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
#### ... |
|||
## ... |
|||
### ... |
|||
#### ... |
|||
### ... |
|||
## ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
## ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
#### ... |
|||
## ... |
|||
### ... |
|||
#### ... |
|||
### ... |
|||
## ... |
|||
####### ... |
|||
#### ... |
|||
##### ... |
|||
### ... |
|||
#### ... |
|||
### ... |
|||
### ... |
|||
#### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
### ... |
|||
## ... |
|||
## ... |
|||
##### ... |
|||
###### ... |
|||
### ... |
|||
## ... |
|||
#### ... |
|||
... |
|||
... |
|||
... |
|||
... |
|||
... |
|||
... |
|||
</lang> |
|||
</font> |
|||
=={{header|Mathematica}}== |
=={{header|Mathematica}}== |