/// <summary> /// Does non-maxima supression for the following gray image. Can be useful for detections filtering (e.g. post-processing output from Harris detector). /// </summary> /// <typeparam name="TDepth">Channel type.</typeparam> /// <param name="img">Image.</param> /// <param name="dest">Destination image. Must have the same size as source image.</param> /// <param name="radius">Non-maxima supression radius (kernel radius).</param> /// <param name="discardValue">The value will be discarded (0 - for black).</param> public static void SupressNonMaxima <TDepth>(this Image <Gray, TDepth> img, Image <Gray, TDepth> dest, int radius = 3, int discardValue = 0) where TDepth : struct { SupressNonMaximaFunc supressNonMaximaFunc = null; if (supressNonMaximaFuncs.TryGetValue(img.ColorInfo.ChannelType, out supressNonMaximaFunc) == false) { throw new NotSupportedException(string.Format("Can not perform non-maxima suppression on an image of type {0}", img.ColorInfo.ChannelType.Name)); } var proc = new ParallelProcessor <IImage, bool>(img.Size, () => true, (_src, _, area) => { Rectangle srcArea = new Rectangle { X = 0, Y = area.Y, Width = _src.Width, Height = area.Height + 2 * radius }; srcArea.Intersect(new Rectangle(new Point(), img.Size)); supressNonMaximaFunc(img.GetSubRect(srcArea), dest.GetSubRect(srcArea), radius, discardValue); }, new ParallelOptions2D { /*ForceSequential = true*/ }); proc.Process(img); }
public static ParallelProcessor <T[, ], T[, ]> GetProcessor <T>(this T[,] field, Func <T, T> processFunc, bool forceSequential = false) { var fieldSize = new Size(field.GetLength(1), field.GetLength(0)); ParallelProcessor <T[, ], T[, ]> proc = new ParallelProcessor <T[, ], T[, ]> ( fieldSize, () => new T[fieldSize.Height, fieldSize.Width], (inputArray, outputArray, patch) => { for (int y = patch.Top; y < patch.Bottom; y++) { for (int x = patch.Left; x < patch.Right; x++) { outputArray[y, x] = processFunc(inputArray[y, x]); } } }, new ParallelOptions2D { ForceSequential = forceSequential } ); return(proc); }
internal static void SetValue <TColor, TDepth>(this Image <TColor, TDepth> img, TDepth[] valueArr) where TColor : IColor where TDepth : struct { if (valueArr.Length > img.ColorInfo.NumberOfChannels) { throw new Exception("Value array length must be the same as number of channels (or less)!"); } Type depthType = img.ColorInfo.ChannelType; SetValueFunc valueSetter = null; if (valueSetters.TryGetValue(typeof(TDepth), out valueSetter) == false) { throw new Exception(string.Format("Setter function can not split image of color depth type {0}", depthType)); } ParallelProcessor <IImage, bool> proc = new ParallelProcessor <IImage, bool>(img.Size, () => //called once { return(true); }, (IImage srcImg, bool dummy, Rectangle area) => //called for every thread { valueSetter(srcImg.GetSubRect(area), valueArr); } /*,new ParallelOptions { ForceSequential = true}*/); proc.Process(img); //result is in srcImg }
/// <summary> /// Copies values from source to destination image using mask. Destination values where mask == 0 are not erased!. /// </summary> /// <param name="img">Image.</param> /// <param name="destImg">Destination image</param> /// <param name="mask">Mask. Color locations that need to be copied must be set to !=0 in mask.</param> public static void CopyTo(this IImage img, IImage destImg, Image <Gray, byte> mask) { if (img.Size != mask.Size || img.Size != destImg.Size) { throw new Exception("Image, mask, destImg size must be the same!"); } if (img.ColorInfo.Equals(destImg.ColorInfo, ColorInfo.ComparableParts.Castable) == false) { throw new Exception("Image and dest image must be castable (the same number of channels, the same channel type)!"); } Type depthType = img.ColorInfo.ChannelType; ConditionalCopyFunc conditionalCopyFunc = null; if (conditionalCopyFuncs.TryGetValue(depthType, out conditionalCopyFunc) == false) { throw new Exception(string.Format("Conditional copy function of color depth type {0}", depthType)); } ParallelProcessor <IImage, IImage> proc = new ParallelProcessor <IImage, IImage>(img.Size, () => //called once { return(destImg); }, (IImage srcImg, IImage dstImg, Rectangle area) => //called for every thread { conditionalCopyFunc(srcImg.GetSubRect(area), dstImg.GetSubRect(area), mask.GetSubRect(area)); } /*,new ParallelOptions { ForceSequential = true}*/); proc.Process(img); //result is in destImg }
public async Task ParallelProcessing() { var count = 500_000; var shouldFind = count / 2; var strings = new string[count]; for (var i = 0; i < count; i++) { if (i % 2 == 0) { strings[i] = "Some text here and This is the pattern I want to find! and some text here"; continue; } strings[i] = "Some text here but not the pattern I am looking for!"; } var parallelStopwatch = new Stopwatch(); parallelStopwatch.Start(); var processor = new ParallelProcessor <string, string>(strings, IndexOfSomeString); var parallelResult = await processor.Process(); var parallelFoundEntries = parallelResult.Count(s => !string.IsNullOrWhiteSpace(s)); parallelStopwatch.Stop(); Debug.WriteLine($"Parallel time ms: {parallelStopwatch.ElapsedMilliseconds}"); Assert.Equal(shouldFind, parallelFoundEntries); }
private static void calculate(IImage src, IImage dest, Image <Gray, byte> mask = null) { if (mask == null) { mask = new Image <Gray, byte>(dest.Width, dest.Height); mask.SetValue(new Gray(255)); } NotFunc mathOpFunc = null; if (notFuncs.TryGetValue(src.ColorInfo.ChannelType, out mathOpFunc) == false) { throw new Exception(string.Format("Bitwise NOT can not be executed on an image of type {0}", src.ColorInfo.ChannelType)); } var proc = new ParallelProcessor <bool, bool>(dest.Size, () => { return(true); }, (bool _, bool __, Rectangle area) => { var srcPatch = src.GetSubRect(area); var destPatch = dest.GetSubRect(area); var maskPatch = mask.GetSubRect(area); mathOpFunc(srcPatch, destPatch, maskPatch); } /*,new ParallelOptions { ForceSequential = true}*/); proc.Process(true); }
private static IImage max(IImage imageA, IImage imageB, bool inPlace) { Type channelType = imageA.ColorInfo.ChannelType; MaxFunc maxFunc = null; if (maxFuncs.TryGetValue(channelType, out maxFunc) == false) { throw new NotSupportedException(string.Format("Can not calculate max from a image of type {0}", channelType)); } var proc = new ParallelProcessor <bool, IImage>(imageA.Size, () => { if (!inPlace) { return(Image.Create(imageA.ColorInfo, imageA.Width, imageA.Height)); } else { return(imageA); } }, (bool _, IImage dest, Rectangle area) => { maxFunc(imageA.GetSubRect(area), imageB.GetSubRect(area), dest.GetSubRect(area)); } /*, new ParallelOptions { ForceSequential = true }*/); return(proc.Process(true)); }
protected virtual void AfterBind() { if (UseParallelSystemComponentsProcessing()) { #if UNITY_EDITOR sampler = UnityEngine.Profiling.CustomSampler.Create(SystemName); #endif parallelSystemComponentProcessor = new ParallelProcessor(ProcessAtIndex); } }
public void Parallel4KImageProcessingTest() { var url1 = @"../../TestData/4k/4k-TD1.jpg"; var url2 = @"../../TestData/4k/4k-TD2.jpg"; var parallelProcessor = new ParallelProcessor(url1, url2); var sw = new Stopwatch(); sw.Start(); parallelProcessor.Process(); sw.Stop(); var t = sw.ElapsedMilliseconds; TestContext.WriteLine($"Parallel Processor Elapsed Time(4K): {t.ToString()}ms"); }
/// <summary> /// Searches the image for the good features to track. /// <para>For each location a Hessian matrix is made and min eig-value is compared against threshold.</para> /// </summary> /// <param name="image">Image.</param> /// <param name="winSize">Window size.</param> /// <param name="minEigVal">Minimum eigen value.</param> /// <param name="minimalDistance">Minimum distance from two features.</param> /// <returns>List of locations that have eigen value larger than <paramref name="minEigVal"/>.</returns> public static List <Point> GoodFeaturesToTrack(this Image <Gray, float> image, int winSize = 10, float minEigVal = 0.3f, float minimalDistance = 3) { var strengthImg = new Image <Gray, float>(image.Size); var Dx = image.Sobel(1, 0, 3); var Dy = image.Sobel(0, 1, 3); var Dxx = Dx.Mul(Dx).MakeIntegral(); var Dxy = Dx.Mul(Dy).MakeIntegral(); var Dyy = Dy.Mul(Dy).MakeIntegral(); var proc = new ParallelProcessor <bool, bool>(image.Size, () => true, (_, __, area) => { Rectangle srcArea = new Rectangle { X = 0, Y = area.Y, Width = image.Width, Height = area.Height + winSize }; srcArea.Intersect(new Rectangle(new Point(), image.Size)); goodFeaturesToTrack(Dxx.GetSubRect(srcArea), Dxy.GetSubRect(srcArea), Dyy.GetSubRect(area), winSize, minEigVal, strengthImg.GetSubRect(srcArea)); }, new ParallelOptions2D { /*ForceSequential = true*/ }, winSize); proc.Process(true); var filteredStrengthImg = strengthImg.SupressNonMaxima(); //var filteredStrengthImg = strengthImg; List <float> values; var locations = filteredStrengthImg.FindNonZero(out values); var sortedFeatures = locations.Zip(values, (f, s) => new { f, s }) .OrderByDescending(x => x.s) .Select(x => x.f) .ToList(); sortedFeatures = sortedFeatures.EnforceMinimalDistance(minimalDistance); return(sortedFeatures); }
/// <summary> /// Searches the image for the good features to track. /// <para>For each location a Hessian matrix is made and min eig-value is compared against threshold.</para> /// </summary> /// <param name="image">Image.</param> /// <param name="winSize">Window size.</param> /// <param name="minEigVal">Minimum eigen value.</param> /// <param name="minimalDistance">Minimum distance from two features.</param> /// <returns>List of locations that have eigen value larger than <paramref name="minEigVal"/>.</returns> public static List<Point> GoodFeaturesToTrack(this Image<Gray, float> image, int winSize = 10, float minEigVal = 0.3f, float minimalDistance = 3) { var strengthImg = new Image<Gray, float>(image.Size); var Dx = image.Sobel(1, 0, 3); var Dy = image.Sobel(0, 1, 3); var Dxx = Dx.Mul(Dx).MakeIntegral(); var Dxy = Dx.Mul(Dy).MakeIntegral(); var Dyy = Dy.Mul(Dy).MakeIntegral(); var proc = new ParallelProcessor<bool, bool>(image.Size, () => true, (_, __, area) => { Rectangle srcArea = new Rectangle { X = 0, Y = area.Y, Width = image.Width, Height = area.Height + winSize }; srcArea.Intersect(new Rectangle(new Point(), image.Size)); goodFeaturesToTrack(Dxx.GetSubRect(srcArea), Dxy.GetSubRect(srcArea), Dyy.GetSubRect(area), winSize, minEigVal, strengthImg.GetSubRect(srcArea)); }, new ParallelOptions2D { /*ForceSequential = true*/ }, winSize); proc.Process(true); var filteredStrengthImg = strengthImg.SupressNonMaxima(); //var filteredStrengthImg = strengthImg; List<float> values; var locations = filteredStrengthImg.FindNonZero(out values); var sortedFeatures = locations.Zip(values, (f, s) => new { f, s }) .OrderByDescending(x => x.s) .Select(x => x.f) .ToList(); sortedFeatures = sortedFeatures.EnforceMinimalDistance(minimalDistance); return sortedFeatures; }
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>); }
internal override void Compute(IImage image) { Reset(); RawMomentsFunc rawMomentsFunc = null; if (rawMomentsFuncs.TryGetValue(image.ColorInfo.ChannelType, out rawMomentsFunc) == false) { throw new Exception(string.Format("Raw moments can not be calculated of an image of type {0}", image.ColorInfo.ChannelType)); } object sync = new object(); ParallelProcessor <IImage, bool> proc = new ParallelProcessor <IImage, bool>(image.Size, () => { return(true); }, (IImage src, bool _, Rectangle area) => //called for every thread { IntPoint offset = new IntPoint(area.X, area.Y); float m00, m01, m10, m11, m02, m20, m12, m21, m30, m03; rawMomentsFunc(src.GetSubRect(area), offset, Order, out m00, out m01, out m10, out m11, out m02, out m20, out m12, out m21, out m30, out m03); lock (sync) { this.M00 += m00; this.M01 += m01; this.M10 += m10; this.M11 += m11; this.M02 += m02; this.M20 += m20; this.M12 += m12; this.M21 += m21; this.M30 += m30; this.M03 += m03; } } /*,new ParallelOptions { ForceSequential = true}*/); proc.Process(image); InvM00 = 1f / M00; CenterX = M10 * InvM00; CenterY = M01 * InvM00; }
/// <summary> /// Converts an image by using specified conversion path. /// </summary> /// <param name="img">Image to convert.</param> /// <param name="conversionData">Conversion path.</param> /// <returns>Converted image.</returns> public static IImage Convert(this IImage img, ConversionData <ColorInfo> conversionData) { var proc = new ParallelProcessor <IImage, IImage> ( img.Size, () => conversionData.CreateFunc(img, conversionData.Destination), (src, dest, area) => conversionData.ConvertFunc(src.GetSubRect(area), dest.GetSubRect(area)) #if DEBUG , new ParallelOptions2D { ForceSequential = true } #else , new ParallelOptions2D { ForceSequential = conversionData.ForceSequential } #endif ); return(proc.Process(img)); }
internal static void MergeChannels(IImage[] channels, IImage destImg, params int[] destChannelIndicies) { if (destChannelIndicies == null || destChannelIndicies.Length == 0) { destChannelIndicies = Enumerable.Range(0, channels.Length).ToArray(); } Type depthType = destImg.ColorInfo.ChannelType; MergeImage merger = null; if (mergers.TryGetValue(depthType, out merger) == false) { throw new Exception(string.Format("Merge function can not merge image of color depth type {0}", depthType)); } ParallelProcessor <IImage[], IImage> proc = new ParallelProcessor <IImage[], IImage>(destImg.Size, () => //called once { return(destImg); }, (IImage[] _channels, IImage _destImg, Rectangle area) => //called for every thread { IImage[] channelsPatches = new IImage[_channels.Length]; for (int i = 0; i < channelsPatches.Length; i++) { channelsPatches[i] = _channels[i].GetSubRect(area); } IImage imgPatch = _destImg.GetSubRect(area); merger(channelsPatches, imgPatch, destChannelIndicies); } /*,new ParallelOptions { ForceSequential = true}*/); proc.Process(channels); //result is in srcImg }
/// <summary> /// Find non-zero locations in the image. /// </summary> /// <typeparam name="TDepth">Channel type.</typeparam> /// <param name="img">Image.</param> /// <param name="values">Values for the found locations.</param> /// <returns>List of found non-zero locations.</returns> public static List <Point> FindNonZero <TDepth>(this Image <Gray, TDepth> img, out List <TDepth> values) where TDepth : struct { FindNonZeroFunc findNonZeroFunc = null; if (findNonZeroFuncs.TryGetValue(img.ColorInfo.ChannelType, out findNonZeroFunc) == false) { throw new NotSupportedException(string.Format("Can not perform FindNonZero on an image of type {0}", img.ColorInfo.ChannelType.Name)); } var locations = new List <Point>(); var _values = new List <TDepth>(); var proc = new ParallelProcessor <IImage, bool>(img.Size, () => true, (_src, _, area) => { List <Point> locationsPatch; IList valuesPatch; findNonZeroFunc(img.GetSubRect(area), out locationsPatch, out valuesPatch); lock (locations) lock (_values) { locationsPatch.ForEach(x => { locations.Add(x + area.Location); }); _values.AddRange(valuesPatch as IList <TDepth>); } }); proc.Process(img); values = _values; return(locations); }
private static void calculate(MathOps mathOpIdx, IImage src1, IImage src2, IImage dest, Image <Gray, byte> mask = null) { Debug.Assert(src1.ColorInfo.Equals(src2.ColorInfo) && src1.Size.Equals(src2.Size)); if (mask == null) { mask = new Image <Gray, byte>(dest.Width, dest.Height); mask.SetValue(new Gray(255)); } var mathOperationOnTypes = mathOperatorFuncs[(int)mathOpIdx]; MathOpFunc mathOpFunc = null; if (mathOperationOnTypes.TryGetValue(src1.ColorInfo.ChannelType, out mathOpFunc) == false) { throw new Exception(string.Format("Math operation {0} can not be executed on an image of type {1}", mathOpIdx.ToString(), src1.ColorInfo.ChannelType)); } var proc = new ParallelProcessor <bool, bool>(dest.Size, () => { return(true); }, (bool _, bool __, Rectangle area) => { var src1Patch = src1.GetSubRect(area); var src2Patch = src2.GetSubRect(area); var destPatch = dest.GetSubRect(area); var maskPatch = mask.GetSubRect(area); mathOpFunc(src1Patch, src2Patch, destPatch, maskPatch); } /*,new ParallelOptions { ForceSequential = true}*/); proc.Process(true); }
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)); }
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>); }
/// <summary> /// Two dimensional Fast Fourier Transform. /// </summary> /// <param name="width">Image width.</param> /// <param name="height">Image height.</param> /// <param name="stride">Image stride.</param> /// <param name="data">Data to transform.</param> /// <param name="direction">Transformation direction.</param> /// /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size /// only in each dimension, where <b>n</b> may vary in the [1, 14] range. For example, 16x16 array /// is valid, but 15x15 is not.</note></para></remarks> /// /// <exception cref="ArgumentException">Incorrect data length.</exception> /// public static unsafe void FFT2(ComplexF* data, int width, int height, int stride, Direction direction) { const int MIN_PATCH_SIZE = 32; //how much rows/columns should one thread process int k = height; int n = width; // check data size if ( (!AForge.Math.Tools.IsPowerOf2(k)) || (!AForge.Math.Tools.IsPowerOf2(n)) || (k < minLength) || (k > maxLength) || (n < minLength) || (n > maxLength) ) { throw new ArgumentException("Incorrect data length."); } // process rows var procRow = new ParallelProcessor<bool, bool>(new Size(1 /*does not matter*/, height), () => true, (_, __, area) => { ComplexF* dataPatchPtr = data + area.Y * stride / sizeof(ComplexF); //get row for (int i = 0; i < area.Height; i++) { // transform it FourierTransform.FFT(dataPatchPtr, n, direction); dataPatchPtr += stride / sizeof(ComplexF); } }, new ParallelOptions2D { ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE /*,ForceSequential = true*/} ); // process columns //(y and x are swaped => proc thinks it is diving horizontal pacthes but instead we are using them as vertical ones) var procCol = new ParallelProcessor<bool, bool>(new Size(1 /*does not matter*/, width), () => true, (_, __, area) => { ComplexF* dataPatchPtr = &data[area.Y]; //get column fixed (ComplexF* _col = new ComplexF[k]) { ComplexF* col = _col; for (int j = 0; j < area.Height; j++) { // copy column ComplexF* dataColPtr = &dataPatchPtr[j]; for (int i = 0; i < k; i++) { col[i] = *dataColPtr; dataColPtr += stride / sizeof(ComplexF); } // transform it FourierTransform.FFT(col, k, direction); // copy back dataColPtr = &dataPatchPtr[j]; for (int i = 0; i < k; i++) { *dataColPtr = col[i]; dataColPtr += stride / sizeof(ComplexF); } } } }, new ParallelOptions2D { ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE /*,ForceSequential = true */} ); procRow.Process(true); procCol.Process(true); }
IEnumerator WriteCameraFeed() { writingCamFile = true; var tempLocalPos = feedCam.transform.localPosition; var bridgeCamPos = memoryBridge.GetVector3("CamLocalPos" + fileName + memoryBridge.cameraFeeds.Count); tempLocalPos.x = bridgeCamPos.x; tempLocalPos.y = -bridgeCamPos.z; tempLocalPos.z = bridgeCamPos.y; feedCam.transform.localPosition = tempLocalPos; feedCam.transform.localEulerAngles = memoryBridge.GetVector3("CamLocalEuler" + fileName + memoryBridge.cameraFeeds.Count); RenderTexture.active = rendText; tex.ReadPixels(new Rect(0, 0, rendTextWidth, rendTextHeight), 0, 0); //tex.Apply(); // camTexture = tex; var textureByte = tex.GetRawTextureData(); // //Debug.Log(textureByte.Length); var multiple = textureByte.Length / threadList.Count; Stream mapStream0 = camFeedFile.MapView(MapAccess.FileMapAllAccess, 0, multiple); Stream mapStream1 = camFeedFile.MapView(MapAccess.FileMapAllAccess, 0, multiple); Stream mapStream2 = camFeedFile.MapView(MapAccess.FileMapAllAccess, 0, multiple); Stream mapStream3 = camFeedFile.MapView(MapAccess.FileMapAllAccess, 0, multiple); ParallelProcessor.EachParallel(threadList, thread => { switch (thread) { case 0: mapStream0.Write(textureByte, 0, multiple); break; case 1: mapStream1.Write(textureByte, 0, multiple); break; case 2: mapStream2.Write(textureByte, 0, multiple); break; case 3: mapStream3.Write(textureByte, 0, multiple); break; } }); mapStream0.Flush(); mapStream1.Flush(); mapStream2.Flush(); mapStream3.Flush(); mapStream0.Close(); mapStream1.Close(); mapStream2.Close(); mapStream3.Close(); RenderTexture.active = null; writingCamFile = false; yield break; }
internal override void Compute(IImage image) { Reset(); RawMomentsFunc rawMomentsFunc = null; if (rawMomentsFuncs.TryGetValue(image.ColorInfo.ChannelType, out rawMomentsFunc) == false) throw new Exception(string.Format("Raw moments can not be calculated of an image of type {0}", image.ColorInfo.ChannelType)); object sync = new object(); ParallelProcessor<IImage, bool> proc = new ParallelProcessor<IImage, bool>(image.Size, () => { return true; }, (IImage src, bool _, Rectangle area) => //called for every thread { IntPoint offset = new IntPoint(area.X, area.Y); float m00, m01, m10, m11, m02, m20, m12, m21, m30, m03; rawMomentsFunc(src.GetSubRect(area), offset, Order, out m00, out m01, out m10, out m11, out m02, out m20, out m12, out m21, out m30, out m03); lock (sync) { this.M00 += m00; this.M01 += m01; this.M10 += m10; this.M11 += m11; this.M02 += m02; this.M20 += m20; this.M12 += m12; this.M21 += m21; this.M30 += m30; this.M03 += m03; } } /*,new ParallelOptions { ForceSequential = true}*/); proc.Process(image); InvM00 = 1f / M00; CenterX = M10 * InvM00; CenterY = M01 * InvM00; }
/// <summary> /// Two dimensional Fast Fourier Transform. /// </summary> /// <param name="width">Image width.</param> /// <param name="height">Image height.</param> /// <param name="stride">Image stride.</param> /// <param name="data">Data to transform.</param> /// <param name="direction">Transformation direction.</param> /// /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size /// only in each dimension, where <b>n</b> may vary in the [1, 14] range. For example, 16x16 array /// is valid, but 15x15 is not.</note></para></remarks> /// /// <exception cref="ArgumentException">Incorrect data length.</exception> /// public unsafe static void FFT2(ComplexF *data, int width, int height, int stride, Direction direction) { const int MIN_PATCH_SIZE = 32; //how much rows/columns should one thread process int k = height; int n = width; // check data size if ( (!AForge.Math.Tools.IsPowerOf2(k)) || (!AForge.Math.Tools.IsPowerOf2(n)) || (k < minLength) || (k > maxLength) || (n < minLength) || (n > maxLength) ) { throw new ArgumentException("Incorrect data length."); } // process rows var procRow = new ParallelProcessor <bool, bool>(new Size(1 /*does not matter*/, height), () => true, (_, __, area) => { ComplexF *dataPatchPtr = data + area.Y * stride / sizeof(ComplexF); //get row for (int i = 0; i < area.Height; i++) { // transform it FourierTransform.FFT(dataPatchPtr, n, direction); dataPatchPtr += stride / sizeof(ComplexF); } }, new ParallelOptions2D { ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE /*,ForceSequential = true*/ } ); // process columns //(y and x are swaped => proc thinks it is diving horizontal pacthes but instead we are using them as vertical ones) var procCol = new ParallelProcessor <bool, bool>(new Size(1 /*does not matter*/, width), () => true, (_, __, area) => { ComplexF *dataPatchPtr = &data[area.Y]; //get column fixed(ComplexF * _col = new ComplexF[k]) { ComplexF *col = _col; for (int j = 0; j < area.Height; j++) { // copy column ComplexF *dataColPtr = &dataPatchPtr[j]; for (int i = 0; i < k; i++) { col[i] = *dataColPtr; dataColPtr += stride / sizeof(ComplexF); } // transform it FourierTransform.FFT(col, k, direction); // copy back dataColPtr = &dataPatchPtr[j]; for (int i = 0; i < k; i++) { *dataColPtr = col[i]; dataColPtr += stride / sizeof(ComplexF); } } } }, new ParallelOptions2D { ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE /*,ForceSequential = true */ } ); procRow.Process(true); procCol.Process(true); }
private static void calculate(MathOps mathOpIdx, IImage src1, IImage src2, IImage dest, Image<Gray, byte> mask = null) { Debug.Assert(src1.ColorInfo.Equals(src2.ColorInfo) && src1.Size.Equals(src2.Size)); if (mask == null) { mask = new Image<Gray, byte>(dest.Width, dest.Height); mask.SetValue(new Gray(255)); } var mathOperationOnTypes = mathOperatorFuncs[(int)mathOpIdx]; MathOpFunc mathOpFunc = null; if (mathOperationOnTypes.TryGetValue(src1.ColorInfo.ChannelType, out mathOpFunc) == false) throw new Exception(string.Format("Math operation {0} can not be executed on an image of type {1}", mathOpIdx.ToString(), src1.ColorInfo.ChannelType)); var proc = new ParallelProcessor<bool, bool>(dest.Size, () => { return true; }, (bool _, bool __, Rectangle area) => { var src1Patch = src1.GetSubRect(area); var src2Patch = src2.GetSubRect(area); var destPatch = dest.GetSubRect(area); var maskPatch = mask.GetSubRect(area); mathOpFunc(src1Patch, src2Patch, destPatch, maskPatch); } /*,new ParallelOptions { ForceSequential = true}*/); proc.Process(true); }