Browse Source

Add ColorBlindness

Former-commit-id: 5ce61ca1e508ed598370b5817fa54fa6aaf7ecff
Former-commit-id: b04c8676420dad90a6cb9515bdc8b9db67752576
Former-commit-id: 98da045e3b41b5369a5d8ef393b2b22b8c011665
pull/1/head
James Jackson-South 10 years ago
parent
commit
31efe63e6d
  1. 96
      src/ImageProcessorCore/Filters/ColorBlindness.cs
  2. 53
      src/ImageProcessorCore/Filters/Options/ColorBlindness.cs
  3. 36
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs
  4. 36
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs
  5. 33
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs
  6. 33
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs
  7. 33
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs
  8. 33
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs
  9. 4
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/README.md
  10. 33
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs
  11. 33
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs
  12. 10
      src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs
  13. 6
      src/ImageProcessorCore/Image.cs
  14. 4
      src/ImageProcessorCore/Image/Image.cs
  15. 2
      src/ImageProcessorCore/Image/ImageBase.cs
  16. 2
      src/ImageProcessorCore/Image/ImageExtensions.cs
  17. 2
      src/ImageProcessorCore/Samplers/Pad.cs
  18. 52
      tests/ImageProcessorCore.Tests/Processors/Filters/ColorBlindnessTest.cs

96
src/ImageProcessorCore/Filters/ColorBlindness.cs

@ -0,0 +1,96 @@
// <copyright file="ColorBlindness.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>-------------------------------------------------------------------------------------------------------------------
namespace ImageProcessorCore
{
using Processors;
/// <summary>
/// Extension methods for the <see cref="Image"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Applies the given colorblindness simulator to the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="colorBlindness">The type of color blindness simulator to apply.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> ColorBlindness<T, TP>(this Image<T, TP> source, ColorBlindness colorBlindness, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
return ColorBlindness(source, colorBlindness, source.Bounds, progressHandler);
}
/// <summary>
/// Applies the given colorblindness simulator to the image.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="colorBlindness">The type of color blindness simulator to apply.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> ColorBlindness<T, TP>(this Image<T, TP> source, ColorBlindness colorBlindness, Rectangle rectangle, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
IImageProcessor<T, TP> processor;
switch (colorBlindness)
{
case ImageProcessorCore.ColorBlindness.Achromatomaly:
processor = new AchromatomalyProcessor<T, TP>();
break;
case ImageProcessorCore.ColorBlindness.Achromatopsia:
processor = new AchromatopsiaProcessor<T, TP>();
break;
case ImageProcessorCore.ColorBlindness.Deuteranomaly:
processor = new DeuteranomalyProcessor<T, TP>();
break;
case ImageProcessorCore.ColorBlindness.Deuteranopia:
processor = new DeuteranopiaProcessor<T, TP>();
break;
case ImageProcessorCore.ColorBlindness.Protanomaly:
processor = new ProtanomalyProcessor<T, TP>();
break;
case ImageProcessorCore.ColorBlindness.Protanopia:
processor = new ProtanopiaProcessor<T, TP>();
break;
case ImageProcessorCore.ColorBlindness.Tritanomaly:
processor = new TritanomalyProcessor<T, TP>();
break;
default:
processor = new TritanopiaProcessor<T, TP>();
break;
}
processor.OnProgress += progressHandler;
try
{
return source.Process(rectangle, processor);
}
finally
{
processor.OnProgress -= progressHandler;
}
}
}
}

53
src/ImageProcessorCore/Filters/Options/ColorBlindness.cs

@ -0,0 +1,53 @@
// <copyright file="ColorBlindness.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
/// <summary>
/// Enumerates the various types of color blindness.
/// </summary>
public enum ColorBlindness
{
/// <summary>
/// Partial color desensitivity.
/// </summary>
Achromatomaly,
/// <summary>
/// Complete color desensitivity (Monochrome)
/// </summary>
Achromatopsia,
/// <summary>
/// Green weak
/// </summary>
Deuteranomaly,
/// <summary>
/// Green blind
/// </summary>
Deuteranopia,
/// <summary>
/// Red weak
/// </summary>
Protanomaly,
/// <summary>
/// Red blind
/// </summary>
Protanopia,
/// <summary>
/// Blue weak
/// </summary>
Tritanomaly,
/// <summary>
/// Blue blind
/// </summary>
Tritanopia
}
}

36
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs

@ -0,0 +1,36 @@
// <copyright file="AchromatomalyProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System.Numerics;
/// <summary>
/// Converts the colors of the image recreating Achromatomaly (Color desensitivity) color blindness.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class AchromatomalyProcessor<T, TP> : ColorMatrixFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override Matrix4x4 Matrix => new Matrix4x4()
{
M11 = .618f,
M12 = .163f,
M13 = .163f,
M21 = .320f,
M22 = .775f,
M23 = .320f,
M31 = .062f,
M32 = .062f,
M33 = .516f
};
/// <inheritdoc/>
public override bool Compand => false;
}
}

