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)])

Posted in: Code by nsundin
Copyright © 2011-2025 Programmatic Verse · RSS Feed
Built on Skeleton
Powerered by Wordpress