mirror of https://github.com/SixLabors/ImageSharp
3 changed files with 74 additions and 1 deletions
@ -0,0 +1,60 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using System.Runtime.CompilerServices; |
||||
|
using SixLabors.ImageSharp.Formats.Jxl.Cms; |
||||
|
using SixLabors.ImageSharp.Formats.Jxl.Processing.Noise; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder.Noise; |
||||
|
|
||||
|
internal static class JxlPhotonNoise |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Assumes a daylight-like spectrum.
|
||||
|
/// </summary>
|
||||
|
private const float PhotonsPerLxSPerUm2 = 11260; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Order of magnitude for cameras in the 2010-2020 decade,
|
||||
|
/// taking the CFA into account.
|
||||
|
/// </summary>
|
||||
|
private const float EffectiveQuantumEfficiency = 0.20f; |
||||
|
|
||||
|
private const float PhotoResponseNonUniformity = 0.005f; |
||||
|
|
||||
|
private const float InputReferredReadNoise = 3; |
||||
|
|
||||
|
private const float SensorAreaUm2 = 36000f * 24000; |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private static float Square(float x) => x * x; |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private static float Cube(float x) => x * x * x; |
||||
|
|
||||
|
public static JxlNoiseParameters SimulatePhotonNoise(int xSize, int ySize, float iso) |
||||
|
{ |
||||
|
float opsinAbsorbanceBiasCbrt = MathF.Cbrt(JxlOpsinConstants.OpsinAbsorbanceBias1); |
||||
|
float h18 = 10f / iso; |
||||
|
float pixelAreaUm2 = SensorAreaUm2 / (xSize * ySize); |
||||
|
float electronsPerPixel18 = EffectiveQuantumEfficiency * PhotonsPerLxSPerUm2 * h18 * pixelAreaUm2; |
||||
|
JxlNoiseParameters parameters = new(); |
||||
|
Span<float> lookup = parameters.Lookup; // Faster than float[]
|
||||
|
|
||||
|
for (int i = 0; i < JxlNoiseParameters.NoisePoints; ++i) |
||||
|
{ |
||||
|
float scaledIndex = i / (JxlNoiseParameters.NoisePoints - 2f); |
||||
|
float y = 2 * scaledIndex; |
||||
|
float linear = MathF.Max(0f, Cube(y - opsinAbsorbanceBiasCbrt) + JxlOpsinConstants.OpsinAbsorbanceBias1); |
||||
|
float electronsPerPixel = electronsPerPixel18 * (linear / 0.18f); |
||||
|
float noise = MathF.Sqrt(Square(InputReferredReadNoise) + electronsPerPixel + Square(PhotoResponseNonUniformity * electronsPerPixel)); |
||||
|
float linearNoise = noise * (0.18f / electronsPerPixel18); |
||||
|
float opsinDerivative = (1f / 3) / Square(MathF.Sqrt(linear - JxlOpsinConstants.OpsinAbsorbanceBias1)); |
||||
|
float opsinNoise = linearNoise * opsinDerivative; |
||||
|
|
||||
|
lookup[i] = Math.Clamp(opsinNoise / (0.22f * MathF.Sqrt(2f) * 1.13f), 0f, JxlNoiseConstants.NoiseLutMax); |
||||
|
} |
||||
|
|
||||
|
return parameters; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Noise; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Constants used by noise processing.
|
||||
|
/// </summary>
|
||||
|
internal static class JxlNoiseConstants |
||||
|
{ |
||||
|
public const float Precision = 1024f; |
||||
|
public const float NoiseLutMax = 1023.4999f / Precision; |
||||
|
} |
||||
Loading…
Reference in new issue