36
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs

@ -0,0 +1,36 @@
// <copyright file="AchromatopsiaProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System.Numerics;
/// <summary>
/// Converts the colors of the image recreating Achromatopsia (Monochrome) color blindness.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class AchromatopsiaProcessor<T, TP> : ColorMatrixFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override Matrix4x4 Matrix => new Matrix4x4()
{
M11 = .299f,
M12 = .299f,
M13 = .299f,
M21 = .587f,
M22 = .587f,
M23 = .587f,
M31 = .114f,
M32 = .114f,
M33 = .114f
};
/// <inheritdoc/>
public override bool Compand => false;
}
}

33
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs

@ -0,0 +1,33 @@
// <copyright file="DeuteranomalyProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System.Numerics;
/// <summary>
/// Converts the colors of the image recreating Deuteranomaly (Green-Weak) color blindness.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class DeuteranomalyProcessor<T, TP> : ColorMatrixFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override Matrix4x4 Matrix => new Matrix4x4()
{
M11 = 0.8f,
M12 = 0.258f,
M21 = 0.2f,
M22 = 0.742f,
M23 = 0.142f,
M33 = 0.858f
};
/// <inheritdoc/>
public override bool Compand => false;
}
}

33
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs

@ -0,0 +1,33 @@
// <copyright file="DeuteranopiaProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System.Numerics;
/// <summary>
/// Converts the colors of the image recreating Deuteranopia (Green-Blind) color blindness.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class DeuteranopiaProcessor<T, TP> : ColorMatrixFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override Matrix4x4 Matrix => new Matrix4x4()
{
M11 = 0.625f,
M12 = 0.7f,
M21 = 0.375f,
M22 = 0.3f,
M23 = 0.3f,
M33 = 0.7f
};
/// <inheritdoc/>
public override bool Compand => false;
}
}

33
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs

@ -0,0 +1,33 @@
// <copyright file="ProtanomalyProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System.Numerics;
/// <summary>
/// Converts the colors of the image recreating Protanopia (Red-Weak) color blindness.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class ProtanomalyProcessor<T, TP> : ColorMatrixFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override Matrix4x4 Matrix => new Matrix4x4()
{
M11 = 0.817f,
M12 = 0.333f,
M21 = 0.183f,
M22 = 0.667f,
M23 = 0.125f,
M33 = 0.875f
};
/// <inheritdoc/>
public override bool Compand => false;
}
}

33
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs

@ -0,0 +1,33 @@
// <copyright file="ProtanopiaProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System.Numerics;
/// <summary>
/// Converts the colors of the image recreating Protanopia (Red-Blind) color blindness.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class ProtanopiaProcessor<T, TP> : ColorMatrixFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override Matrix4x4 Matrix => new Matrix4x4()
{
M11 = 0.567f,
M12 = 0.558f,
M21 = 0.433f,
M22 = 0.442f,
M23 = 0.242f,
M33 = 0.758f
};
/// <inheritdoc/>
public override bool Compand => false;
}
}

4
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/README.md

@ -0,0 +1,4 @@
Color blindness matrices adapted from and tested against:
http://web.archive.org/web/20090413045433/http://nofunc.org/Color_Matrix_Library
http://www.color-blindness.com/coblis-color-blindness-simulator/

33
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs

@ -0,0 +1,33 @@
// <copyright file="TritanomalyProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System.Numerics;
/// <summary>
/// Converts the colors of the image recreating Tritanomaly (Blue-Weak) color blindness.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class TritanomalyProcessor<T, TP> : ColorMatrixFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override Matrix4x4 Matrix => new Matrix4x4()
{
M11 = 0.967f,
M21 = 0.33f,
M22 = 0.733f,
M23 = 0.183f,
M32 = 0.267f,
M33 = 0.817f
};
/// <inheritdoc/>
public override bool Compand => false;
}
}

33
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs

@ -0,0 +1,33 @@
// <copyright file="TritanopiaProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Processors
{
using System.Numerics;
/// <summary>
/// Converts the colors of the image recreating Tritanopia (Blue-Blind) color blindness.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public class TritanopiaProcessor<T, TP> : ColorMatrixFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
{
/// <inheritdoc/>
public override Matrix4x4 Matrix => new Matrix4x4()
{
M11 = 0.95f,
M21 = 0.05f,
M22 = 0.433f,
M23 = 0.475f,
M32 = 0.567f,
M33 = 0.525f
};
/// <inheritdoc/>
public override bool Compand => false;
}
}

10
src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs

