Canny Edge Detector-JuliaImages

I am trying to implement canny edge detector on my own created image using array functionalities

 using Images, FileIO, ImageShow, ImageFiltering,TestImages,ImageFeatures,ImageTransformations,CoordinateTransformations, Rotations,OffsetArrays

||img_source=zeros(Float64, (200, 200));|
||img_gray=Gray.(img_source);|
||img_gray[50:150, 50:150] .= 1;|
||tfm = recenter(RotMatrix(pi/8), center(img_gray));|
||imgrot = warp(img_gray, tfm);||
||imgg = imfilter(imgrot, Kernel.gaussian(3));|
||imgfinal=Gray.(imgg);|
||img_edges = canny(imgfinal,(80,20),1);|#error thrown at this point
||[imgfinal Gray.(img_edges)];|

Error:

BoundsError: attempt to access 262×262 OffsetArray(::Array{Float64,2}, -30:231, -30:231) with eltype Float64 with indices -30:231×-30:231 at index [232, 1]

1. **throw_boundserror** (::OffsetArrays.OffsetArray{Float64,2,Array{Float64,2}}, ::Tuple{Int64,Int64})@ *abstractarray.jl:541*
2. **checkbounds** @ *abstractarray.jl:506* [inlined]
3. **getindex** @ *OffsetArrays.jl:269* [inlined]
4. **thin_edges_nonmaxsup_core!** (::Array{Float64,2}, ::Array{Graphics.Vec2,2}, ::OffsetArrays.OffsetArray{Float64,2,Array{Float64,2}}, ::OffsetArrays.OffsetArray{Float64,2,Array{Float64,2}}, ::Float64, ::String, ::Float64)@ *edge.jl:304*
5. **#thin_edges_nonmaxsup#88** (::Float64, ::Float64, ::typeof(Images.thin_edges_nonmaxsup), ::OffsetArrays.OffsetArray{Float64,2,Array{Float64,2}}, ::OffsetArrays.OffsetArray{Float64,2,Array{Float64,2}}, ::String)@ *edge.jl:354*
6. **thin_edges_nonmaxsup** @ *edge.jl:352* [inlined]
7. **canny** (::OffsetArrays.OffsetArray{ColorTypes.Gray{Float64},2,Array{ColorTypes.Gray{Float64},2}}, ::Tuple{Int64,Int64}, ::Int64)@ *edge.jl:399*
8. **top-level scope** @ *[Local: 10](http://localhost:1234/edit?id=76f06094-3761-11eb-0a1c-b75d84b942ec#)*

How do I resolve this and make it work??
Also I wanted to create additional noise in the imgfinal with something like this in python:


# Generate noisy image of a square
im = np.zeros((128, 128))
im[32:-32, 32:-32] = 1

im = ndi.rotate(im, 15, mode='constant')
im = ndi.gaussian_filter(im, 4#I have successfully done till here
im += 0.2 * np.random.random(im.shape)#this is what I don't know

How to do this??

It looks like canny doesn’t work well with OffsetArrays. The output of warp is an OffsetArray with indices from -30:231, canny is attempting to index 1:width. The fix is to turn the rotated and offset image back into an ordinary array by calling parent

Something like this:

img_gray = zeros(Gray{Float64}, 200, 200)
img_gray[50:150, 50:150] .= 1
tfm = recenter(RotMatrix(pi/8), center(img_gray))
imgrot = warp(img_gray, tfm) |> parent
imgg = imfilter(imgrot, Kernel.gaussian(3))
img_edges = canny(imgg,(80,20),1)
im += 0.2*rand(Gray{Float32}, size(im))
1 Like

I registered a new package ImageEdgeDetection.jl yesterday and it solves the issues you are encountering. That is, it works on OffsetArrays and it also handles the NaNs that arise as a by-product of your warp function correctly. I discovered a moment ago when trying your example that the current canny function in Images seems to have a bug with NaNs because it yields spurious artifacts in the NaN regions of the image.

With the ImageEdgeDetection package, the solution you are looking for looks likes this:

using CoordinateTransformations
using ImageCore
using ImageEdgeDetection
using ImageFiltering
using ImageTransformations
using ImageShow
using OffsetArrays
using Rotations

img_gray = zeros(Gray{Float64}, 200, 200)
img_gray[50:150, 50:150] .= 1
tfm = recenter(RotMatrix(pi/8), center(img_gray))
imgrot = warp(img_gray, tfm) 
imgg = imfilter(imgrot, Kernel.gaussian(3))
algo = Canny(spatial_scale = 1, 
             high = ImageEdgeDetection.Percentile(80), 
             low = ImageEdgeDetection.Percentile(20))
img_edges = detect_edges(imgg, algo)   
3 Likes

Relevant Image.jl issue: https://github.com/JuliaImages/Images.jl/issues/926

2 Likes

Another Issue arose


Issue arises when I am trying to add random noise after the gaussian filter.It’s another offset arrays issue,How to deal with this now??

@zygmuntszpak your solution worked perfectly well,but the difference between detected edges weren’t significant for sigma =1, sigma=3 with the image without random_noise which I wanted to show,so I wanted to add some random_noise…

Also,I am having a little bit of issue with using Plots to show the results as the center in ImageTransformations.j become undefined when I try to use Plots

# rotate the image by pi/8	
tfm = recenter(RotMatrix(pi/8), center(img_gray)) #this one
imgrot = warp(img_gray, tfm)

This worked for me with some changes but It would be great if it can solved with ImageEdgeDetection.jl Directly