public void Indexer(int width, int height, int x, int y) { using (PinnedImageBuffer <Foo> buffer = new PinnedImageBuffer <Foo>(width, height)) { Foo[] array = buffer.Array; ref Foo actual = ref buffer[x, y]; ref Foo expected = ref array[y * width + x];
public void Construct(int width, int height) { using (PinnedImageBuffer <Foo> buffer = new PinnedImageBuffer <Foo>(width, height)) { Assert.Equal(width, buffer.Width); Assert.Equal(height, buffer.Height); Assert.Equal(width * height, buffer.Length); } }
public void Construct_FromExternalArray(int width, int height) { Foo[] array = new Foo[width * height + 10]; using (PinnedImageBuffer <Foo> buffer = new PinnedImageBuffer <Foo>(array, width, height)) { Assert.Equal(width, buffer.Width); Assert.Equal(height, buffer.Height); Assert.Equal(width * height, buffer.Length); } }
public void GetRowSpanXY(int width, int height, int x, int y) { using (PinnedImageBuffer <Foo> buffer = new PinnedImageBuffer <Foo>(width, height)) { BufferSpan <Foo> span = buffer.GetRowSpan(x, y); Assert.Equal(width * y + x, span.Start); Assert.Equal(width - x, span.Length); Assert.Equal(buffer.Pointer + sizeof(Foo) * (width * y + x), span.PointerAtOffset); } }
public void CreateClean() { for (int i = 0; i < 100; i++) { using (PinnedImageBuffer <int> buffer = PinnedImageBuffer <int> .CreateClean(42, 42)) { for (int j = 0; j < buffer.Length; j++) { Assert.Equal(0, buffer.Array[j]); buffer.Array[j] = 666; } } } }
public Vector4 ComputeWeightedColumnSum(PinnedImageBuffer <Vector4> firstPassPixels, int x) { float *verticalValues = this.Ptr; int left = this.Left; // Destination color components Vector4 result = Vector4.Zero; for (int i = 0; i < this.Length; i++) { float yw = verticalValues[i]; int index = left + i; result += firstPassPixels[x, index] * yw; } return(result); }
/// <summary> /// Initializes a new instance of the <see cref="WeightsBuffer"/> class. /// </summary> /// <param name="sourceSize">The size of the source window</param> /// <param name="destinationSize">The size of the destination window</param> public WeightsBuffer(int sourceSize, int destinationSize) { this.dataBuffer = PinnedImageBuffer <float> .CreateClean(sourceSize, destinationSize); this.Weights = new WeightsWindow[destinationSize]; }
/// <inheritdoc/> protected override unsafe void OnApply(ImageBase <TColor> source, Rectangle sourceRectangle) { // Jump out, we'll deal with that later. if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle) { return; } int width = this.Width; int height = this.Height; int sourceX = sourceRectangle.X; int sourceY = sourceRectangle.Y; int startY = this.ResizeRectangle.Y; int endY = this.ResizeRectangle.Bottom; int startX = this.ResizeRectangle.X; int endX = this.ResizeRectangle.Right; int minX = Math.Max(0, startX); int maxX = Math.Min(width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(height, endY); if (this.Sampler is NearestNeighborResampler) { // Scaling factors float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width; float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height; using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height)) { using (PixelAccessor <TColor> sourcePixels = source.Lock()) { Parallel.For( minY, maxY, this.ParallelOptions, y => { // Y coordinates of source points int originY = (int)(((y - startY) * heightFactor) + sourceY); for (int x = minX; x < maxX; x++) { // X coordinates of source points targetPixels[x, y] = sourcePixels[(int)(((x - startX) * widthFactor) + sourceX), originY]; } }); } // Break out now. source.SwapPixelsBuffers(targetPixels); return; } } // Interpolate the image using the calculated weights. // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm // First process the columns. Since we are not using multiple threads startY and endY // are the upper and lower bounds of the source rectangle. // TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed! using (PixelAccessor <TColor> targetPixels = new PixelAccessor <TColor>(width, height)) { using (PixelAccessor <TColor> sourcePixels = source.Lock()) using (PinnedImageBuffer <Vector4> firstPassPixels = new PinnedImageBuffer <Vector4>(width, source.Height)) { firstPassPixels.Clear(); Parallel.For( 0, sourceRectangle.Bottom, this.ParallelOptions, y => { // TODO: Without Parallel.For() this buffer object could be reused: using (PinnedBuffer <Vector4> tempRowBuffer = new PinnedBuffer <Vector4>(sourcePixels.Width)) { BufferSpan <TColor> sourceRow = sourcePixels.GetRowSpan(y); BulkPixelOperations <TColor> .Instance.ToVector4( sourceRow, tempRowBuffer, sourceRow.Length); if (this.Compand) { for (int x = minX; x < maxX; x++) { WeightsWindow window = this.HorizontalWeights.Weights[x - startX]; firstPassPixels[x, y] = window.ComputeExpandedWeightedRowSum(tempRowBuffer); } } else { for (int x = minX; x < maxX; x++) { WeightsWindow window = this.HorizontalWeights.Weights[x - startX]; firstPassPixels[x, y] = window.ComputeWeightedRowSum(tempRowBuffer); } } } }); // Now process the rows. Parallel.For( minY, maxY, this.ParallelOptions, y => { // Ensure offsets are normalised for cropping and padding. WeightsWindow window = this.VerticalWeights.Weights[y - startY]; if (this.Compand) { for (int x = 0; x < width; x++) { // Destination color components Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x); destination = destination.Compress(); TColor d = default(TColor); d.PackFromVector4(destination); targetPixels[x, y] = d; } } else { for (int x = 0; x < width; x++) { // Destination color components Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x); TColor d = default(TColor); d.PackFromVector4(destination); targetPixels[x, y] = d; } } }); } source.SwapPixelsBuffers(targetPixels); } }