private static Image <Complex, TDepth> prepareImage <TDepth>(Image <Gray, TDepth> image, int biggestKernelWidth, int biggestKernelHeight, ConvolutionBorder options, out int fillX, out int fillY) where TDepth : struct { int FFTNumOfCols = (int)System.Math.Pow(2.0, System.Math.Ceiling(System.Math.Log(biggestKernelWidth + image.Width, 2.0))); int FFTNumOfRows = (int)System.Math.Pow(2.0, System.Math.Ceiling(System.Math.Log(biggestKernelHeight + image.Height, 2.0))); fillX = System.Math.Min(image.Width, biggestKernelWidth / 2); fillY = System.Math.Min(image.Height, biggestKernelHeight / 2); Rectangle centerRegion = new Rectangle(fillX, fillY, image.Width, image.Height); Image <Gray, TDepth> paddedImage = new Image <Gray, TDepth>(FFTNumOfCols, FFTNumOfRows); //center paddedImage.GetSubRect(centerRegion).SetValue(image); if (options == ConvolutionBorder.BorderMirror) { ParallelConvolution.MirrorBorders(image, paddedImage, fillX, fillY); } Image <Complex, TDepth> paddedImageCmplx = new Image <Complex, TDepth>(new Image <Gray, TDepth>[] { paddedImage, paddedImage.CopyBlank() }); paddedImageCmplx.FFT(FourierTransform.Direction.Forward, true); return(paddedImageCmplx); }
private static ComplexF[,] prepareImage(Gray <float>[,] image, int biggestKernelWidth, int biggestKernelHeight, ConvolutionBorder options, out int fillX, out int fillY) { int FFTNumOfCols = (int)System.Math.Pow(2.0, System.Math.Ceiling(System.Math.Log(biggestKernelWidth + image.Width(), 2.0))); int FFTNumOfRows = (int)System.Math.Pow(2.0, System.Math.Ceiling(System.Math.Log(biggestKernelHeight + image.Height(), 2.0))); fillX = System.Math.Min(image.Width(), biggestKernelWidth / 2); fillY = System.Math.Min(image.Height(), biggestKernelHeight / 2); var paddedImage = new Gray <float> [FFTNumOfRows, FFTNumOfCols]; //center image.CopyTo(paddedImage, new Point(fillX, fillY)); if (options == ConvolutionBorder.BorderMirror) { mirrorBorders(image, paddedImage, fillX, fillY); } var paddedImageCmplx = paddedImage.ToComplex(); paddedImageCmplx.FFT(FourierTransform.Direction.Forward, true); return(paddedImageCmplx); }
internal static IImage Convolve(IImage src, IImage[] kernels, ConvolutionBorder options) { IImage dest = src; foreach (var kernel in kernels) { dest = Convolve(dest, kernel, options); } return(dest); }
private static IImage prepareSourceImage(IImage src, Size kernelSize, ConvolutionBorder options, out Rectangle validRegion) { var preparedSrc = Image.Create(src.ColorInfo, src.Width + kernelSize.Width, src.Height + kernelSize.Height); Rectangle centerRegion = new Rectangle(kernelSize.Width / 2, kernelSize.Height / 2, src.Width, src.Height); preparedSrc.GetSubRect(centerRegion).SetValue(src); if (options == ConvolutionBorder.BorderMirror) { ParallelConvolution.MirrorBorders(src, preparedSrc, centerRegion.X, centerRegion.Y); } validRegion = centerRegion; return(preparedSrc); }
internal static IImage Convolve(IImage src, IImage kernel, ConvolutionBorder options) { ConvolutionFunc convolutionFunc = null; if (convolutionFuncs.TryGetValue(src.ColorInfo.ChannelType, out convolutionFunc) == false) { throw new NotSupportedException(string.Format("Can not perform spatial convolution on an image of type {0}", src.ColorInfo.ChannelType.Name)); } Rectangle validRegion; var preparedSrc = prepareSourceImage(src, kernel.Size, options, out validRegion); var proc = new ParallelProcessor <IImage, IImage>(src.Size, () => preparedSrc.CopyBlank(), //in-place convolution is not supported due to parallel processing (junction patches handling) (_src, _dest, area) => { Rectangle srcArea = new Rectangle { X = 0, Y = area.Y, Width = _src.Width, Height = area.Height + kernel.Height //get area sufficient to process with the selected kernel; area.Height is processed }; //srcArea.Inflate(-kernel.Width , -kernel.Height ); srcArea.Width -= kernel.Width; srcArea.Height -= kernel.Height; srcArea.Intersect(new Rectangle(new Point(), _src.Size)); convolutionFunc(_src, srcArea, _dest, new Point(kernel.Width / 2, area.Y + kernel.Height / 2), kernel); } /*,new ParallelOptions2D { ForceSequential = true }*/); var dest = proc.Process(preparedSrc); return(dest.GetSubRect(validRegion)); }
/// <summary> /// Convolves the image with the provided kernels. /// </summary> /// <typeparam name="TColor">Color type.</typeparam> /// <param name="src">Source image.</param> /// <param name="kernels">Kernels to convolve with.</param> /// <param name="options">Border pixels resolvent options.</param> /// <returns>Convolved image.</returns> public static Image <TColor, float> Convolve <TColor>(Image <TColor, float> src, Image <Gray, float>[] kernels, ConvolutionBorder options) where TColor : IColor { return(Convolve((IImage)src, kernels, options) as Image <TColor, float>); }
/// <summary> /// Convolves the image with the specified kernels. /// </summary> /// <typeparam name="TColor">Image color type.</typeparam> /// <param name="image">Image.</param> /// <param name="kernels">Kernels to convolve with.</param> /// <param name="options">Options for resolving border pixels.</param> /// <returns>Convolved image.</returns> public static Image <TColor, double> Convolve <TColor>(Image <TColor, double> image, Image <Gray, double>[] kernels, ConvolutionBorder options) where TColor : IColor { return(Convolve <TColor, double>(image, kernels, options)); }
/// <summary> /// Convolves the image with the specified kernels. /// </summary> /// <typeparam name="TColor">Image color type.</typeparam> /// <param name="image">Image.</param> /// <param name="kernelArrs">Kernels to convolve with.</param> /// <param name="options">Options for resolving border pixels.</param> /// <returns>Convolved image.</returns> public static Image <TColor, double> Convolve <TColor>(Image <TColor, double> image, double[][,] kernelArrs, ConvolutionBorder options) where TColor : IColor { var kernels = kernelArrs.Select(x => x.AsImage()).ToArray(); return(Convolve <TColor, double>(image, kernels, options)); }
private static IEnumerable <Image <Gray, TDepth> > ConvolveSeparated <TDepth>(Image <Gray, TDepth> image, Image <Gray, TDepth>[] kernels, ConvolutionBorder options) where TDepth : struct /*float and double */ { int biggestKernelWidth, biggestKernelHeight; ParallelConvolution.GetTheBiggestSize(kernels, out biggestKernelWidth, out biggestKernelHeight); int fillX, fillY; var paddedIm = prepareImage(image, biggestKernelWidth, biggestKernelHeight, options, out fillX, out fillY); foreach (var kernel in kernels) { var preparedKernel = prepareKernel(kernel, paddedIm.Size); var convolvedIm = paddedIm.Mul(preparedKernel, null); yield return(getConvolutionResult(convolvedIm, fillX, fillY, image.Size, true)); } }
private static Image <Gray, TDepth> convolve <TDepth>(Image <Gray, TDepth> image, Image <Gray, TDepth>[] kernels, ConvolutionBorder options) where TDepth : struct { int biggestKernelWidth, biggestKernelHeight; ParallelConvolution.GetTheBiggestSize(kernels, out biggestKernelWidth, out biggestKernelHeight); int fillX, fillY; var paddedIm = prepareImage(image, biggestKernelWidth, biggestKernelHeight, options, out fillX, out fillY); Image <Complex, TDepth> convolvedIm = paddedIm; foreach (var kernel in kernels) { var preparedKernel = prepareKernel(kernel, convolvedIm.Size); convolvedIm = convolvedIm.Mul(preparedKernel, null); } return(getConvolutionResult(convolvedIm, fillX, fillY, image.Size, true)); }
/// <summary> /// Convolves the image with the specified kernels. /// </summary> /// <typeparam name="TColor">Image color type.</typeparam> /// <typeparam name="TDepth">Channel type.</typeparam> /// <param name="image">Image.</param> /// <param name="kernels">Kernels to convolve with.</param> /// <param name="options">Options for resolving border pixels.</param> /// <returns>Convolved image.</returns> internal static Image <TColor, TDepth> Convolve <TColor, TDepth>(Image <TColor, TDepth> image, Image <Gray, TDepth>[] kernels, ConvolutionBorder options) where TColor : IColor where TDepth : struct { if (typeof(TColor).Equals(typeof(Gray)) == true) //saving time on channel splitting and creating an image from channels (can function without this) { return(convolve <TDepth>(image as Image <Gray, TDepth>, kernels, options) as Image <TColor, TDepth>); } var channels = image.SplitChannels(); var convolvedChannels = new List <Image <Gray, TDepth> >(); foreach (var ch in channels) { var convolvedCh = convolve(ch as Image <Gray, TDepth>, kernels, options); convolvedChannels.Add(convolvedCh); } return(new Image <TColor, TDepth>(convolvedChannels.ToArray())); }
private static Image <TColor, TDepth> Convolve <TColor, TDepth, TKernel>(Image <TColor, TDepth> src, TKernel[][,] kernelArrs, ConvolutionBorder options, bool forceSpatialConvolution = false) where TColor : IColor where TDepth : struct where TKernel : struct { var kernels = kernelArrs.Select(x => x.AsImage()).ToArray(); return(Convolve <TColor, TDepth, TKernel>(src, kernels, options, forceSpatialConvolution)); }
/// <summary> /// Convolves an image with kernels. /// Convolution type (FFT or spatial) is automatically selected based on kernels size. /// </summary> /// <param name="src">Input image.</param> /// <param name="kernels">Kernels</param> /// <param name="options">Border options</param> /// <param name="forceSpatialConvolution">Use spatial convolution even if FFT should be used.</param> /// <returns>Convolved image</returns> public static Image <TColor, TDepth> Convolve <TColor, TDepth>(this Image <TColor, TDepth> src, float[][,] kernels, ConvolutionBorder options, bool forceSpatialConvolution = false) where TColor : IColor where TDepth : struct { return(Convolve <TColor, TDepth, float>(src, kernels, options, forceSpatialConvolution)); }
internal static Image <TColor, TDepth> Convolve <TColor, TDepth, TKernel>(this Image <TColor, TDepth> src, Image <Gray, TKernel>[] kernels, ConvolutionBorder options, bool forceSpatialConvolution = false) where TColor : IColor where TDepth : struct where TKernel : struct { bool useFFT = ShouldUseFFT(kernels) && !forceSpatialConvolution; Type[] supportedTypes = null; if (useFFT) { supportedTypes = ParallelFFTConvolution.SupportedTypes; } else { supportedTypes = ParallelSpatialConvolution.SupportedTypes; } supportedTypes = supportedTypes.Where(x => x.Equals(typeof(TKernel))).ToArray(); if (supportedTypes.Length == 0) { throw new NotSupportedException(string.Format("Kernel of type {0} is not supported. Used convolution: {1}. Supported types for used convolution: {2}." + "Please use different kernel type, or force convolution method.", typeof(TKernel).Name, (useFFT) ? "FFT" : "Spatial", supportedTypes.Select(x => x.Name))); } /************************************** convert src ********************************/ var supportedColors = supportedTypes.Select(x => ColorInfo.GetInfo(typeof(TColor), x)).ToArray(); var conversionPath = ColorConverter.GetPath(src.ColorInfo, supportedColors); IImage convertedSrc = ColorConverter.Convert(src, conversionPath.ToArray(), false); if (convertedSrc == null) { throw new Exception(string.Format("Convolution does not support images of type {0}", src.ColorInfo.ChannelType)); } /************************************** convert src ********************************/ IImage dest = null; if (useFFT) { dest = ParallelFFTConvolution.Convolve <TColor, TKernel>(convertedSrc as Image <TColor, TKernel>, kernels, options); } else { dest = ParallelSpatialConvolution.Convolve(convertedSrc, kernels, options); } /************************************** convert back ********************************/ var backwardConversion = ColorConverter.GetPath(dest.ColorInfo, src.ColorInfo); IImage convertedDest = ColorConverter.Convert(dest, backwardConversion.ToArray(), false); if (convertedDest == null) { throw new Exception(string.Format("Convolution does not support images of type {0}", src.ColorInfo.ChannelType)); } /************************************** convert back ********************************/ return(convertedDest as Image <TColor, TDepth>); }
/// <summary> /// Convolves the image with the specified kernels. /// </summary> /// <typeparam name="TColor">Image color type.</typeparam> /// <param name="image">Image.</param> /// <param name="kernels">Kernels.</param> /// <param name="options">Options for resolving border pixels.</param> /// <returns>Convolved image.</returns> public static TColor[,] ConvolveFFT <TColor>(this TColor[,] image, IList <float[, ]> kernels, ConvolutionBorder options) where TColor : struct, IColor <float> { var channels = image.SplitChannels <TColor, float>(); var convolvedChannels = new List <Gray <float> [, ]>(); foreach (var channel in channels) { var convolvedChannel = convolve(channel, kernels, options); convolvedChannels.Add(convolvedChannel); } var destination = convolvedChannels.MergeChannels <TColor, float>(); return(destination); }
private static Gray <float>[,] convolve(Gray <float>[,] image, IList <float[, ]> kernels, ConvolutionBorder options) { int biggestKernelWidth, biggestKernelHeight; getTheBiggestSize(kernels, out biggestKernelWidth, out biggestKernelHeight); int fillX, fillY; var paddedIm = prepareImage(image, biggestKernelWidth, biggestKernelHeight, options, out fillX, out fillY); var convolvedIm = paddedIm; foreach (var kernel in kernels) { var preparedKernel = prepareKernel(kernel, convolvedIm.Size()); convolvedIm = convolvedIm.MulComplex(preparedKernel, inPlace: false); } return(getConvolutionResult(convolvedIm, fillX, fillY, image.Size())); }