Skip to content

Instantly share code, notes, and snippets.

@mandarinx
Last active October 22, 2022 00:04
Show Gist options
  • Save mandarinx/e4df9a7766b003e909ed1001086cf3dc to your computer and use it in GitHub Desktop.
Save mandarinx/e4df9a7766b003e909ed1001086cf3dc to your computer and use it in GitHub Desktop.
Quantize color channels
public static int Quantize(float value, int bits) {
return (int)(value * (Math.Pow(2, bits) - 1));
}
public static int JoinColors(int maskWidth, params int[] colors) {
int joined = colors[0];
for (int i=1; i<colors.Length; ++i) {
joined = JoinColor(joined, colors[i], i, maskWidth);
}
return joined;
}
public static int JoinColor(int joined, int color, int i, int maskWidth) {
return joined |= color << (i * maskWidth);
}
public static float EncodeQuantized(int quantized, int maxValue) {
return (float)quantized / ((float)maxValue - 1f);
}
public static int DecodeQuantized(float encoded, int maxValue) {
return (int)(Math.Min(maxValue - 1, (int)(encoded * maxValue)));
}
public static int ExtractQuantized(int decoded, int num, int mask, int maskWidth) {
return (decoded & (mask << (num * maskWidth))) >> (num * maskWidth);
}
public static float ToColor(int quantized, int bits) {
return (float)quantized / ((int)Math.Pow(2, bits) - 1);
}
public static int GetMask(int bits) {
int mask = 0;
for (int i=0; i<bits; ++i) {
mask |= (1 << i);
}
return mask;
}
public static float EncodeChannel(int channel, int colorBits, int maxBits, params Color[] colors) {
int j = 0;
for (int i=0; i<colors.Length; ++i) {
int q = Quantize(colors[i][channel], colorBits);
j = JoinColor(j, q, i, colorBits);
}
return EncodeQuantized(j, maxBits);
}
public static float DecodeChannel(float encodedChannel, int num, int maxBits, int colorBits, int channelMask) {
int decoded = DecodeQuantized(encodedChannel, maxBits);
int q = ExtractQuantized(decoded, num, channelMask, colorBits);
return ToColor(q, colorBits);
}
public static string Bits(int value) {
return Convert.ToString(value, 2).PadLeft(32, '0');
}
public static void PrintBits(string label, int value) {
Console.WriteLine($"{label}: {Bits(value)}");
}
public static void Run() {
int colorBits = 8;
int numColors = 2;
int channelMask = GetMask(colorBits);
int maxBits = (int)Math.Pow(2, (numColors * colorBits));
Console.WriteLine($"..channelMask: {Bits(channelMask)} dec : {channelMask}");
// Create two colors
Color a = new Color(1f, 0f, 0f);
Color b = new Color(0f, 1f, 0f);
// Encode each channel og both colors
float encodedR = EncodeChannel((int)Channel.RED, colorBits, maxBits, a, b);
float encodedG = EncodeChannel((int)Channel.GREEN, colorBits, maxBits, a, b);
float encodedB = EncodeChannel((int)Channel.BLUE, colorBits, maxBits, a, b);
Console.WriteLine($"Color a.r {a.r} b.r {b.r} : {encodedR}");
Console.WriteLine($"Color a.g {a.g} b.g {b.g} : {encodedG}");
Console.WriteLine($"Color a.b {a.b} b.b {b.b} : {encodedB}");
// extract two colors
float r0 = DecodeChannel(encodedR, 0, maxBits, colorBits, channelMask);
Console.WriteLine($"...........r0: {r0}");
float r1 = DecodeChannel(encodedR, 1, maxBits, colorBits, channelMask);
Console.WriteLine($"...........r1: {r1}");
float g0 = DecodeChannel(encodedG, 0, maxBits, colorBits, channelMask);
Console.WriteLine($"...........g0: {g0}");
float g1 = DecodeChannel(encodedG, 1, maxBits, colorBits, channelMask);
Console.WriteLine($"...........g1: {g1}");
float b0 = DecodeChannel(encodedB, 0, maxBits, colorBits, channelMask);
Console.WriteLine($"...........b0: {b0}");
float b1 = DecodeChannel(encodedB, 1, maxBits, colorBits, channelMask);
Console.WriteLine($"...........b1: {b1}");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment