simple_compression
This program is my first dabbling in image compression. It turns out that storing pixel data as gradients isn’t any smaller than indexing. Anyway, it was fun novel idea I had been meaning to try for a while (coded July 2010).
import struct
from PIL import Image
import math
def writeUnsignedShort(stream,v):
stream.write(struct.pack('<H', v))
def readUnsignedShort(stream):
s = stream.read(2)
p, = struct.unpack('<H', s)
return p
def writeDouble(stream,v):
stream.write(struct.pack('d', v))
def readDouble(stream):
s = stream.read(8)
p, = struct.unpack('d', s)
return p
def writeUnsignedChar(stream,v):
stream.write(struct.pack('c', chr(v)))
def readUnsignedChar(stream):
s = stream.read(1)
p, = struct.unpack('c', s)
return ord(p)
def testOut():
s = open("byte_test","wb")
writeUnsignedShort(s,10)
s.close()
s = open("byte_test","rb")
print readUnsignedShort(s)
s.close()
class CompressedFile:
def __init__(self):
self.m = 0.0
self.b = 0.0
self.inds = []
self.size = [0,0]
def writeFile(self, s):
writeUnsignedShort(s, self.size[0])
writeUnsignedShort(s, self.size[1])
writeDouble(s, self.m)
writeDouble(s, self.b)
writeUnsignedShort(s, len(self.inds))
for ind in self.inds:
writeUnsignedShort(s, ind)
#writeUnsignedChar(s, ind)
def readFile(self, s):
self.size[0] = readUnsignedShort(s)
self.size[1] = readUnsignedShort(s)
self.m = readDouble(s)
self.b = readDouble(s)
inds_len = readUnsignedShort(s)
for ind in range(inds_len):
self.inds.append(readUnsignedShort(s))
#self.inds.append(readUnsignedChar(s))
##double slope
##double intercept
##unsigned short size
## unsigned short pixel_index
def linearRegression(points): #points are stored in this form [(x,y), ...]
sum_xy = 0
sum_x = 0
sum_y = 0
sum_x2 = 0
for point in points:
sum_xy+=point[0]*point[1]
sum_x+=point[0]
sum_y+=point[1]
sum_x2+=point[0]**2
n = float(len(points))
m = (n*sum_xy - sum_x * sum_y)/(n*sum_x2-sum_x**2) #slope
b = (sum_y-m*sum_x)/n #intercept
return m, b
def processSector(data): #data is [(R,G,B), ...]
#let's just compress red to start with
buffer = [] #[(value,old_index), ...]
for i in range(len(data)):
buffer.append((data[i][0],i))
buffer.sort() #sort from lowest to highest by first element
#print buffer
linreg_buffer = []
for i in range(len(buffer)):
linreg_buffer.append((i,buffer[i][0]))
m,b = linearRegression(linreg_buffer)
print "slope", m, "intercept", b
return_vals = [] #in original order with form [amplitude_index, ...]
#create array to insert stuff into
for i in range(len(buffer)):
return_vals.append(0)
for amplitude in range(len(buffer)):
return_vals[buffer[amplitude][1]] = amplitude #buffer[amplitude][1] is the original ind
return m,b,return_vals
#just deal with one sector (255x255) for now
def compressImage_single():
image = Image.open("vax.bmp")
pixels = image.getdata()
m,b,inds = processSector(pixels)
f = CompressedFile()
f.m = m
f.b = b
f.inds = inds
f.size = list(image.size)
s = open("output.compressed", "wb")
f.writeFile(s)
s.close()
def compressImage():
image = Image.open("vax.bmp")
pixels = image.getdata()
m,b,inds = processSector(pixels)
f = CompressedFile()
f.m = m
f.b = b
f.inds = inds
f.size = list(image.size)
s = open("output.compressed", "wb")
f.writeFile(s)
s.close()
####now write it back and display the image
def decompressImage_single():
s = open("output.compressed", "rb")
f = CompressedFile()
f.readFile(s)
s.close()
print "read:", f.m,f.b,f.size
image = Image.new("RGB",tuple(f.size))
pixels = image.load()
for i in range(f.size[0]*f.size[1]):
x = i % f.size[0]
y = math.ceil(i/f.size[0])
val = int(round(f.inds[i]*f.m+f.b)) #inds[i] amplitude or x value
pixels[x, y] = (val,val,val)
image.save("output.bmp")
def decompressImage():
s = open("output.compressed", "rb")
f = CompressedFile()
f.readFile(s)
s.close()
print "read:", f.m,f.b,f.size
image = Image.new("RGB",tuple(f.size))
pixels = image.load()
for i in range(f.size[0]*f.size[1]):
x = i % f.size[0]
y = math.ceil(i/f.size[0])
val = int(round(f.inds[i]*f.m+f.b)) #inds[i] amplitude or x value
pixels[x, y] = (val,val,val)
image.save("output.bmp")
#image must be evenly
compressImage()
decompressImage()
#print linearRegression([(0,0),(2,2)])