Browse Source

Attempt to speed up operations using vectors.

Former-commit-id: a28745bb3a7a48769718459f660aee59dc6727fd
Former-commit-id: 3cea324866d570efa674f7ea8cfcf964a3283f58
Former-commit-id: 8eb414b88e6c70055d2653818694c0fc8c95ba83
af/merge-core
James Jackson-South 11 years ago
parent
commit
eabdd9074b
  1. 2
      src/ImageProcessor/Colors/Bgra.cs
  2. 193
      src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs
  3. 34
      src/ImageProcessor/Common/Helpers/PixelOperations.cs
  4. 11
      src/ImageProcessor/Samplers/Resize.cs
  5. 16
      tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs

2
src/ImageProcessor/Colors/Bgra.cs

@ -194,7 +194,7 @@ namespace ImageProcessor
/// </returns>
public static implicit operator Bgra(ColorVector color)
{
return new Bgra((255 * color.B).ToByte(), (255 * color.G).ToByte(), (255 * color.R).ToByte(), (255 * color.A).ToByte());
return new Bgra((255f * color.B).ToByte(), (255f * color.G).ToByte(), (255f * color.R).ToByte(), (255f * color.A).ToByte());
}
/// <summary>

193
src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs

@ -0,0 +1,193 @@
// <copyright file="PixelOperations.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor
{
using System;
/// <summary>
/// Performs per-pixel operations.
/// </summary>
public static class PixelOperations
{
/// <summary>
/// The array of bytes representing each possible value of color component
/// converted from sRGB to the linear color space.
/// </summary>
private static readonly Lazy<byte[]> LinearBytes = new Lazy<byte[]>(GetLinearBytes);
/// <summary>
/// The array of bytes representing each possible value of color component
/// converted from linear to the sRGB color space.
/// </summary>
private static readonly Lazy<byte[]> SrgbBytes = new Lazy<byte[]>(GetSrgbBytes);
/// <summary>
/// The array of bytes representing each possible value of color component
/// converted from gamma to the linear color space.
/// </summary>
private static readonly Lazy<byte[]> LinearGammaBytes = new Lazy<byte[]>(GetLinearGammaBytes);
/// <summary>
/// The array of bytes representing each possible value of color component
/// converted from linear to the gamma color space.
/// </summary>
private static readonly Lazy<byte[]> GammaLinearBytes = new Lazy<byte[]>(GetGammaLinearBytes);
/// <summary>
/// Converts an pixel from an sRGB color-space to the equivalent linear color-space.
/// </summary>
/// <param name="composite">
/// The <see cref="Bgra"/> to convert.
/// </param>
/// <returns>
/// The <see cref="Bgra"/>.
/// </returns>
public static Bgra ToLinear(Bgra composite)
{
// Create only once and lazily.
// byte[] ramp = LinearGammaBytes.Value;
byte[] ramp = LinearBytes.Value;
return new Bgra(ramp[composite.B], ramp[composite.G], ramp[composite.R], composite.A);
}
/// <summary>
/// Converts a pixel from a linear color-space to the equivalent sRGB color-space.
/// </summary>
/// <param name="linear">
/// The <see cref="Bgra"/> to convert.
/// </param>
/// <returns>
/// The <see cref="Bgra"/>.
/// </returns>
public static Bgra ToSrgb(Bgra linear)
{
// Create only once and lazily.
// byte[] ramp = GammaLinearBytes.Value;
byte[] ramp = SrgbBytes.Value;
return new Bgra(ramp[linear.B], ramp[linear.G], ramp[linear.R], linear.A);
}
/// <summary>
/// Gets an array of bytes representing each possible value of color component
/// converted from sRGB to the linear color space.
/// </summary>
/// <returns>
/// The <see cref="T:byte[]"/>.
/// </returns>
private static byte[] GetLinearBytes()
{
byte[] ramp = new byte[256];
for (int x = 0; x < 256; ++x)
{
byte val = (255f * SrgbToLinear(x / 255f)).ToByte();
ramp[x] = val;
}
return ramp;
}
/// <summary>
/// Gets an array of bytes representing each possible value of color component
/// converted from linear to the sRGB color space.
/// </summary>
/// <returns>
/// The <see cref="T:byte[]"/>.
/// </returns>
private static byte[] GetSrgbBytes()
{
byte[] ramp = new byte[256];
for (int x = 0; x < 256; ++x)
{
byte val = (255f * LinearToSrgb(x / 255f)).ToByte();
ramp[x] = val;
}
return ramp;
}
/// <summary>
/// Gets the correct linear value from an sRGB signal.
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
/// </summary>
/// <param name="signal">The signal value to convert.</param>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
private static float SrgbToLinear(float signal)
{
float a = 0.055f;
if (signal <= 0.04045)
{
return signal / 12.92f;
}
return (float)Math.Pow((signal + a) / (1 + a), 2.4);
}
/// <summary>
/// Gets the correct sRGB value from an linear signal.
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
/// </summary>
/// <param name="signal">The signal value to convert.</param>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
private static float LinearToSrgb(float signal)
{
float a = 0.055f;
if (signal <= 0.0031308)
{
return signal * 12.92f;
}
return ((float)((1 + a) * Math.Pow(signal, 1 / 2.4f))) - a;
}
/// <summary>
/// Gets an array of bytes representing each possible value of color component
/// converted from gamma to the linear color space.
/// </summary>
/// <returns>
/// The <see cref="T:byte[]"/>.
/// </returns>
private static byte[] GetLinearGammaBytes()
{
byte[] ramp = new byte[256];
for (int x = 0; x < 256; ++x)
{
byte val = (255f * Math.Pow(x / 255f, 2.2)).ToByte();
ramp[x] = val;
}
return ramp;
}
/// <summary>
/// Gets an array of bytes representing each possible value of color component
/// converted from linear to the gamma color space.
/// </summary>
/// <returns>
/// The <see cref="T:byte[]"/>.
/// </returns>
private static byte[] GetGammaLinearBytes()
{
byte[] ramp = new byte[256];
for (int x = 0; x < 256; ++x)
{
byte val = (255f * Math.Pow(x / 255f, 1 / 2.2)).ToByte();
ramp[x] = val;
}
return ramp;
}
}
}

34
src/ImageProcessor/Common/Helpers/PixelOperations.cs

@ -13,16 +13,16 @@ namespace ImageProcessor
public static class PixelOperations
{
/// <summary>
/// The array of bytes representing each possible value of color component
/// The array of values representing each possible value of color component
/// converted from sRGB to the linear color space.
/// </summary>
private static readonly Lazy<byte[]> LinearBytes = new Lazy<byte[]>(GetLinearBytes);
private static readonly Lazy<float[]> LinearLut = new Lazy<float[]>(GetLinearBytes);
/// <summary>
/// The array of bytes representing each possible value of color component
/// The array of values representing each possible value of color component
/// converted from linear to the sRGB color space.
/// </summary>
private static readonly Lazy<byte[]> SrgbBytes = new Lazy<byte[]>(GetSrgbBytes);
private static readonly Lazy<float[]> SrgbLut = new Lazy<float[]>(GetSrgbBytes);
/// <summary>
/// The array of bytes representing each possible value of color component
@ -45,13 +45,14 @@ namespace ImageProcessor
/// <returns>
/// The <see cref="Bgra"/>.
/// </returns>
public static Bgra ToLinear(Bgra composite)
public static Bgra ToLinear(ColorVector composite)
{
// Create only once and lazily.
// byte[] ramp = LinearGammaBytes.Value;
byte[] ramp = LinearBytes.Value;
float[] ramp = LinearLut.Value;
return new Bgra(ramp[composite.B], ramp[composite.G], ramp[composite.R], composite.A);
// TODO: This just doesn't seem right to me.
return new ColorVector(ramp[(composite.B * 255).ToByte()], ramp[(composite.G * 255).ToByte()], ramp[(composite.R * 255).ToByte()], composite.A);
}
/// <summary>
@ -63,13 +64,14 @@ namespace ImageProcessor
/// <returns>
/// The <see cref="Bgra"/>.
/// </returns>
public static Bgra ToSrgb(Bgra linear)
public static Bgra ToSrgb(ColorVector linear)
{
// Create only once and lazily.
// byte[] ramp = GammaLinearBytes.Value;
byte[] ramp = SrgbBytes.Value;
float[] ramp = SrgbLut.Value;
return new Bgra(ramp[linear.B], ramp[linear.G], ramp[linear.R], linear.A);
// TODO: This just doesn't seem right to me.
return new ColorVector(ramp[(linear.B * 255).ToByte()], ramp[(linear.G * 255).ToByte()], (linear.R * 255).ToByte(), linear.A);
}
/// <summary>
@ -79,12 +81,12 @@ namespace ImageProcessor
/// <returns>
/// The <see cref="T:byte[]"/>.
/// </returns>
private static byte[] GetLinearBytes()
private static float[] GetLinearBytes()
{
byte[] ramp = new byte[256];
float[] ramp = new float[256];
for (int x = 0; x < 256; ++x)
{
byte val = (255f * SrgbToLinear(x / 255f)).ToByte();
float val = SrgbToLinear(x / 255f);
ramp[x] = val;
}
@ -98,12 +100,12 @@ namespace ImageProcessor
/// <returns>
/// The <see cref="T:byte[]"/>.
/// </returns>
private static byte[] GetSrgbBytes()
private static float[] GetSrgbBytes()
{
byte[] ramp = new byte[256];
float[] ramp = new float[256];
for (int x = 0; x < 256; ++x)
{
byte val = (255f * LinearToSrgb(x / 255f)).ToByte();
float val = LinearToSrgb(x / 255f);
ramp[x] = val;
}

11
src/ImageProcessor/Samplers/Resize.cs

@ -7,6 +7,7 @@ namespace ImageProcessor.Samplers
{
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Threading.Tasks;
/// <summary>
@ -61,6 +62,7 @@ namespace ImageProcessor.Samplers
int targetBottom = targetRectangle.Bottom;
int startX = targetRectangle.X;
int endX = targetRectangle.Right;
//Vector<int> endVX = new Vector<int>(targetRectangle.Right);
Parallel.For(
startY,
@ -100,8 +102,8 @@ namespace ImageProcessor.Samplers
}
int originX = xw.Index;
Bgra sourceColor = source[originX, originY];
//ColorVector sourceColor = PixelOperations.ToLinear(source[originX, originY]);
ColorVector sourceColor = source[originX, originY];
//sourceColor = PixelOperations.ToLinear(sourceColor);
r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum);
g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum);
@ -110,9 +112,8 @@ namespace ImageProcessor.Samplers
}
}
// TODO: Double cast.
Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), a.ToByte());
//Bgra destinationColor = PixelOperations.ToSrgb(new ColorVector(b, g, r, a));
// TODO: Double cast?
Bgra destinationColor = new ColorVector(b, g, r, a);//PixelOperations.ToSrgb(new ColorVector(b, g, r, a));
target[x, y] = destinationColor;
}
}

16
tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs

@ -20,14 +20,14 @@ namespace ImageProcessor.Tests
public static readonly List<string> Files = new List<string>
{
"../../TestImages/Formats/Jpg/Backdrop.jpg",
"../../TestImages/Formats/Jpg/Calliphora.jpg",
"../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg",
"../../TestImages/Formats/Jpg/greyscale.jpg",
"../../TestImages/Formats/Bmp/Car.bmp",
"../../TestImages/Formats/Png/cmyk.png",
"../../TestImages/Formats/Png/gamma-1.0-or-2.2.png",
"../../TestImages/Formats/Gif/leaf.gif",
"../../TestImages/Formats/Gif/rings.gif"
//"../../TestImages/Formats/Jpg/Calliphora.jpg",
//"../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg",
//"../../TestImages/Formats/Jpg/greyscale.jpg",
//"../../TestImages/Formats/Bmp/Car.bmp",
//"../../TestImages/Formats/Png/cmyk.png",
//"../../TestImages/Formats/Png/gamma-1.0-or-2.2.png",
//"../../TestImages/Formats/Gif/leaf.gif",
//"../../TestImages/Formats/Gif/rings.gif"
// { "../../TestImages/Formats/Gif/ani.gif" },
// { "../../TestImages/Formats/Gif/ani2.gif" },

Loading…
Cancel
Save