JPEG Image Compression Implemented in Matlab

advertisement
JPEG Image Compression
Implemented in Matlab
By Michael Christensen
Abstract:
In this project I attempted to implement basic JPEG compression using only basic
Matlab functions. This included going from a basic grayscale bitmap image all the way
to a fully encoded file readable by standard image readers. I will show that I have
implemented the majority of the project, including much of the final binary coding.
Although I never obtained a fully completed image from my functions, I came very close.
Results:
In this section I will present the steps of obtaining a finalized JPEG file and how I
implemented each step in matlab. I will comment on possible improvements and
mistakes made in each case. The code used is attached at the end of this report.
Step1: Converting the base image to 8x8 matrices, DCT transform, quantizing
These steps were relatively easy, especially in matlab, which is specifically set up
to work with matrices. The 2-D discrete cosine transform is done simply with the dct2()
command. After splitting the matrix into 8x8 matrices and performing the DCT, a simple
piecewise division by the quantization matrix obtains the quantized matrices needed for
the next step.
Step 2: Zig-Zag Encoding of Quantized Matrices
I found no matlab implementation for this function, so I wrote one myself. I took
advantage of the fact that each diagonal row has addresses that add up to the same
number. Depending on whether the number is even or odd determined the direction of
the iteration through the row. The code I wrote is able to zig-zag through any matrix of
equal height and width. This could be useful if one wanted to experiment with deviding
images into matrices larger than 8x8.
Step 3: Conversion of quantized vectors into the JPEG defined bitstream
For this step, I started with an old implementation of the default AC code written
by Yu Hen Hu. After updating the code to work with Matlab 7 I modified the code to
encode the first number in the incoming vector with the default DC code, the table for
which I added to the file. The function returns a completed bitstream to correspond to the
input of the quantized vector.
I am sorry to say I cannot guarantee that the code contained in vecenc.m is at all
reliable. I tested single vectors with standard examples and obtained the correct result.
However, having never obtained a final result, I cannot guarantee that this function
complies with the JPEG standard.
Step 4: Construction of the JPEG File header, Writing the File
Being relatively inexperienced with coding in general, this step presented me with
the most trouble overall. It took several hours to determine how to encode a binary
vector into a file. It took even longer to realize that each byte encoded into the file was
being represented with the least significant bits on the left side. After overcoming that
obstacle, I was faced with the task of constructing a file header for my bit stream.
The JPEG standard only goes as far as conversion to the binary bit stream. While
that process is well defined in scientific papers, the construction of a JPEG file header is
not. In the matlab file head.m, I tried to express what I learned about the process in the
most expressive way possible.
It seems that the JPEG file is broken into many blocks. Each block begins with
two bytes, the first being FF in hexadecimal and the second being ‘XX’ where different
‘XX’s denoting different blocks. The second part of each block is the length, in bytes, of
the block including the two length bytes. The rest of the block contains the data as
defined by the block type.
As of this writing, I am in the middle of coding head.m, but will be unable to
finish due to time constraints. I am confident, though, that I have a very good
understanding of how the rest of the header construction would proceed.
Conclusion:
While not completing the goal I set out to achieve, I have demonstrated that
conversion from a grayscale image to the JPEG encoded binary bit stream is a fairly
simple and straightforward process. It comes as no surprise to me that the file I/O was
the most challenging part of the process.
As for where to go from here, I hope to complete the project in my free time and
publish the matlab files on the internet. I believe that while there are far more powerful
and efficient implementations of the JPEG algorithm out there, other students like myself
would benefit from a simple and straightforward implementation that emphasizes step-by
step explanations of what is going on and why.
function b = jpeg(file);
%
%
%
%
%
%
%
%
%
%
Usage : Input an image file and recieve the jpeg implementation
of the file.
b:
file:
output binary stream
input file
by Michael Christensen
December 14, 2005
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%
% Step 1: Read in the file, obtain parameters
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
A = imread(file); %reads file into a matrix
B = imfinfo(file); %reads file info
%convert to YCbCr
%if B.Format=='bmp'
%
A=rgb2ycbcr(A)
width=B.Width;
height=B.Height;
%detirmine number of 8x8 matrices, use ceil to round up
W=ceil(width/8);
H=ceil(height/8);
%create a matrix of zeros and add the image to it to fill out the 8x8
%matrices (matrix will stay the same size if height and width are
%divisible by 8
I=zeros(H*8,W*8,'uint8');
I(1:height,1:width)=A(1:height,1:width);
%divide numbers into WxH 8x8 matrices
X=zeros(H,W,8,8);
for J=1:H
for K=1:W
for j=1:8
for k=1:8
X(J,K,j,k)=I((J-1)*8+j,(K-1)*8+k);
end
end
end
end
%define
Q=[...
16
12
14
14
18
24
49
72
luminance quantization matrix
11
12
13
17
22
35
64
92
10
14
16
22
37
55
78
95
16
19
24
29
56
64
87
98
24
26
40
51
68
81
103
112
40
58
57
87
109
104
121
100
51
60
69
80
103
113
120
103
61
55
56
62
77
92
101
99];
b=[];
vprev=[];
vcurrent=[];
for J=1:H
for K=1:W
temp=zeros(8,8,'uint8');%create temporary matrix
temp(:,:)=X(J,K,:,:);%add values from current 8x8 sector
temp=double(temp);%convert numbers to double format(floating
point)
temp=temp-128;%shift mean to zero
temp=dct2(temp);%perform 2-D cosine transfer function
temp=temp./Q;%devide by quantization matrix
temp=round(temp);%round off the quantized matrix
vcurrent=zigzag(temp);%convert quantized matrix to 1-D vector
vcurrent=shorten(vcurrent);%remove extra zeros from vector
if J==1 && K==1
b=[b vecenc(vcurrent)];
else
vcurrent(1)=vcurrent(1) - vprev(1);%take difference of
first value
b=[b vecenc(vcurrent)];
end
vprev=vcurrent;
end
end
b=[head(Q) b 1 1 1 1 1 1 1 1
denote EOF End of File
1 0 0 1 1 0 1 1];%last two bytes:ff d9
Download