Created
December 28, 2016 04:11
-
-
Save CoderSherlock/834e9eb918eeb0dfee5f4550077f57f8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
2D CDF 9/7 Wavelet Forward and Inverse Transform (lifting implementation) | |
This code is provided "as is" and is given for educational purposes. | |
2008 - Kris Olhovsky - [email protected] | |
''' | |
from PIL import Image # Part of the standard Python Library | |
''' Example matrix as a list of lists: ''' | |
mat4x4 = [ | |
[0, 1, 2, 3], # Row 1 | |
[4, 5, 6, 7], # Row 2 | |
[8, 9, 10, 11], # Row 3 | |
[12, 13, 14, 15], # Row 4 | |
] # We don't do anything with this matrix. | |
# It's just here for clarification. | |
def fwt97_2d(m, nlevels=1): | |
''' Perform the CDF 9/7 transform on a 2D matrix signal m. | |
nlevel is the desired number of times to recursively transform the | |
signal. ''' | |
w = len(m[0]) | |
h = len(m) | |
for i in range(nlevels): | |
m = fwt97(m, w, h) # cols | |
m = fwt97(m, w, h) # rows | |
w /= 2 | |
h /= 2 | |
return m | |
def iwt97_2d(m, nlevels=1): | |
''' Inverse CDF 9/7 transform on a 2D matrix signal m. | |
nlevels must be the same as the nlevels used to perform the fwt. | |
''' | |
w = len(m[0]) | |
h = len(m) | |
# Find starting size of m: | |
for i in range(nlevels-1): | |
h /= 2 | |
w /= 2 | |
for i in range(nlevels): | |
m = iwt97(m, w, h) # rows | |
m = iwt97(m, w, h) # cols | |
h *= 2 | |
w *= 2 | |
return m | |
def fwt97(s, width, height): | |
''' Forward Cohen-Daubechies-Feauveau 9 tap / 7 tap wavelet transform | |
performed on all columns of the 2D n*n matrix signal s via lifting. | |
The returned result is s, the modified input matrix. | |
The highpass and lowpass results are stored on the left half and right | |
half of s respectively, after the matrix is transposed. ''' | |
# 9/7 Coefficients: | |
a1 = -1.586134342 | |
a2 = -0.05298011854 | |
a3 = 0.8829110762 | |
a4 = 0.4435068522 | |
# Scale coeff: | |
k1 = 0.81289306611596146 # 1/1.230174104914 | |
k2 = 0.61508705245700002 # 1.230174104914/2 | |
# Another k used by P. Getreuer is 1.1496043988602418 | |
for col in range(width): # Do the 1D transform on all cols: | |
''' Core 1D lifting process in this loop. ''' | |
''' Lifting is done on the cols. ''' | |
# Predict 1. y1 | |
for row in range(1, height-1, 2): | |
s[row][col] += a1 * (s[row-1][col] + s[row+1][col]) | |
s[height-1][col] += 2 * a1 * s[height-2][col] # Symmetric extension | |
# Update 1. y0 | |
for row in range(2, height, 2): | |
s[row][col] += a2 * (s[row-1][col] + s[row+1][col]) | |
s[0][col] += 2 * a2 * s[1][col] # Symmetric extension | |
# Predict 2. | |
for row in range(1, height-1, 2): | |
s[row][col] += a3 * (s[row-1][col] + s[row+1][col]) | |
s[height-1][col] += 2 * a3 * s[height-2][col] | |
# Update 2. | |
for row in range(2, height, 2): | |
s[row][col] += a4 * (s[row-1][col] + s[row+1][col]) | |
s[0][col] += 2 * a4 * s[1][col] | |
# de-interleave | |
temp_bank = [[0]*width for i in range(height)] | |
for row in range(height): | |
for col in range(width): | |
# k1 and k2 scale the vals | |
# simultaneously transpose the matrix when deinterleaving | |
if row % 2 == 0: # even | |
temp_bank[col][row/2] = k1 * s[row][col] | |
else: # odd | |
temp_bank[col][row/2 + height/2] = k2 * s[row][col] | |
# write temp_bank to s: | |
for row in range(width): | |
for col in range(height): | |
s[row][col] = temp_bank[row][col] | |
return s | |
def iwt97(s, width, height): | |
''' Inverse CDF 9/7. ''' | |
# 9/7 inverse coefficients: | |
a1 = 1.586134342 | |
a2 = 0.05298011854 | |
a3 = -0.8829110762 | |
a4 = -0.4435068522 | |
# Inverse scale coeffs: | |
k1 = 1.230174104914 | |
k2 = 1.6257861322319229 | |
# Interleave: | |
temp_bank = [[0]*width for i in range(height)] | |
for col in range(width/2): | |
for row in range(height): | |
# k1 and k2 scale the vals | |
# simultaneously transpose the matrix when interleaving | |
temp_bank[col * 2][row] = k1 * s[row][col] | |
temp_bank[col * 2 + 1][row] = k2 * s[row][col + width/2] | |
# write temp_bank to s: | |
for row in range(width): | |
for col in range(height): | |
s[row][col] = temp_bank[row][col] | |
for col in range(width): # Do the 1D transform on all cols: | |
''' Perform the inverse 1D transform. ''' | |
# Inverse update 2. | |
for row in range(2, height, 2): | |
s[row][col] += a4 * (s[row-1][col] + s[row+1][col]) | |
s[0][col] += 2 * a4 * s[1][col] | |
# Inverse predict 2. | |
for row in range(1, height-1, 2): | |
s[row][col] += a3 * (s[row-1][col] + s[row+1][col]) | |
s[height-1][col] += 2 * a3 * s[height-2][col] | |
# Inverse update 1. | |
for row in range(2, height, 2): | |
s[row][col] += a2 * (s[row-1][col] + s[row+1][col]) | |
s[0][col] += 2 * a2 * s[1][col] # Symmetric extension | |
# Inverse predict 1. | |
for row in range(1, height-1, 2): | |
s[row][col] += a1 * (s[row-1][col] + s[row+1][col]) | |
s[height-1][col] += 2 * a1 * s[height-2][col] # Symmetric extension | |
return s | |
def seq_to_img(m, pix): | |
''' Copy matrix m to pixel buffer pix. | |
Assumes m has the same number of rows and cols as pix. ''' | |
for row in range(len(m)): | |
for col in range(len(m[row])): | |
pix[col,row] = m[row][col] | |
if __name__ == "__main__": | |
# Load image. | |
im = Image.open("test1_512.png") # Must be a single band image! (grey) | |
# Create an image buffer object for fast access. | |
pix = im.load() | |
# Convert the 2d image to a 1d sequence: | |
m = list(im.getdata()) | |
# Convert the 1d sequence to a 2d matrix. | |
# Each sublist represents a row. Access is done via m[row][col]. | |
m = [m[i:i+im.size[0]] for i in range(0, len(m), im.size[0])] | |
# Cast every item in the list to a float: | |
for row in range(0, len(m)): | |
for col in range(0, len(m[0])): | |
m[row][col] = float(m[row][col]) | |
# Perform a forward CDF 9/7 transform on the image: | |
m = fwt97_2d(m, 3) | |
seq_to_img(m, pix) # Convert the list of lists matrix to an image. | |
im.save("test1_512_fwt.png") # Save the transformed image. | |
# Perform an inverse transform: | |
m = iwt97_2d(m, 3) | |
seq_to_img(m, pix) # Convert the inverse list of lists matrix to an image. | |
im.save("test1_512_iwt.png") # Save the inverse transformation. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment