8
$\begingroup$

Both DerivativeFilter and RidgeFilter take an optional parameter σ to indicate the scale of derivatives being used. I would like to reproduce an algorithm I've been working on in another language, so I need to figure out what exactly these functions do with that parameter. However, the docs aren't giving much away. We have this from DerivativeFilter:

[...] computes the derivative at a Gaussian scale of standard deviation σ.

Image derivatives are susceptible to noise. To counteract this effect, you can regularize the image or data by a Gaussian kernel of standard deviation σ. The default value is σ = 0.

And this from RidgeFilter:

[...] uses the specified ridge scale σ.

In RidgeFilter[image, σ], σ is the scale of the ridges that is used to compute the derivatives in the Hessian. By default, σ = 1 is used.

I believe that the exact effect of σ is the same in both functions, because the docs of DerivativeFilter contain a reimplementation of RidgeFilter. It doesn't exactly match the outputs of RidgeFilter, but we can fix that by adding a simple Clip:

ridgeFilter[img_, σ_: 1] := Module[
  {data = ImageData[img], Lxx, Lxy, Lyy},
  {Lxx, Lxy, Lyy} = 
    DerivativeFilter[data, {{0, 2}, {1, 1}, {2, 0}}, σ];
    Image[
      Clip[Chop[σ^(3/2)/2 (Sqrt[(Lxx - Lyy)^2 + 4 Lxy^2] - Lxx - Lyy)], {0, ∞}]
    ]
]

The results of this are identical (except for small numerical errors) to RidgeFilter and this just passes the σ through to DerivativeFilter.

Nevertheless, combining the information from the two pages of the docs, I still can't tell what exactly the functions are doing. It sounds to me like they simply run a GaussianFilter over the image first. I can obtain results at the same scale by using 2 σ as the radius of the Gaussian filter, but then I still get a lot of small scale artefacts that are missing when I use DerivativeFilter or RidgeFilter directly:

img = ColorConvert[ExampleData[{"TestImage", "Mandrill"}], "Grayscale"]
σ = 10;
ImageAssemble @ {
  ImageAdjust @ DerivativeFilter[img, {1, 1}, σ], 
  ImageAdjust @ DerivativeFilter[GaussianFilter[img, 2 σ], {1, 1}]
}

Results in:

filtered image

I'm actually completely baffled that I need to double σ (instead of halving it) since the docs for GaussianFilter call this parameter the radius r and they even say explicitly:

GaussianFilter[image, r] uses r = σ/2.

All of this seems highly confusing, and there must be more to it than simply smoothing the input up front.

What exactly is the magic behind this σ parameter in DerivativeFilter (and by extension RidgeFilter)?

$\endgroup$

1 Answer 1

9
+250
$\begingroup$

DerivativeFilter calculates two sequential convolutions of original image with one-dimesional gaussian kernels. First with vertical kernel and then with horizontal one.

Parameter sigma defines the standard deviation of the gaussian distribution which is used to calculate each one-dimensional kernel.

Here is a code which reproduces DerivativeFilter using ImageConvolve:

mockupDerivativeFilter[image_, {verticalDerivativeOrder_, horizontalDerivativeOrder_}, sigma_] := Module[
    {verticalKernel, horizontalKernel, verticallyFilteredImage},

    verticalKernel = Transpose[{gaussianDerivativeKernel[verticalDerivativeOrder, sigma]}];
    horizontalKernel = {gaussianDerivativeKernel[horizontalDerivativeOrder, sigma]};

    verticallyFilteredImage = ImageConvolve[
        image,
        verticalKernel,
        Padding->"Fixed"
        ];

    ImageConvolve[
        verticallyFilteredImage,
        horizontalKernel,
        Padding->"Fixed"
        ]
    ];

gaussianDerivativeKernel[derivativeOrder_Integer, sigma_] := Module[
    {xvar, radius},
    radius =  Ceiling[1.0 + 6.23 sigma];
    Table[ N[D[1/(Sqrt[2 Pi] sigma) Exp[-xvar^2/(2 sigma^2)], {xvar, derivativeOrder}] /. xvar->x] , {x, -radius, radius}]
    ];

img = Image[ColorConvert[ExampleData[{"TestImage", "Mandrill"}], "Grayscale"], "Real32"];

referenceImage = ImageAdjust@DerivativeFilter[img, {1, 1}, 10];

mockupImage = ImageAdjust@mockupDerivativeFilter[img, {1, 1}, 10];

{referenceImage, mockupImage, referenceImage - mockupImage}

The function GaussianFilter[image, r] indeed uses standard deviation sigma=r/2. The corresponding help page seems to be corrected in Mathematica 11.

$\endgroup$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.