@ -9,8 +9,10 @@ namespace ImageProcessorCore.Processors
using System.Threading.Tasks;
/// <summary>
/// The color matrix filter.
/// The color matrix filter. Inherit from this class to perform operation involving color matrices.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
public abstract class ColorMatrixFilter<T, TP> : ImageProcessor<T, TP>, IColorMatrixFilter<T, TP>
where T : IPackedVector<TP>
where TP : struct
@ -63,11 +65,11 @@ namespace ImageProcessorCore.Processors
// color = Color.Expand(color);
//}
Vector4 transformed = Vector4.Transform(color.ToVector4(), matrix);
//Vector3 transformed = Vector3.Transform(color.ToVector3(), matrix);
Vector4 vector = color.ToVector4();
Vector3 transformed = Vector3.Transform(new Vector3(vector.X, vector.Y, vector.Z), matrix);
//return compand ? Color.Compress(new Color(transformed, color.A)) : new Color(transformed, color.A);
T packed = default(T);
packed.PackVector(transformed);
packed.PackVector(new Vector4(transformed.X, transformed.Y, transformed.Z, vector.W));
return packed;
}
}

6
src/ImageProcessorCore/Image.cs

@ -5,12 +5,14 @@
namespace ImageProcessorCore
{
using System;
using System.Diagnostics;
using System.IO;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha.
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
[DebuggerDisplay("Image: {Width}x{Height}")]
public class Image : Image<Color, uint>
{
/// <summary>

4
src/ImageProcessorCore/Image/Image.cs

@ -13,12 +13,14 @@ namespace ImageProcessorCore
using System.Linq;
using Formats;
using System.Diagnostics;
/// <summary>
/// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
[DebuggerDisplay("Image: {Width}x{Height}")]
public class Image<T, TP> : ImageBase<T, TP>
where T : IPackedVector<TP>
where TP : struct
@ -75,6 +77,7 @@ namespace ImageProcessorCore
/// <param name="other">The other image, where the clone should be made from.</param>
/// <exception cref="ArgumentNullException"><paramref name="other"/> is null.</exception>
public Image(Image<T, TP> other)
: base(other)
{
foreach (ImageFrame<T, TP> frame in other.Frames)
{
@ -84,7 +87,6 @@ namespace ImageProcessorCore
}
}
this.Quality = other.Quality;
this.RepeatCount = other.RepeatCount;
this.HorizontalResolution = other.HorizontalResolution;
this.VerticalResolution = other.VerticalResolution;

2
src/ImageProcessorCore/Image/ImageBase.cs

@ -6,6 +6,7 @@
namespace ImageProcessorCore
{
using System;
using System.Diagnostics;
/// <summary>
/// The base class of all images. Encapsulates the basic properties and methods required to manipulate
@ -13,6 +14,7 @@ namespace ImageProcessorCore
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
[DebuggerDisplay("Image: {Width}x{Height}")]
public abstract class ImageBase<T, TP> : IImageBase<T, TP>
where T : IPackedVector<TP>
where TP : struct

2
src/ImageProcessorCore/Image/ImageExtensions.cs

@ -174,7 +174,7 @@ namespace ImageProcessorCore
: new Image<T, TP>
{
// Several properties require copying
// TODO: Check why we need to set these?
FrameDelay = source.FrameDelay,
Quality = source.Quality,
HorizontalResolution = source.HorizontalResolution,
VerticalResolution = source.VerticalResolution,

2
src/ImageProcessorCore/Samplers/Pad.cs

@ -21,7 +21,7 @@ namespace ImageProcessorCore
/// <param name="width">The new width.</param>
/// <param name="height">The new height.</param>
/// <param name="progressHandler">A delegate which is called as progress is made processing the image.</param>
/// <returns>The <see cref="Image"/>.</returns>
/// <returns>The <see cref="Image{T,TP}"/>.</returns>
public static Image<T, TP> Pad<T, TP>(this Image<T, TP> source, int width, int height, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct

52
tests/ImageProcessorCore.Tests/Processors/Filters/ColorBlindnessTest.cs

@ -0,0 +1,52 @@
// <copyright file="SamplerTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System.IO;
using Xunit;
public class ColorBlindnessTest : FileTestBase
{
public static readonly TheoryData<ColorBlindness> ColorBlindnessFilters
= new TheoryData<ColorBlindness>
{
ColorBlindness.Achromatomaly,
ColorBlindness.Achromatopsia,
ColorBlindness.Deuteranomaly,
ColorBlindness.Deuteranopia,
ColorBlindness.Protanomaly,
ColorBlindness.Protanopia,
ColorBlindness.Tritanomaly,
ColorBlindness.Tritanopia
};
[Theory]
[MemberData("ColorBlindnessFilters")]
public void ImageShouldApplyColorBlindnessFilter(ColorBlindness colorBlindness)
{
const string path = "TestOutput/ColorBlindness";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
string filename = Path.GetFileNameWithoutExtension(file) + "-" + colorBlindness + Path.GetExtension(file);
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
image.ColorBlindness(colorBlindness)
.Save(output);
}
}
}
}
}
}
Loading…
Cancel
Save