Well, it outputs data, not sure if it’s valid data
A test would be that all the codes are unique and none of the smaller codes are the beginning of longer codes.
I don’t know if I understood this correctly, but when I tried making the keys of the priorityqueue into ints, it found identical values and didn’t know how to order it. I assume it tried to compare the other object in the tuple(the hoffmanNode object). It have me this error
TypeError: unorderable types: HuffmanNode() < str()
I don’t think it matters the order of values that are the same, but I just overloaded some boolean operators to make it work.
import bpy
import os.path
import queue
from collections import defaultdict
dirpath = r"C:\Users\Joe\Desktop\codec est"
numFrames = 1
d = defaultdict(int)
pq = queue.PriorityQueue()
class HuffmanNode(object):
def __init__(self, left=None, right=None, root=None):
self.left = left
self.right = right
self.root = root # Why? Not needed for anything.
def children(self):
return((self.left, self.right))
def __gt__(self, other):
return True
def __lt__(self, other):
return False
for frameNum in range(numFrames):
filename = "stills%04i.png" % frameNum
img = bpy.data.images.load(filepath=os.path.join(dirpath, filename))
pixels = img.pixels[:]
for p in pixels:
d[int(p*255)] += 1
print("%s completed" % filename)
def create_tree():
for value in range(d.__len__()):
pq.put((d[value],value))
while pq.qsize() > 1: # 2. While there is more than one node
l, r = pq.get(), pq.get() # 2a. remove two highest nodes
node = HuffmanNode(l, r) # 2b. create internal node with children
pq.put((l[0]+r[0], node)) # 2c. add new node to queue
return pq.get() # 3. tree is complete - return root node
node = create_tree()
print("tree created")
# Recursively walk the tree down to the leaves,
# assigning a code value to each symbol
def walk_tree(node, prefix="", code={}):
weight , k = node
if type(k) is int:
code[k] = prefix
else:
left , right = k.children()
walk_tree(left,prefix+'0',code)
walk_tree(right,prefix+'1',code)
return(code)
code = walk_tree(node)
for i in range(255):
print(i, ' ' + str(d[i]) + ' ', code[i])
Edit : After some thinking I added some code to test that the codes are unique and that none of the smaller codes are the beginning of any of the bigger codes. Here is what I used:
boo = False
for i in range(255):
foo = code[i]
length = len(foo)
for j in range(255):
if(i != j and foo == code[j][:length]):
boo == True
print(boo)
I can’t definitively say the codes are valid, but the test didn’t disprove it either. Next step is creating a file header that contains the code and a body that contains the compressed data.
Edit: Edit: I just added some code to estimate the file size. Uncompressed, the pictures would average 1megabyte, I’m predicting the compressed file size will be 129kbytes. The test images are 93kbytes. Not bad for 1 layer of compression. I might be able to 93kbyts if I do multiple passes or incorporate other compression algorithms.