/// <summary> /// Gets images (channels) for 2D/3D array. /// <remarks> Any array that is not 2D/3D and its element is not a primitive type is not supported. (an exception is thrown)</remarks> /// </summary> /// <param name="arr">Input array.</param> /// <returns>Channels. For 2D array output will consist of an single image.</returns> public unsafe static IImage[] GetChannels(this Array arr) { int nChannels, width, height; getArrayDimenions(arr, out nChannels, out width, out height); var elemType = arr.GetType().GetElementType(); var color = ColorInfo.GetInfo(typeof(Gray), elemType); GCHandle arrHandle = GCHandle.Alloc(arr, GCHandleType.Pinned); int arrDimStride = width * color.Size; var imageChannels = new IImage[nChannels]; for (int i = 0; i < nChannels; i++) { int dimOffset = i * arrDimStride * height; IntPtr dimPtr = (IntPtr)((byte *)arrHandle.AddrOfPinnedObject() + dimOffset); var channelImg = Image.Create(color, width, height); HelperMethods.CopyImage(dimPtr, channelImg.ImageData, arrDimStride, channelImg.Stride, arrDimStride, height); imageChannels[i] = channelImg; } arrHandle.Free(); return(imageChannels); }
internal void Calculate <TDepth>(Image <Gray, TDepth>[] channels, bool accumulate, Image <Gray, byte> mask = null) where TDepth : struct { var color = ColorInfo.GetInfo(typeof(Gray), typeof(TDepth)); CalculateHistFunc calculateHistFunc = null; if (calculateHistFuncs.TryGetValue(color.ChannelType, out calculateHistFunc) == false) { throw new Exception(string.Format("Calculate function does not support an image of type {0}", color.ChannelType)); } if (!accumulate) { Array.Clear(histogram, 0, this.NumberOfElements); } if (mask == null) { mask = new Image <Gray, byte>(channels[0].Width, channels[0].Height); mask.SetValue(new Gray(255)); } calculateHistFunc(this, channels, mask); }
private static void correctValueMapping <TColor>(ref int[] colorArr) where TColor : IColor { if (ColorInfo.GetInfo <TColor, double>().ConversionCodename == "BGR") //TODO (priority: lowest): other way to do that (without harcoding) - converters ? { var temp = colorArr[0]; colorArr[0] = colorArr[2]; colorArr[2] = temp; } }
/// <summary> /// Converts unmanaged image to generic image. Depending on output format a simple cast may be performed instead of data copy. /// <seealso cref="AsImage"/> /// </summary> /// <param name="unmanagedImage">Unmanaged image.</param> /// <param name="copyAlways">Forces data copy even if the cast is enough.</param> /// <param name="failIfCannotCast">Fails if an image data must be converted to a format that is supported by UnmanagedImage. Switch <paramref name="copyAlways"/> is omitted.</param> /// <returns>Generic image.</returns> public static Image <TColor, TDepth> ToImage <TColor, TDepth>(this UnmanagedImage unmanagedImage, bool copyAlways = false, bool failIfCannotCast = false) where TColor : IColor where TDepth : struct { IImage im = AsImage(unmanagedImage); var convertedImage = ((Image)im).Convert(ColorInfo.GetInfo <TColor, TDepth>(), copyAlways, failIfCannotCast); return(convertedImage as Image <TColor, TDepth>); }
/// <summary> /// Converts a bitmap to an image (copies data). /// If an output color is not matched with bitmap pixel format additional conversion may be applied. /// </summary> /// <param name="bmp">Input bitmap.</param> /// <returns>Generic image.</returns> public static Image <TColor, TDepth> ToImage <TColor, TDepth>(this Bitmap bmp) where TColor : IColor where TDepth : struct { IImage im = ToImage(bmp); //convert if necessary var convertedImage = ((Image)im).Convert(ColorInfo.GetInfo <TColor, TDepth>(), false); return(convertedImage as Image <TColor, TDepth>); }
/// <summary> /// Converts color to unmanaged data of type <typeparamref name="TDepth"/>. /// </summary> /// <typeparam name="TColor">Color type.</typeparam> /// <typeparam name="TDepth">Channel type.</typeparam> /// <param name="color">Color</param> /// <param name="data">Pointer to unmanaged data. Space must be allocated (number of color channels * sizeof(<typeparamref name="TDepth"/>)</param> public unsafe static void ColorToPointer <TColor, TDepth>(TColor color, IntPtr data) where TColor : IColor where TDepth : struct { var colorInfo = ColorInfo.GetInfo <TColor, TDepth>(); TDepth[] arr = ColorToArray <TColor, TDepth>(color); GCHandle handle = GCHandle.Alloc(arr, GCHandleType.Pinned); AForge.SystemTools.CopyUnmanagedMemory(data, handle.AddrOfPinnedObject(), colorInfo.Size); handle.Free(); }
private static Map <ColorInfo, PixelFormat> initPixelFormatMappings() { var map = new Map <ColorInfo, PixelFormat>(); map.Add(ColorInfo.GetInfo <Gray, byte>(), PixelFormat.Format8bppIndexed); map.Add(ColorInfo.GetInfo <Gray, short>(), PixelFormat.Format16bppGrayScale); map.Add(ColorInfo.GetInfo <Bgr, byte>(), PixelFormat.Format24bppRgb); map.Add(ColorInfo.GetInfo <Bgra, byte>(), PixelFormat.Format32bppArgb); map.Add(ColorInfo.GetInfo <Bgr, short>(), PixelFormat.Format48bppRgb); map.Add(ColorInfo.GetInfo <Bgra, short>(), PixelFormat.Format64bppArgb); return(map); }
/// <summary> /// Converts array to image (data is copied). Array elements must be primitive types. /// </summary> /// <param name="arr">Input array</param> /// <param name="width">Image width.</param> /// <param name="height">Image height.</param> /// <returns>Image</returns> public unsafe static Image <TColor, byte> ToImage <TColor>(this byte[] arr, int width, int height) where TColor : IColor { var colorSize = ColorInfo.GetInfo <TColor, byte>().Size; int srcStride = arr.Length / height; var image = new Image <TColor, byte>(width, height); fixed(byte *arrPtr = arr) { HelperMethods.CopyImage((IntPtr)arrPtr, image.ImageData, srcStride, image.Stride, image.Width * colorSize, image.Height); } return(image); }
/// <summary> /// Casts iplImage in generic image representation. /// </summary> /// <param name="iplImage">IplImage structure.</param> /// <param name="destructor">Destructor which is called when created generic image is disposed.</param> /// <returns>Image.</returns> public static unsafe IImage AsImage(this IplImage iplImage, Action <IplImage> destructor = null) { var depthType = depthAssociations.Reverse[iplImage.ChannelDepth]; var colorType = colorAssociations.Reverse[iplImage.NumberOfChannels]; var colorInfo = ColorInfo.GetInfo(colorType, depthType); if (destructor != null) { return(Image.Create(colorInfo, (IntPtr)iplImage.ImageData, iplImage.Width, iplImage.Height, iplImage.WidthStep, (object)iplImage, (x) => destructor((IplImage)x))); } else { return(Image.Create(colorInfo, (IntPtr)iplImage.ImageData, iplImage.Width, iplImage.Height, iplImage.WidthStep)); } }
/// <summary> /// Converts unmanaged data to color representation. /// </summary> /// <typeparam name="TColor">Color type.</typeparam> /// <typeparam name="TDepth">Channel type.</typeparam> /// <param name="data">Pointer to unmanaged data of type: <typeparamref name="TDepth"/>.</param> /// <returns>Color</returns> public unsafe static TColor PointerToColor <TColor, TDepth>(IntPtr data) where TColor : IColor where TDepth : struct { TColor color; var colorInfo = ColorInfo.GetInfo <TColor, TDepth>(); using (PinnedArray <TDepth> arr = new PinnedArray <TDepth>(colorInfo.Size)) { AForge.SystemTools.CopyUnmanagedMemory(arr.Data, data, colorInfo.Size); color = ArrayToColor <TColor, TDepth>(arr.Array); } return(color); }
/// <summary> /// Extracts the specified image channels. /// </summary> /// <typeparam name="TSrcColor">Source color type.</typeparam> /// <typeparam name="TDepth">Channel depth type.</typeparam> /// <param name="image">Image.</param> /// <param name="area">Working area.</param> /// <param name="channelIndices">Channel indicies to extract. If null, all channels are extracted.</param> /// <returns>Channel collection.</returns> public static unsafe Gray <TDepth>[][,] SplitChannels <TSrcColor, TDepth>(this TSrcColor[,] image, Rectangle area, params int[] channelIndices) where TSrcColor : struct, IColor <TDepth> where TDepth : struct { if (channelIndices == null || channelIndices.Length == 0) { channelIndices = Enumerable.Range(0, ColorInfo.GetInfo <TSrcColor>().ChannelCount).ToArray(); } var channels = new Gray <TDepth> [channelIndices.Length][, ]; for (int i = 0; i < channelIndices.Length; i++) { channels[i] = GetChannel <TSrcColor, TDepth>(image, area, channelIndices[i]); } return(channels); }
internal static IImage[] SplitChannels(IImage img, params int[] channelIndicies) { if (channelIndicies == null || channelIndicies.Length == 0) { channelIndicies = Enumerable.Range(0, img.ColorInfo.NumberOfChannels).ToArray(); } Type depthType = img.ColorInfo.ChannelType; ColorInfo channelType = ColorInfo.GetInfo(typeof(Gray), depthType); SplitImage splitter = null; if (splitters.TryGetValue(depthType, out splitter) == false) { throw new Exception(string.Format("Splitting function can not split image of color depth type {0}", depthType)); } ParallelProcessor <IImage, IImage[]> proc = new ParallelProcessor <IImage, IImage[]>(img.Size, () => //called once { IImage[] channels = new IImage[channelIndicies.Length]; for (int i = 0; i < channels.Length; i++) { channels[i] = Image.Create(channelType, img.Width, img.Height); } return(channels); }, (IImage src, IImage[] dest, Rectangle area) => //called for every thread { IImage srcPatch = src.GetSubRect(area); IImage[] destPatch = new IImage[dest.Length]; for (int i = 0; i < dest.Length; i++) { destPatch[i] = dest[i].GetSubRect(area); } splitter(srcPatch, destPatch, channelIndicies); } /*,new ParallelOptions { ForceSequential = true}*/); return(proc.Process(img)); }
internal static Image <Gray, byte> InRange <TColor, TDepth>(this Image <TColor, TDepth> img, TDepth[] minArr, TDepth[] maxArr, byte valueToSet = 255, params int[] channelIndicies) where TColor : IColor where TDepth : struct { Type depthType = img.ColorInfo.ChannelType; InRangeFunc inRangeFilter = null; if (inRangeFilters.TryGetValue(typeof(TDepth), out inRangeFilter) == false) { throw new Exception(string.Format("InRange function can not process image of color depth type {0}", depthType)); } if (channelIndicies == null || channelIndicies.Length == 0) { channelIndicies = Enumerable.Range(0, ColorInfo.GetInfo <TColor, TDepth>().NumberOfChannels).ToArray(); } if (channelIndicies.Length > img.ColorInfo.NumberOfChannels) { throw new Exception("Number of processed channels must not exceed the number of available image channels!"); } ParallelProcessor <IImage, Image <Gray, byte> > proc = new ParallelProcessor <IImage, Image <Gray, byte> >(img.Size, () => //called once { var destImg = new Image <Gray, byte>(img.Width, img.Height); destImg.SetValue(new Gray(255)); //initialize destination mask. return(destImg); }, (IImage srcImg, Image <Gray, byte> dstImg, Rectangle area) => //called for every thread { var srcPatch = srcImg.GetSubRect(area); var destPatch = dstImg.GetSubRect(area); inRangeFilter(srcPatch, minArr, maxArr, channelIndicies, destPatch, valueToSet); } /*,new ParallelOptions { ForceSequential = true}*/); var dest = proc.Process(img); return(dest as Image <Gray, byte>); }
/// <summary> /// Converts array to image (data is shared). Array elements must be primitive types. /// </summary> /// <param name="arr">Input array</param> /// <returns>Image</returns> public static Image <Gray, TDepth> AsImage <TDepth>(this TDepth[,] arr) where TDepth : struct { GCHandle arrHandle = GCHandle.Alloc(arr, GCHandleType.Pinned); int width = arr.GetLength(1); int height = arr.GetLength(0); int stride = ColorInfo.GetInfo <Gray, TDepth>().ChannelSize *width; Image <Gray, TDepth> img = new Image <Gray, TDepth>(arrHandle.AddrOfPinnedObject(), width, height, stride, arr, (_) => { if (arrHandle.IsAllocated) { arrHandle.Free(); } }); return(img); }
private Image <Gray, TDepth> BackProject <TDepth>(Image <Gray, TDepth>[] srcs) where TDepth : struct { var destColor = ColorInfo.GetInfo <Gray, TDepth>(); BackpropagateFunc backpropagateFunc = null; if (backpropagateFuncs.TryGetValue(destColor.ChannelType, out backpropagateFunc) == false) { throw new Exception(string.Format("Back-propagate function does not support an image of type {0}", destColor.ChannelType)); } var imgSize = srcs[0].Size; var proc = new ParallelProcessor <IImage[], IImage>(imgSize, () => //executed once { return(Image.Create(destColor, imgSize.Width, imgSize.Height)); }, (IImage[] srcImgs, IImage destImg, Rectangle area) => //executed for each thread { var channelPatches = new IImage[srcImgs.Length]; for (int i = 0; i < channelPatches.Length; i++) { channelPatches[i] = srcImgs[i].GetSubRect(area); } var projPatch = destImg.GetSubRect(area); backpropagateFunc(this, channelPatches, projPatch); } /*,new ParallelOptions { ForceSequential = true}*/); return(proc.Process(srcs) as Image <Gray, TDepth>); }
private unsafe static Array toArray(IImage image) { Array arr = Array.CreateInstance(image.ColorInfo.ChannelType, image.ColorInfo.NumberOfChannels, image.Height, image.Width); var channelColor = ColorInfo.GetInfo(typeof(Gray), image.ColorInfo.ChannelType); GCHandle arrHandle = GCHandle.Alloc(arr, GCHandleType.Pinned); int arrDimStride = image.Width * channelColor.Size; IImage[] channels = (image.ColorInfo.NumberOfChannels == 1) ? new IImage[] { image } : ChannelSplitter.SplitChannels(image); for (int i = 0; i < channels.Length; i++) { int dimOffset = i * arrDimStride * image.Height; IntPtr dimPtr = (IntPtr)((byte *)arrHandle.AddrOfPinnedObject() + dimOffset); var channelImg = channels[i]; HelperMethods.CopyImage(channelImg.ImageData, dimPtr, channelImg.Stride, arrDimStride, arrDimStride, image.Height); } arrHandle.Free(); return(arr); }
/// <summary> /// Converts the image from source to destination color and depth. /// Data may be shared if casting is used. To prevent that set <paramref name="copyAlways"/> to true. /// </summary> /// <typeparam name="DestColor">Destination color (IColor).</typeparam> /// <typeparam name="DestType">Destination type (primitive type).</typeparam> /// <param name="image">Image.</param> /// <param name="copyAlways">Forces data copy even if a casting is enough.</param> /// <param name="failIfCannotCast">If data copy is needed throws an exception.</param> /// <returns>Converted image.</returns> public static Image <DestColor, DestType> Convert <DestColor, DestType>(this IImage image, bool copyAlways = false, bool failIfCannotCast = false) where DestColor : IColor where DestType : struct { return(Convert(image, ColorInfo.GetInfo <DestColor, DestType>(), copyAlways, failIfCannotCast) as Image <DestColor, DestType>); }
/// <summary> /// Do not remove! Needed for dynamic image creation via cached expressions. /// </summary> private Image() { this.ColorInfo = ColorInfo.GetInfo <TColor, TDepth>(); //an early init is needed during deserialization }
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> /// Creates an unmanaged image by pinning the provided array. /// <para>No data is copied.</para> /// </summary> /// <param name="array">Array to lock.</param> /// <returns>Unmanaged image.</returns> public static Image <TColor> Lock(TColor[,] array) { GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned); int width = array.GetLength(1); int height = array.GetLength(0); var image = new Image <TColor>(handle.AddrOfPinnedObject(), width, height, ColorInfo.GetInfo <TColor>().Size *width, handle, x => ((GCHandle)x).Free()); return(image); }