Skip to content

Instantly share code, notes, and snippets.

@greenboxal
Created February 13, 2013 04:37
Show Gist options
  • Save greenboxal/4942309 to your computer and use it in GitHub Desktop.
Save greenboxal/4942309 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuffmanTexture
{
public class HuffmanPixelTree
{
public sealed class Node
{
public Vector4 Color;
public Node[] Childs;
public bool Leaf;
public Node(Vector4 color)
{
Color = color;
Childs = new Node[4];
Leaf = true;
}
public Vector4 GetAverage()
{
int i = 0;
Vector4 a = new Vector4();
if (Leaf)
return Color;
foreach (Vector4 c in from node in Childs where node != null select node.GetAverage())
{
a += c;
i++;
}
a /= i;
return a;
}
public void SetChild(int index, Node node)
{
Childs[index] = node;
if (!Leaf && node != null)
{
Leaf = true;
}
else
{
foreach (Node n in Childs)
{
Leaf = n == null;
if (Leaf)
break;
}
}
}
}
private readonly Vector4[,] _originalPixels;
private Node _mainNode;
private bool _dirty;
private Bitmap _cache;
public int Size { get; private set; }
private Vector4 _nodeThreshold;
public Vector4 NodeThreshold
{
get { return _nodeThreshold; }
set
{
_nodeThreshold = value;
Generate();
}
}
public HuffmanPixelTree(Bitmap source)
{
if (source.Width != source.Height || source.Width % 4 != 0)
throw new NotSupportedException("Invalid image");
Size = source.Width;
_dirty = true;
_cache = new Bitmap(Size, Size);
_originalPixels = new Vector4[Size, Size];
_nodeThreshold = Vector4.Zero;
for (int x = 0; x < source.Width; x++)
for (int y = 0; y < source.Height; y++)
_originalPixels[x, y] = new Vector4(source.GetPixel(x, y));
Generate();
}
private void Generate()
{
_mainNode = new Node(Vector4.Zero);
Generate(_mainNode, 0, 0, Size);
}
private void Generate(Node father, int startX, int startY, int size)
{
int childSize = size / 4;
if (childSize == 1)
{
Vector4[] colors = new Vector4[4];
colors[0] = _originalPixels[startX, startY];
colors[1] = _originalPixels[startX + 1, startY];
colors[2] = _originalPixels[startX, startY + 1];
colors[3] = _originalPixels[startX + 1, startY + 1];
if (CheckThreshold(colors))
{
father.Color = colors[0];
}
else
{
father.SetChild(0, new Node(colors[0]));
father.SetChild(1, new Node(colors[1]));
father.SetChild(2, new Node(colors[2]));
father.SetChild(3, new Node(colors[3]));
}
}
else
{
Node n = new Node(Vector4.Zero);
Generate(n, startX, startY, childSize);
father.SetChild(0, n);
n = new Node(Vector4.Zero);
Generate(n, startX + childSize, startY, childSize);
father.SetChild(1, n);
n = new Node(Vector4.Zero);
Generate(n, startX, startY + childSize, childSize);
father.SetChild(2, n);
n = new Node(Vector4.Zero);
Generate(n, startX + childSize, startY + childSize, childSize);
father.SetChild(3, n);
}
}
public Bitmap Rebuild()
{
lock (_cache)
{
if (_dirty)
Rebuild(_mainNode, 0, 0, Size);
return new Bitmap(_cache); ;
}
}
private void Rebuild(Node node, int startX, int startY, int size)
{
}
private bool CheckThreshold(Vector4[] colors)
{
int i;
Vector4 a = new Vector4();
Vector4 min = new Vector4();
Vector4 max = new Vector4();
for (i = 0; i < colors.Length; i++)
{
Vector4 c = colors[i];
Vector4.Min(ref min, ref c, out min);
Vector4.Max(ref max, ref c, out max);
a += colors[i];
i++;
}
a /= i;
return (a - _nodeThreshold) >= min && (a + _nodeThreshold) <= max;
}
}
}
private bool CheckThreshold(Vector4[] colors, out Vector4 average)
{
int i;
Vector4 a = new Vector4();
Vector4 min = new Vector4(1);
Vector4 max = new Vector4(0);
for (i = 0; i < colors.Length; i++)
{
Vector4 c = colors[i];
Vector4.Min(ref min, ref c, out min);
Vector4.Max(ref max, ref c, out max);
a += c;
}
a /= i;
average = a;
return ((a - _nodeThreshold) <= min && min <= a) || (a >= max && max >= (a + _nodeThreshold));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment