Skip to content

Instantly share code, notes, and snippets.

@greenboxal
Created February 13, 2013 16:41
Show Gist options
  • Save greenboxal/4945942 to your computer and use it in GitHub Desktop.
Save greenboxal/4945942 to your computer and use it in GitHub Desktop.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuffmanTexture
{
public class HuffmanPixelTree
{
public sealed class Node : IListSource
{
public Vector4 Color;
public Node[] Childs;
public bool Leaf;
public Node(Vector4 color)
{
Color = color;
Childs = new Node[4];
Leaf = true;
}
IList IListSource.GetList()
{
return Childs;
}
bool IListSource.ContainsListCollection { get { return !Leaf; } }
}
private readonly Vector4[,] _originalPixels;
private readonly Bitmap _cache;
private bool _dirty;
public int Size { get; private set; }
public int HighestLevel { get; private set; }
private Node _mainNode;
public Node MainNode
{
get { return _mainNode; }
}
private float _nodeThreshold;
public float NodeThreshold
{
get { return _nodeThreshold; }
set
{
if (_nodeThreshold == value)
return;
_nodeThreshold = value;
Generate();
}
}
public event Action Generated;
public HuffmanPixelTree(Bitmap source)
{
if (source.Width != source.Height || source.Width % 4 != 0)
throw new NotSupportedException("Invalid image");
Size = source.Width;
_nodeThreshold = 0;
_cache = new Bitmap(Size, Size);
_originalPixels = new Vector4[Size, Size];
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, 0);
_dirty = true;
if (Generated != null)
Generated();
}
// TODO: Check threshold against the original non processed pixels
private void Generate(Node father, int startX, int startY, int size, int level)
{
int childSize = size / 2;
Vector4 average;
if (CheckThreshold(startX, startY, size, out average))
{
father.Color = average;
father.Leaf = true;
}
else
{
father.Childs[0] = new Node(Vector4.Zero);
Generate(father.Childs[0], startX, startY, childSize, level + 1);
father.Childs[1] = new Node(Vector4.Zero);
Generate(father.Childs[1], startX + childSize, startY, childSize, level + 1);
father.Childs[2] = new Node(Vector4.Zero);
Generate(father.Childs[2], startX, startY + childSize, childSize, level + 1);
father.Childs[3] = new Node(Vector4.Zero);
Generate(father.Childs[3], startX + childSize, startY + childSize, childSize, level + 1);
father.Leaf = false;
}
HighestLevel = Math.Max(HighestLevel, level);
}
public Bitmap Rebuild()
{
lock (_cache)
{
if (_dirty)
{
Rebuild(_mainNode, 0, 0, Size);
_dirty = true;
}
return new Bitmap(_cache); ;
}
}
private void Rebuild(Node node, int startX, int startY, int size)
{
int childSize = size / 2;
if (node == null)
return;
if (node.Leaf)
{
Color c = node.Color.ToColor();
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
_cache.SetPixel(startX + x, startY + y, c);
}
else
{
Rebuild(node.Childs[0], startX, startY, childSize);
Rebuild(node.Childs[1], startX + childSize, startY, childSize);
Rebuild(node.Childs[2], startX, startY + childSize, childSize);
Rebuild(node.Childs[3], startX + childSize, startY + childSize, childSize);
}
}
private bool CheckThreshold(int startX, int startY, int size, out Vector4 average)
{
Vector4 a = new Vector4();
float pba = 0;
float min = 1;
float max = 0;
float threshold;
for (int x = 0; x < size; x++)
{
for (int y = 0; y < size; y++)
{
Vector4 c = _originalPixels[startX + x, startY + y];
float pb = (c.X + c.Y + c.Z) / 3;
if (pb < min)
min = pb;
if (pb > max)
max = pb;
a += c;
pba += pb;
}
}
a /= size * size;
pba /= size * size;
average = a;
threshold = pba * _nodeThreshold / 100.0f;
return (min <= pba && pba <= (min + threshold)) || (max <= pba && pba <= (max + threshold));
}
/*
private bool CheckThreshold(IList<Vector4> colors, out Vector4 average)
{
int i;
Vector4 a = new Vector4();
float pba = 0;
float min = 1;
float max = 0;
float threshold;
for (i = 0; i < colors.Count; i++)
{
Vector4 c = colors[i];
float pb = (c.X + c.Y + c.Z) / 3;
if (pb < min)
min = pb;
if (pb > max)
max = pb;
a += c;
pba += pb;
}
a /= i;
pba /= i;
average = a;
threshold = pba *_nodeThreshold / 100.0f;
return (min <= pba && pba <= (min + threshold)) || (max <= pba && pba <= (max + threshold));
}*/
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment