public static PNM ApplyCannyDetector(this PNM image) { PNM workImage = image.ApplyPointProcessing(Color.ToGrayscale) .ApplyConvolutionMatrix(new float[] { 0, 0.01F, 0.02F, 0.01F, 0, 0.01F, 0.06F, 0.1F, 0.06F, 0.01F, 0.02F, 0.1F, 0.16F, 0.1F, 0.02F, 0.01F, 0.06F, 0.1F, 0.06F, 0.01F, 0, 0.01F, 0.02F, 0.01F, 0 }, 1, 0); Filter.Pad(workImage, 1); float[] xraster = Filter.ApplyConvolutionUnbound(workImage, SobelX, 3).Item1; float[] yraster = Filter.ApplyConvolutionUnbound(workImage, SobelY, 3).Item1; var vectorField = xraster.Zip(yraster, (x, y) => Tuple.Create(Module(x, y), GetOrientation(x, y))).ToArray(); byte[] suppressed = NonMaximumSuppression(vectorField, image.Width, image.Height); return(ApplyHysteresis(suppressed, image.Width, image.Height, 0.05, 0.2)); }