public void CheckPassingOrTest() { // given: chain with filters var chain = new PixelFilterChain() { Mode = LogicMode.Or }; var valueFilter1 = new Mock <IPixelValueFilter>(MockBehavior.Strict); valueFilter1.Setup(v => v.Check(It.IsAny <byte>())).Returns(false); var valueFilter2 = new Mock <IPixelValueFilter>(MockBehavior.Strict); valueFilter2.Setup(v => v.Check(It.IsAny <byte>())).Returns(false); var indexFilter1 = new Mock <IPixelIndexFilter>(MockBehavior.Strict); indexFilter1.Setup(i => i.Check(It.IsAny <int>())).Returns(false); var indexFilter2 = new Mock <IPixelIndexFilter>(MockBehavior.Strict); indexFilter2.Setup(i => i.Check(It.IsAny <int>())).Returns(true); chain.AddPixelFilter(valueFilter1.Object); chain.AddPixelFilter(valueFilter2.Object); chain.AddPixelFilter(indexFilter1.Object); chain.AddPixelFilter(indexFilter2.Object); // when: checking // then: passes Assert.That(chain.Check(0, 0), Is.True); }
public void CheckEmptyTest() { // given: empty chain var chain = new PixelFilterChain(); // when: checking with empty chain // then: passes Assert.That(chain.Check(0, 0), Is.True); }
/// <summary> /// Processes the pixels of the given <paramref name="plane"/> /// in the given <paramref name="bounds"/> with the /// given <paramref name="processorFunc"/>. /// </summary> /// <param name="plane">The plane whose pixels to process.</param> /// <param name="bounds">Bounds defining which pixels to process.</param> /// <param name="processorFunc">Func that takes a byte, processes /// it and returns a byte.</param> /// <param name="filterChain">Optional filter chain.</param> public static void ProcessMono(ImagePlane plane, ProcessingBounds bounds, Func <byte, byte> processorFunc, PixelFilterChain filterChain) { if (filterChain == null || !filterChain.HasActiveFilter) { ProcessMono(plane, bounds, processorFunc); return; } if (processorFunc == null) { throw new ArgumentNullException(nameof(processorFunc)); } if (plane.TryGetLinearAccess(out LinearAccessData data)) { var yInc = (int)data.YInc; var xInc = (int)data.XInc; int startY = bounds.StartY; int startX = bounds.StartX; int boundsY = startY + bounds.Height; int boundsX = startX + bounds.Width; unsafe { var pBase = (byte *)data.BasePtr; Parallel.For(startY, boundsY, (y) => { byte *pLine = pBase + yInc * y; for (int x = startX; x < boundsX; x++) { byte *pPixel = pLine + xInc * x; if (filterChain.Check(*pPixel, y * boundsY + x)) { *pPixel = processorFunc.Invoke(*pPixel); } } }); } } else { throw new ArgumentException("Plane could not be accessed linear", nameof(plane)); } }
/// <summary> /// Processes the given rgb <paramref name="img"/> in the /// given <paramref name="bounds"/> with /// the given <paramref name="processingFunc"/>. /// </summary> /// <param name="img">Image to process.</param> /// <param name="processingFunc">Processing function to process /// the <paramref name="img"/> with.</param> /// <param name="bounds">Bounds defining which pixels to process.</param> /// <param name="filterChain">Optional filter chain.</param> public static void ProcessRGB(Image img, Func <RGBPixel, RGBPixel> processingFunc, ProcessingBounds bounds, PixelFilterChain filterChain) { if (filterChain == null || !filterChain.HasActiveFilter) { ProcessRGB(img, processingFunc, bounds); return; } if (img == null) { throw new ArgumentNullException(nameof(img)); } if (img.Planes.Count < 3) { throw new ArgumentException("Image is no rgb image", nameof(img)); } if (processingFunc == null) { throw new ArgumentNullException(nameof(processingFunc)); } if (img.Planes[0].TryGetLinearAccess(out LinearAccessData rData) && img.Planes[1].TryGetLinearAccess(out LinearAccessData gData) && img.Planes[2].TryGetLinearAccess(out LinearAccessData bData)) { int startY = bounds.StartY; int startX = bounds.StartX; int boundsY = startY + bounds.Height; int boundsX = startX + bounds.Width; var rYInc = (int)rData.YInc; var gYInc = (int)gData.YInc; var bYInc = (int)bData.YInc; var rXInc = (int)rData.XInc; var gXInc = (int)gData.XInc; var bXInc = (int)bData.XInc; unsafe { var pBaseR = (byte *)rData.BasePtr; var pBaseG = (byte *)gData.BasePtr; var pBaseB = (byte *)bData.BasePtr; Parallel.For(startY, boundsY, (y) => { byte *rLine = pBaseR + rYInc * y; byte *gLine = pBaseG + gYInc * y; byte *bLine = pBaseB + bYInc * y; for (int x = startX; x < boundsX; x++) { byte *rPixel = rLine + rXInc * x; byte *gPixel = gLine + gXInc * x; byte *bPixel = bLine + bXInc * x; if (filterChain.Check(*rPixel, *gPixel, *bPixel, y * boundsY + x)) { var result = processingFunc.Invoke(new RGBPixel(*rPixel, *gPixel, *bPixel)); *rPixel = result.R; *gPixel = result.G; *bPixel = result.B; } } }); } }
public static ImagePlane ProcessMonoKernel(ImagePlane plane, Func <byte?[], byte> processingFunc, KernelSize kernel, ProcessingBounds bounds, PixelFilterChain filterChain) { if (filterChain == null || !filterChain.HasActiveFilter) { return(ProcessMonoKernel(plane, processingFunc, kernel, bounds)); } if (plane.TryGetLinearAccess(out LinearAccessData data)) { var newImage = Image.FromPlanes(MappingOption.CopyPixels, plane); var newData = newImage.Planes[0].GetLinearAccess(); var yInc = (int)data.YInc; var xInc = (int)data.XInc; var newYInc = (int)newData.YInc; var newXInc = (int)newData.XInc; int boundHeight = plane.Parent.Height - 1; int boundWidth = plane.Parent.Width - 1; int startY = bounds.StartY; int startX = bounds.StartX; int boundsY = startY + bounds.Height; int boundsX = startX + bounds.Width; int kernelSize = kernel.GetKernelNumber(); int kernelArrSize = kernelSize * kernelSize; var kernelFac = (int)System.Math.Floor(kernelSize / 2.0); unsafe { var pBase = (byte *)data.BasePtr; var pBaseNew = (byte *)newData.BasePtr; Parallel.For(startY, boundsY, (y) => { var kernelValues = new byte?[kernelArrSize]; var pLine = pBase + y * yInc; int newLineInc = newYInc * y; for (int x = startX; x < boundsX; x++) { int kernelCounter = -1; var pMiddle = pLine + xInc * x; for (int kRow = -kernelFac; kRow <= kernelFac; kRow++) { byte *pKLine = pMiddle + kRow * yInc; int yKRow = y + kRow; for (int kColumn = -kernelFac; kColumn <= kernelFac; kColumn++) { kernelCounter++; int xKColumn = x + kColumn; if (yKRow < 0 || yKRow > boundHeight || xKColumn < 0 || xKColumn > boundWidth) { continue; } byte *pPixel = pKLine + kColumn * xInc; if (filterChain.Check(*pPixel, y * boundsY + x)) { kernelValues[kernelCounter] = *pPixel; } } } if (kernelValues.Any(b => b.HasValue)) { var pTargetLine = pBaseNew + newLineInc; var pTargetPixel = pTargetLine + newXInc * x; // current "middle pixel" in the target image *pTargetPixel = processingFunc.Invoke(kernelValues); } } }); } return(newImage.Planes[0]); } else { throw new ArgumentException("Plane could not be accessed linear", nameof(plane)); } }