Академический Документы
Профессиональный Документы
Культура Документы
The objective of our project was to perform the discrete Haar wavelet transformation
on an image for the purpose of compression. The Haar wavelet transformation is
composed of a sequence of low-pass and high-pass filters, known as a filter bank.
These filter sequences can be applied in the same way as a discrete FIR filter in the
DSP, using the MACP command, except as multiple successive FIR filters. The low
pass filter performs an averaging/blurring operation, and is expressed as:
1
H= ( 1,1)
2
and the high-pass filter performs a differencing operation and can be expressed as:
1
G= ( 1, -1)
2
on any adjacent pixel pair. The complete wavelet transform can be represented in
matrix format by:
T = WN AWNT
where A is the matrix representing the 2D image pixels, T is the Haar wavelet
transformation of the image, and
1 1
2 0 0 0 0 0 0
2
1 1
0 0
2 2
0 0 0 0
0 1 1
0 0 0 0 0
2 2
0 1 1
0 0 0 0 0
H 2 2
WN = =
G 1 1
- 0 0 0 0 0 0
2 2
0 1 1
0 - 0 0 0 0
2 2
0 1 1
0 0 0 - 0 0
2 2
0 1 1
0 0 0 0 0 -
2 2
in the case of transforming a 4x4 pixel image. The equivalent matrix can be expanded
for larger images. This transformation can be represented by an FIR filter approach
for use with the DSPs MACP operation. We will discuss this in more detail later.
The wavelet transformation employs the use of a technique called averaging and
differencing. Below is a simple example of the technique performed on a single row
of the matrix of pixels that represent an image.
Imagine extracting one row from a 16x16 black and white, 256-color image in its
matrix form. For example:
Original Sequence:
45 45 46 46 47 48 53 101 104 105 106 106 107 106 106 106
Every element in this 16-element vector has a value between 0 and 255 since the
image is 256-color. The magnitude of the element represents the brightness of its
corresponding pixel. Hence, the darker it is, the closer it is to black (0).
Inside most of the pixel sequence, we notice that most of the elements have values
very close to the values of their neighbors this indicates a gradual shift in color.
Sudden jumps in values occur at the outlines (edges) of objects in the image (53 to
101), which are sudden transitions in brightness.
We also know that any two numbers can be completely characterized by their average
and their difference. In the sequence above, the averages and differences of successive
pairs are:
Averages:
45 46 47.5 77 105 106 107 106
Differences:
0 0 -1 -48 -1 0 1 0
Now, we observe that the sequence of differences has many small (recall that
neighboring values are very similar, implying small differences). This sequence is
therefore very easy to compress. We perform the compression by making all the
values of small magnitude 0. Hence we have a very sparse sequence.
This sequence is highly compressible. Using this new sequence of differences and the
same sequence of averages, we can easily recompute the original sequence that
defined a section of the image:
Recovered Sequence:
45 45 46 46 47 47 53 101 104 104 106 106 106 106 106 106
To perform the transformation in DSP we loaded the pixel values for the image into
DSP memory, process the image in the DSP assembly program, and output the
transformed image, or transformed-compressed image, to a memory location below
the original image. This data would be processed again to recover the original image.
To be more specific, our original image was loaded at location 0x1800, the
intermediate result, which is the first half of the transformation is stored immediately
below the original image at location 0x1C00. Finally, we store the final output
directly below this at address 0x2000. Below is a memory map showing the addresses
used in the memory for the intermediate result and final result of our output:
Original Image A A
1800 Hex Grayscale Values
Intermediate Result B B = WN A
1C00 Hex Grayscale Values
Project Development:
By the second week, we were well versed with the process of the transformation. Our
goal now was to successfully perform the Haar wavelet transformation of a sample
image in MATLAB. If successful, we expected to see the image in the compressed,
yet lossless form. We imposed no restrictions on the complexity of functions used,
since at this stage all we wanted was to see a result. All our programming at this stage
was in MATLAB. At first we used the various functions to perform the matrix
multiplications. Once successful, we broke down the MATLAB functions that we
used into computations into code that could easily be transferred to assembly
language. The most important process here was the conversion of the matrix
multiplication into a filter representation. We also recreated the MACP command in
MATLAB; this would prove very helpful in the following week when we begin to
convert our MATLAB code to assembly.
After the success of the MATLAB program, we immediately began to rewrite our
code in assembly. Progress slowed down dramatically at this stage, given the many
restrictions and the complexity of programming in assembly. To test our program at
each stage, we performed only the first half of the filter representation of the matrix
multiplication during this week. We constantly compared our results with the results
obtained from performing only the first half of the transformation in MATLAB. This
way we believed that the time spent debugging the program at a later date would be
reduced significantly. Fortunately, progress was satisfactory in this week, and we were
able to move on to the second half of the transformation in the following week.
By this stage in the timeline, we were quite confident of our programming skills in
assembly. We identified errors more quickly, which made the programming less
frustrating. Nonetheless, our progress was always fraught with unexpected and
sometimes arbitrary errors that required much time to correct, mostly by using brute
force. We had a major problem running our code right through. To check our results,
we had to break through the code in code explorer. Because of this problem, our
progress began to crawl. Due to this, we realized that we would not be able to achieve
our initial objective of performing lossless and lossy compression in assembly. We
had also hoped to perform the inverse transformation in assembly. We decided to
pursue only lossless compression because doing this would in itself demonstrate the
capabilities of compression using the wavelet transform. Finally, we realized that the
pipelining of operations was the cause of our inability to run the code in entirety. To
solve this problem, we inserted multiple nop commands after nearly every line of the
code. After this, we successfully got our result and verified it in MATLAB. We also
transferred the hex data from the memory to MATLAB, and performed the inverse
transformation to recover the original, lossless image.
Week 5: Presentation
During this week, we gathered our results and compiled a report of them that was then
transferred to a presentation that was used in class. We reviewed the details of the
wavelet transformation so that we could educate the rest of the class on it too before
demonstrating the results of our project during the presentation.
Discussion of Results:
We were able to successfully perform the Haar wavelet transform for image
compression in Matlab and also on DSP. In Matlab, the forward and inverse
transformation ran as desired and was tested for several different test images. Two
different forward transformations were tested in Matlab; the original matrix
representation of the transformation and its inverse, and the forward transformation as
represented by filter operations on the rows and columns, which is a closer model of
the algorithm used on the DSP. Both representations obtained identical results for the
forward transformation. Two examples tested are shown below, with the original
image on the left and the transformed image on the right, and their sizes as JPEG files
below.
Thus the MATLAB code successfully performed the Haar wavelet transform over the
rows and columns of the image and found the transform T of the image, representing
the transformation:
T = WN AWNT
A = W N-1TWN-T
recovered the original test image without any changes, showing that the lossless
transformation was implemented correctly.
We implemented only the forward transformation on the DSP, due to time limitations.
We were not able to use the test images above to test our algorithm due to the smaller
memory capacity of the DSP. We were only able to use images of size 32x32. We
tested our DSP code for one particular 32x32 test image, and we compared the
resulting transformed image with the transformation as done using our MATLAB
code. We also compared the result of the inverse transformation on both transformed
images. The results are shown in the diagram below.
It is clear that the DSP successfully performed the lossless Haar wavelet transform on
the sample image correctly. There is some difference in compressed image size, due to
the limited 16-bit precision of computations on the DSP. However, despite this lack of
precision equivalent to Matlabs transform, the inverse transformation yielded images
that were not recognizably different from the original image. Thus, any error
introduced by the limited precision of calculation on the DSP does not actually affect
the accuracy of the transformation in any significant way.
We faced some issues with running the code on the DSP. Debugging various errors
took a significant portion of our development time. One particular problem we
encountered had to do with pipelining of operations. Portions of the code would work
perfectly when we step through line by line, but the program would not run correctly
when we try to run it from beginning to end, or even continuously between certain
breakpoints. We found that the solution was to place NOP commands between lines,
and even multiple NOP commands between some lines. This command tells the DSP
processor to halt processing for one cycle, to allow operations to catch up and the
correct computation results to be used in subsequent commands. Our code ran
flawlessly after this correction. The NOP command, of course, will slow the overall
performance of the code, but our algorithm was not meant to run continuously since it
does not operate on time-domain signals. We noticed no slowdown since it only runs
once. Another issue involved the limitation of how values can be assigned to registers
and accumulators. A seemingly simple command like adding two memory addresses
and setting the resulting memory location to an accumulator value is actually a
somewhat complex command to implement correctly in assembly code. It took time
to find workarounds for unforeseen issues such as these. Thus, in the end we only had
time to implement the lossless forward transform on the DSP, and not the lossy
transform or the inverse transform.
Conclusion:
We successfully implemented the 2-dimensional Haar wavelet transformation on the
DSP as applied to lossless image compression. We also implemented the
transformation and its inverse in Matlab and compared the results to verify that our
algorithm was working correctly. We found that compression on the DSP actually
worked, as we achieved smaller JPEG file sizes for the transformed images when
compared to file sizes for the original images, and we were able to fully recover the
original image from these compressed images using Matlab. Challenges and problems
included memory limitation of the DSP, assembly language issues, and automatic
pipelining of processing. Future extensions of this project could include
implementation of the inverse transform on DSP, and implementation of lossy image
compression by setting a threshold value for the transformed image.
References:
Van Fleet, P. Discrete Haar Wavelet Transforms, PREP Wavelet Workshop 2006,
June 7, 2006,
<http://cam.mathlab.stthomas.edu/wavelets/pdffiles/UST06/Lecture4.pdf>
Yusof, Z., Manap, N., Suleiman, I., Saleh, S., Aspar, Z. Impelementation of Wavelet
Codec by using Texas Instruments DSP TMS320C6701 EVM Board,
International Symposium on Signal Processing and its Applications, August
13-16, 2001.
Project Files:
original.jpg:
This is the input image file that will be compressed.
ee113filters.m:
This MATLAB program takes the original input image original.jpg, performs the
wavelet transform on it, and saves the transformed, compressed representation of the
image to transformed_image.jpg.
32.asm:
This file holds the values of the pixels of the image in vector form. These values will
be read by wavelet.asm using the table look-up method.
32noword.asm:
This file is the same as 32.asm, only without the .word directives. This file will is
used by output.m.
8tap.asm:
This file holds the two coefficients of each the two filters that will be used in the
filters in wavelet.asm.
wavelet.asm:
This is the main assembly program file. This program retrieves filter and image
content from 8tap.asm and 32.asm respectively. It then outputs the compressed form
of the image to memory location 0x2000 of the DSP memory.
dsp_output.dat:
This data file contains the output of memory location 0x2000 of the DSP obtained
after running wavelet.asm. The memory, starting at 0x2000, holds the pixel values of
the image that is in the compressed form.
output.m:
This MATLAB program converts the raw data from dsp_output.dat to an image form.
It then displays the original image (using 32noword.asm), the image in compressed
form and the recovered image for comparison.
Code:
wavelet.asm:
.setsect ".data", 0x07EF, 0 ;all program code, FIR coeffs and temp
data stored in first block
.setsect ".text", 0x0180, 0 ;of program memory
.setsect "coeff", 0x07F8, 0
.sect "pic"
picbeg
.copy "32.asm" ;original pic, loaded as array of 8bit
luminance values
.sect "OPpic"
pic2 ;label for output picture
.sect "coeff"
.copy "8tap.asm" ; 2-tap wavelet FIR
; coefficient values here
XN .word 0,0,0,0,0,0,0
XNLAST .word 0 ;
OUTPUT .word 0 ; extra word for the bit bucket
new:
;DP = #XNLAST ;data ptr to allow buffer access
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;situation:
;AR2 is 32
;AR6 is counter
;AR1 is beginning of current input column
;AR3 is beginning of current output column
;AR5 is column number for next column
;AR0, AR4, AR7 unused
nop
nop
nop
nop
*******FIR CODE****************
;AR0, AR7 unused
;B(index, c) = macd([A(r,c) A(r+1,c)],h1);
;index = index+1;
B = #0 ;n-pixels
nop
nop
nop
nop
nop
nop
nop
nop
A = *AR1
nop
nop
nop
nop
*AR7+ = A
nop
nop
nop
nop
A = #0 ;sets A to AR1+32
nop
nop
nop
nop
B = AR1
nop
nop
nop
nop
A = A+B
nop
nop
nop
nop
A = A+#32
nop
nop
nop
nop
AR0 = A
nop
nop
nop
nop
A = *AR0
nop
nop
nop
nop
*AR7+ = A
nop
nop
nop
nop
A = *AR7-
nop
nop
nop
nop
A = *AR7-
nop
nop
nop
nop
B = #0
nop
nop
nop
nop
repeat(#ntaps - 1)
MACP(*AR7+, h0, B)
nop
nop
nop
B = B >> 10
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;RIGHT NOW WHERE WE ARE: above, made MACP
work with one element in row above another for this case
;MUST CHANGE this!!!!! below - not AR3+AR4
; have to be AR3 + AR4*32 = <<5
;store into output - MEMORY ADDRESSING
;must store B to column which starts at AR3
;row of AR4
;memory location is going to be
;AR3+AR4*32
;have A, AR0, AR7
AR7 = B
nop
nop
nop
nop
A = AR3
nop
nop
nop
nop
B = AR4
nop
nop
nop
nop
AR0 = B
nop
nop
nop
nop
B = B << 5
nop
nop
nop
nop
A = A+B
nop
nop
nop
nop
AR0 = A
nop
nop
nop
nop
A = AR7
nop
nop
nop
nop
nop
nop
nop
*AR0 = A
nop
nop
nop
nop
A = AR4
nop
nop
nop
nop
A = A + #1 ;increments index
nop
nop
nop
nop
AR4 = A
nop
nop
nop
nop
A = AR1
nop
nop
nop
nop
A = A + #64
nop
nop
nop
nop
AR1 = A
*******************************
nop
nop
nop
nop
;B = *AR2-
if(*AR2- != 0) goto aloop ;if pixels remaining continue
*************************************************************
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
B = B + #1
nop
nop
nop
nop
AR5 = B
*******FIR CODE****************
;AR0, AR7 unused
;C(r, index) = macd([B(r,c) B(r,c+1)],h1);
;C(r, index+cols/2) = macd([B(r,c) B(r,c+1)],h2);
;index = index+1;
B = #0 ;n-pixels
nop
nop
nop
nop
nop
nop
nop
A = *AR1
nop
nop
nop
nop
*AR7+ = A
nop
nop
nop
nop
A = #0 ;sets A to AR1+32
nop
nop
nop
B = AR1
nop
nop
nop
nop
A = A+B
nop
nop
nop
nop
A = A+#32
nop
nop
nop
nop
AR0 = A
nop
nop
nop
nop
A = *AR0
nop
nop
nop
nop
*AR7+ = A
nop
nop
nop
nop
A = *AR7-
nop
nop
nop
A = *AR7-
nop
nop
nop
nop
B = #0
nop
nop
nop
nop
repeat(#ntaps - 1)
MACP(*AR7+, h2, B)
nop
B = B >> 10
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
AR7 = B
A = AR3
nop
nop
nop
nop
B = AR4
AR0 = B
nop
B = B << 5
nop
A = A+B
nop
AR0 = A
nop
A = AR7
nop
nop
nop
nop
*AR0 = A
nop
A = AR4
nop
A = A + #1 ;increments index
nop
AR4 = A
A = AR1
nop
A = A + #64
nop
AR1 = A
*******************************
nop
;B = *AR2-
if(*AR2- != 0) goto aloop2 ;if pixels remaining continue
*************************************************************
nop
start2
AR5 = #0 ;AR5 holds current row (array indexing)
AR6 = #(nrows - 1) ;counter to loop through each row
nop
nop
nop
nop
;situation:
;AR2 is 32
;AR6 is counter
;AR1 is beginning of current input row
;AR3 is beginning of current output row
;AR5 is row number for next row
;AR0, AR4, AR7 unused
********move down each column and compute h1/h2 filters******
AR4 = #0 ;index variable
nop
*******FIR CODE****************
;AR0, AR7 unused
;C(r, index) = macd([B(r,c) B(r,c+1)],h1);
;C(r, index+cols/2) = macd([B(r,c) B(r,c+1)],h2);
;index = index+1;
B = #0 ;n-pixels
nop
repeat(#ntaps - 1)
MACP(*AR1+, h0, B)
nop
nop
B = B >> 10
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;store into output - MEMORY ADDRESSING
;must store B to row which starts at AR3
;column of AR4
;memory location is going to be
;AR3+AR4
;have A, AR0, AR7
nop
AR7 = B
A = AR3
nop
B = AR4
A = A+B
nop
AR0 = A
A = AR7
nop
nop
nop
nop
*AR0 = A
nop
A = AR4
A = A + #1 ;increments index
AR4 = A
*******************************
nop
;B = *AR2-
if(*AR2- != 0) goto loop ;if pixels remaining continue
*************************************************************
nop
AR2 = #(halfn - 1) ;num times to loop in row (ncols?)
AR1 = #picbeg ;AR1 (input pointer) set to beginning of
pic
A = AR1
A = A+#size
AR1 = A ;Add size to AR1 to set part 2s i/p to part
1s o/p
nop
nop
nop
nop
nop
nop
nop
AR5 = B
B = #0 ;n-pixels
nop
repeat(#ntaps - 1)
MACP(*AR1+, h2, B)
nop
nop
B = B >> 10
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;store into output - MEMORY ADDRESSING
;must store B to row which starts at AR3
;column of AR4
;memory location is going to be
;AR3+AR4
;have A, AR0, AR7
AR7 = B
A = AR3
nop
B = AR4
A = A+B
nop
AR0 = A
A = AR7
nop
nop
nop
*AR0 = A
nop
A = AR4
A = A + #1 ;increments index
nop
AR4 = A
*******************************
nop
;B = *AR2-
if(*AR2- != 0) goto loop2 ;if pixels remaining continue
*************************************************************
nop
WAIT: nop
goto WAIT ; infinite loop at end of execution
.end
ee113filters.m:
function ee113filters()
function sum = macd(ar,h)
%incorporates repeat as well
sum = 0;
for i = 1:length(h)
sum = sum + h(i)*ar(i);
end
end
clear all;
[A,map] = imread('original.jpg','jpg');
B = double(A(:,:,1));
dim = length(B(1,:));
h1 = [0.707 0.707];
h2 = [-0.707 0.707];
A= B;
% the algorithm:
%A is image
%first step: perform B = Wn * A
for c = 1:dim;
%for each column
% h1 filter
index = 1;
for r = 1:2:dim;
%move down the column of A
B(index, c) = macd([A(r,c) A(r+1,c)],h1);
index = index+1;
end
% h2 filter
for r = 1:2:dim;
%move down the column of A
B(index, c) = macd([A(r,c) A(r+1,c)],h2);
index = index+1;
end
end
for r = 1:dim;
%for each row of B
% h2 filter
index = 1;
for c = 1:2:dim;
%move down the row of B
C(r, index) = macd([B(r,c) B(r,c+1)],h1);
index = index+1;
end
% h2 filter
for c = 1:2:dim;
%move down the row of B
C(r, index) = macd([B(r,c) B(r,c+1)],h2);
index = index+1;
end
end
out = C;
out2(:,:,1) = uint8(out);
out2(:,:,2) = uint8(out);
out2(:,:,3) = uint8(out);
imwrite(out2,'transformed_image.jpg','jpg');
end
output.m:
% This program converts the raw data points from the DSP output into an
% image. It also outputs the image onto the computer.
close all;
clear all;
clc;
% VARIABLES
=============================================================
ORIGINAL = '32noword.asm'; % original image
RAW = 'dsp_output.dat'; % processed raw data points
OUTPUT = 'dsp_output.jpg'; % name of output file
%
=============================================================
==========
% Read data
=============================================================
==
original = load(ORIGINAL); % original image data with .word directives
removed
[row,col] = size(original);
raw1 = load(RAW); % raw data
%
=============================================================
==========
filtered1(:,:,1) = uint8(filtered11);
filtered1(:,:,2) = uint8(filtered11);
filtered1(:,:,3) = uint8(filtered11);
%
=============================================================
==========
dim = 32;
for r = 1:dim;
for c = 1:dim;
if (c == 2*r || c == 2*r - 1 )
Wn(r,c) = 0.707;
elseif c == 2*(r-dim/2)
Wn(r,c) = 0.707;
elseif c == 2*(r-dim/2)-1
Wn(r,c) = -0.707;
else
Wn(r,c) = 0;
end
end
end
original = inv(Wn)*filtered11*inv(Wn');
original2(:,:,1) = uint8(original);
original2(:,:,2) = uint8(original);
original2(:,:,3) = uint8(original);
imwrite(original2,'original_actual.jpg','jpg'); %Save the recovered image
% Plot data
=============================================================
===
figure(1);
subplot(3,3,2);
colormap('gray(256)');
imagesc(original);
title('Original Image');
subplot(3,3,5);
colormap('gray(256)');
imagesc(filtered1);
title('Image in Compressed Form');
subplot(3,3,8);
colormap('gray(256)');
imagesc(original2);
title('Recovered Image');
%
=============================================================
==========
% Clear data
=============================================================
==
clear ORIGINAL;
clear OUTPUT;
clear RAW;
clear raw1;
clear row;
clear col;
clear n;