I am trying to create a debug tool that would help me visualize an image RGB and luminance histogram. I have created a compute shader where I gather the histogram data
#pragma kernel Clear
#pragma kernel Gather
Texture2D<float4> Input;
struct HIST {
uint4 color;
};
RWStructuredBuffer<HIST> HistogramBuffer;
[numthreads(64, 1, 1)]
void Clear(uint3 id : SV_DispatchThreadID)
{
HistogramBuffer[id.x].color = uint4(0, 0, 0, 0);
}
[numthreads(8, 8, 1)]
void Gather(uint3 id : SV_DispatchThreadID)
{
uint4 col = uint4(255.0 * Input[id.xy]);
InterlockedAdd(HistogramBuffer[col.r].color.r, 1);
InterlockedAdd(HistogramBuffer[col.g].color.g, 1);
InterlockedAdd(HistogramBuffer[col.b].color.b, 1);
InterlockedAdd(HistogramBuffer[dot(col.rgb, float3(0.2126729, 0.7151522, 0.0721750))].color.a, 1);
}
And in the c# code after I've gathered the data I create a final output texture.
using UnityEngine;
using UnityEngine.UI;
internal sealed class Histogram : MonoBehaviour
{
public const int HISTOGRAM_BINS = 256;
uint[] histogramData;
[SerializeField]
ComputeShader shader;
ComputeBuffer histogramBuffer;
[SerializeField] RawImage output = null;
[SerializeField] Texture2D input;
public void Start()
{
//Init kernels
int clearKernel = shader.FindKernel("Clear");
int gatherkernel = shader.FindKernel("Gather");
//Init data
histogramBuffer = new ComputeBuffer(HISTOGRAM_BINS, sizeof(uint) * 4);
histogramData = new uint[HISTOGRAM_BINS * 4];
//Set data
shader.SetTexture(gatherkernel, "Input", input);
shader.SetBuffer(gatherkernel, "HistogramBuffer", histogramBuffer);
shader.SetBuffer(clearKernel, "HistogramBuffer", histogramBuffer);
//Execute shader
shader.Dispatch(clearKernel, HISTOGRAM_BINS / 64, 1, 1);
shader.Dispatch(gatherkernel, input.width / 8, input.height / 8, 1);
//Get data
histogramBuffer.GetData(histogramData);
//Find highest value
uint highestValue = uint.MinValue;
for (int i = 0; i < histogramData.Length; i++)
{
if (histogramData[i] > highestValue)
{
highestValue = histogramData[i];
}
}
//Create final output texture
Texture2D final = new Texture2D(HISTOGRAM_BINS, input.height)
{
filterMode = FilterMode.Bilinear,
wrapMode = TextureWrapMode.Clamp
};
final.Apply();
//Init the texture pixels array
Color32[] pixels = new Color32[HISTOGRAM_BINS * input.height];
//Get all red values from the histogram data array
uint[] reds = new uint[HISTOGRAM_BINS];
for (int i = 0, h = 0; i < HISTOGRAM_BINS; i++, h += 4)
{
reds[i] = histogramData[h];
}
pixels = ComputeChannelHistogram(pixels, in reds, highestValue, new Color32(255, 0, 0, 255));
//Get all green values from the histogram data array
uint[] greens = new uint[HISTOGRAM_BINS];
for (int i = 0, h = 1; i < HISTOGRAM_BINS; i++, h += 4)
{
greens[i] = histogramData[h];
}
pixels = ComputeChannelHistogram(pixels, in greens, highestValue, new Color32(0, 255, 0, 255));
//Get all blue values from the histogram data array
uint[] blues = new uint[HISTOGRAM_BINS];
for (int i = 0, h = 2; i < HISTOGRAM_BINS; i++, h += 4)
{
blues[i] = histogramData[h];
}
pixels = ComputeChannelHistogram(pixels, in blues, highestValue, new Color32(0, 0, 255, 255));
//Get all lum values from the histogram data array
uint[] lum = new uint[HISTOGRAM_BINS];
for (int i = 0, h = 3; i < HISTOGRAM_BINS; i++, h += 4)
{
lum[i] = histogramData[h];
}
pixels = ComputeChannelHistogram(pixels, in lum, highestValue, new Color32(127, 127, 127, 255));
//Set pixels
final.SetPixels32(pixels); final.Apply();
//Set output image
output.texture = final;
}
Color32[] ComputeChannelHistogram(Color32[] pixels, in uint[] data, float max, Color32 color)
{
for (int x = 0; x < HISTOGRAM_BINS; x++)
{
float p = Mathf.InverseLerp(0F, max, data[x]);
for (int y = 0; y < input.height * p; y++)
{
int index = x + (y * HISTOGRAM_BINS);
Color32 pixelColor = pixels[index];
pixelColor.r += color.r;
pixelColor.g += color.g;
pixelColor.b += color.b;
pixels[index] = new Color32(pixelColor.r, pixelColor.g, pixelColor.b, 255);
}
}
return pixels;
}
}
However, I am getting weird results and not sure why.
E.g. input image (Figure 1)
The histogram that is generated
The histogram that is generated in Photoshop
Can someone please help me understand what am I doing wrong here and how can I fix it to have better results? I just recently started looking at histograms, I understand what they show and are, the vertical is a number of pixels and the horizontal bars that go from left to right are the tones, so left is blacks, the middle is midtones, and right is whites, but for some reason I have a difficult time creating one...