實驗六 數學形態及圖像壓縮
實驗要求
對test 目錄下的圖像進行圖像壓縮測試,調節參數查看效果。
實驗內容
形態學的基本操作(膨脹,腐蝕,開閉等運算)
如何選擇形態學結構元素(保持基本形狀,去除不相關特徵)
JPEG的編碼過程
Huffman編碼的過程
形態學用到matlab自帶的函數:
imdilate :膨脹
imerode:腐蝕
strel :生成結構元素
imopen: 開操作
imclose: 閉操作
bwhitmiss: 擊中擊不中
bwmorph: 實現多種形態學操作
圖像壓縮編碼用到的matlab函數:
huffman **編解碼:**mat2huff,huff2mat
JPEG 編解碼: im2jpeg,jpeg2im
JPEG2000編解碼: im2jpeg2k,jpeg2k2im
參看例子代碼: code目錄下的CompressionTest.m
Code
im2jpeg2k.m 使用JPEG2000近似壓縮一幅圖像
im2jpeg2k使用JPEG2000近似值壓縮圖像
im2jpeg2k Compresses an image using a JPEG 2000 approximation.
Y = im2jpeg2k(X, N, Q) compresses image X using an N-scale JPEG
2K wavelet transform, implicit or explicit coefficient
quantization, and Huffman symbol coding augmented by zero
run-length coding. If quantization vector Q contains two
elements, they are assumed to be implicit quantization
parameters; else, it is assumed to contain explicit subband step
sizes. Y is an encoding structure containing Huffman-encoded
data and additional parameters needed by JPEG2K2IM for decoding.
%im2jpeg2k源程序
function y=im2jpeg2k(x,n,q)
%im2jpeg2k使用JPEG2000近似值壓縮圖像
%y=im2jpeg2k(x,n,q)使用N尺度jpeg2k小波變換,不明確和明確係數量化和零步長解碼去壓縮圖像
%如果量化向量僅包含兩個元素,它們被認爲不明確量化參數。
%否則被認爲包含明確子帶步長。
%y是包含霍夫曼編碼數據和加上爲編碼通過JPEG2K2IM得到的參數的一個編碼結構。
global RUNS
error(nargchk(3,3,nargin));%檢查輸入參數
if nidms(x) ~=2 | ~isreal(x) | ~isnumeric(x) | ~isa(x,'uint8')
error('The input must be a UINT8 image.');
end
if length(q) ~=2 & length(q) ~=3*n+1
error('The quantization step size vector is bad.');
end
%水平平移輸入和計算它的小波變量
x=double(x)-128;
[c,s]=wavefast(x,n,'jpeg9.7');
%量化小波係數
q=stepsize(n,q);
sgn=sign(c);sgn(find(sgn==0))=1;c=abs(c);
for k=1:n
qi=3*k-2;
c=wavepaste('h',c,s,k,wavecopy('h',c,s,k)/q(qi));
c=wavepaste('v',c,s,k,wavecopy('v',c,s,k)/q(qi+1));
c=wavepaste('d',c,s,k,wavecopy('d',c,s,k)/q(qi+2));
end
c=wavepaste('a',c,s,k,wavecopy('a',c,s,k)/q(qi+3));
c=floor(c);c=c.*sgn;
%通過創造一個特別的編碼爲0執行和結束編碼來開始和做一個步長表
zrc=min(c(:))-1;eoc=zrc-1;RUNS=[65535];
%找到步長變換指針:'plus'包含零運行開始的指針與相適應的minus是它的結束+1
z=c==0;z=z-[0 z(1:end-1)];
plus=find(z==1);minus=find(z==-1);
%從c中刪除零運行
if length(plus) ~=length(minus)
c(plus(end):end)=[];c=[c eoc];
end
%刪除從c中所有其他零運行(建立在'plus'和'minus')
for i=length(minus):-1:1
run=minus(i)-plus(i);
if run>10
ovrflo=floor(run/65535);run=run-ovrflo*65535;
c=[c(1:plus(i)-1) repmat([zrc 1],1,ovrflo) zrc ...
runcode(run) c(minus(i):end)];
end
end
%霍夫曼編碼和加混合。解碼信息
y.runs=uint16(RUNS);
y.s=uint16(s(:));
y.zrc=uint16(-zrc);
y.q=uint16(100*q');
y.n=uint16(n);
y.huffman=mat2huff(c);
所用函數:
wavefast
function [c, s] = wavefast(x, n, varargin)
%wavefast源函數
function [c,s]=wavefast(x,n,varargin)
%wavefast執行一個二維快速小波變換
%[c,l]=wavefast(x,n,lp,hp)用帶有最大值和最小值的重構濾波器執行一個FWT圖像
%[c,l]=wavefast(x,n,wname)執行同樣的程序,但是使用wavefilter爲小波wname取得一個帶有最大值和最小值的濾波器
%其中尺度參數n必須小於或等於圖像維數最大值的log2。濾波器的最大值和最小值必須是偶數。
%爲了減少邊界失真,x必須是對稱擴展的。例如x=[c1 c2 c3 ... cn](一維的),而它的對稱擴展是[... c3 c2 c1 c1 c2 c3 ... cn cn cn-1 cn-2 ...]
%輸出:
%矩陣c是係數分解向量:
%c=[a(n) h(n) v(n) d(n) h(n-1) ... v(1) d(1)]
%其中a,h,v和d分別是包含近似值,水平的,垂直的,和二維繫數矩陣的列向量。c有3n+1個部分,其中n是小波重構數。
%矩陣s是一個(n+2)*2的簿記矩陣
%s=[sa(n,:);sd(n,:);sd(n-1,:);... sd(1,:);sx],其中sa和sd是近似值和細節大小條目
%檢查輸入參數
error(nargchk(3,4,nargin));
%nargin用來判斷輸入變量個數的函數,
%當nargin的值大於4時,nargchk返回字符串'Too many input arguments';當nargin的值小於3時,nargchk返回字符串'Not enough input arguments';
%當nargin的值在3到4之間,nargchk返回空字符串。error以錯誤的方式顯示警告字符串(以紅色字體顯示)。
if nargin==3
if ischar(varargin{1})
[lp,hp]=wavefilter(varargin{1},'d');
else
error('Missing wavelet name.');
end
else
lp=varargin{1};hp=varargin{2};
end
f1=length(lp);sx=size(x);
if (ndims(lp)~=2) | (min(sx)<2) | ~isreal(x) | ~isnumeric(x)
error('X must be a real,numeric matrix.')
end
if(ndims(lp)~=2) | ~isreal(lp) | ~isnumeric(lp)...
| (ndims(hp)~=2) | ~isreal(hp) | ~isnumeric(hp)...
| (f1~=length(hp)) | rom(f1,2)~=0
error(['LP and HP must be even and equal length real,''numeric filter vectors.']);
end
if ~isreal(n) | ~isnumeric(n) | (n<1) | (n>log2(max(sx)))
error(['N must be a real scalar between 1 and' 'log2(max(size(X))).']);
end
%設置最初的輸出數據結構和最初近似值
c=[];s=sx;app=double(x);
%對於每個重構
for i=1:n
%對稱地擴展近似值
[app,keep]=symextend(app,f1);
%用hp和採樣率計算卷積行。然後用hp和lp得到的卷積列去獲取對角線和垂直的係數。
rows=symconv(app,hp,'row',f1,keep);
coefs=symconv(rows,hp,'col',f1,keep);
c=[coefs(:)' c];s=[size(coefs);s];
coefs=symconv(rows,lp,'col',f1,keep);
c=[coefs(:)' c];
% 用hp和採樣率計算卷積行。然後用hp和lp得到的卷積列去獲取垂直的和下一個近似的係數。
rows=symconv(app,lp,'row',f1,keep);
coefs=symconv(rows,hp,'col',f1,keep);
c=[coefs(:)'c];
app=symconv(rows,lp,'col',f1,keep);
end
%附加最後的近似值結構
c=[app(:)'c];s=[size(app);s];
stepsize
function q=stepsize(n,p)
%stepsize源程序
function q=stepsize(n,p)
%通過分解創造步驟大小順序的一個子帶量化和子帶(水平的、垂直的、對角線的和近似值子帶的最後分解)
if length(p)==2%不明確量化
q=[];
qn=2^(8-p(2)+n)*(1+p(1)/2^11);
for k=1:n
qk=2^-k*qn;
q=[q (2*qk) (2*qk)(4*qk)];
end
q=[q qk];
else%明確量化
q=p;
end
q=round(q*100)/100;%大約1/100分配
if any(100*q>65535)
error('The quantizing steps are not UNIT16 representable.')
end
if any(q==0)
error('A quantizing step of 0 is not allowed.');
end
wavepaste
function nc=wavepaste(type,c,s,n,x)
%wavepaste源程序
function nc=wavepaste(type,c,s,n,x)
%wavepaste是在小波重構結構是投入的係數
%粘貼x之後返回一個新的重構結構
%輸入:
%類型 係數類型
%'a' 近似值係數
%'h' 水平細節
%'v' 垂直細節
%'d' 對角線細節
%[c,s]是一個小波數據結構。
%n是指定的重構水平(type='a'則忽略)。
%x是二維近似值或者細節係數矩陣
error(nargchk(5,5,nargin))
nc=wavework('paste',type,c,s,n,x);
wavecopy
function y=wavecopy(type,c,s,n)
%wavecopy源程序
function y=wavecopy(type,c,s,n)
%wavecopy是在小波重構結構是取得的係數
%決定在type和n,返回一個係數數組
%輸入:
%類型 係數類型
%'a' 近似值係數
%'h' 水平細節
%'v' 垂直細節
%'d' 對角線細節
%[c,s]是一個小波數據結構。n是指定的重構水平(type='a'則忽略)。
error(nargchk(3,4,nargin));
if nargin==4
y=wavework('copy',type,c,s,n);
else
runcode
function y=runcode(x)
%runcode源程序
function y=runcode(x)
%在步長表中找到一個零運行,如果沒找到,在表中創造一個新的入口。
%返回運行的指針
global RUNS
y=find(RUNS==x);
if length(y) ~=1
RUNS=[RUNS;x];
y=length(RUNS);
end
mat2huff
function =mat2huff(x)
%mat2huff源函數
function =mat2huff(x)
%mat2huff編碼一個矩陣
%使用符號概率在最大值和最小值之間建立單位寬度直方圖。
%編碼數據返回一個結構y
%y:
%y.code x的Huffman編碼值,儲存在16比特向量。y的其他領域包括額外的解碼信息,包括:
%y.min x的最小值加32768
%y.size x的大小
%y.hist x的直方圖
%如果x是logical,uint8,uint16,uint32,int8,int16,或者double的整數值,可以直接輸入到mat2muff中。
%x的最小值必須是int16.
%如果x是非整值的double。例如:一個圖像的值在0和1之間,首先x的大小應該接近整數的範圍。
%例如y=mat2huff(255*x)是256灰度級編碼
%note:
%Huffman的編碼數是round(max(x(:)))-round(min(x(:)))+1.輸出x的產生合理的長度.x的行數和列數的最大維數和最小維數是65535.
if ndims(x)~=2 | ~isreal(x) | (~isnumeric) & ~islogical(x))
error('X must be a 2-D real numeric or logical matrix.');
end
%輸入x的類型
y.size=uint32(size(x));
%找到x的範圍並儲存最小值+32768作爲一個uint16.
x=round(double(x));
xmin=min(x(:));
xmax=max(x(:));
pmin=double(int16(xmin)); y.min=pmin;
%使用x的最小值和最大值之間之間的單位寬度bin計算x的直方圖h,並縮放該直方圖,以使其爲uint16向量。
x=x(:)';
h=histc(x,xmin,xmax);
if max(h)>65535
h=65535*h/max(h);
end
h=uint16(h);y.hist=h;
%編碼輸入矩陣和儲存結果
map=huffman(double(h));%做Huffman編碼圖
hx=map(x(:)-xmin+1);%產生單元數組
hx=hx(:)';%轉成字符數組
hx(hx=='')=[];%刪除空格符
ysize=ceil(length(hx)/16);%計算編碼大小
hx16(1:length(hx))=hx;%分配模16向量
hx16=hx16'-'0';%在長度上做hx模16
twos=pow2(15:-1:0);%重建
y.code=uint16(sum(hx16.*twos(ones(ysize,1),:),2))';%轉變二維字符串爲十進制
jpeg2k2im.m 解碼IM2JPEG2K壓縮的圖像
jpeg2k2im Decodes an IM2JPEG2K compressed image.
X = jpeg2k2im(Y) decodes compressed image Y, reconstructing an
approximation of the original image X. Y is an encoding
structure returned by IM2JPEG2K.
%jpeg2k2im源程序
function x=jpeg2k2im(y)
%解碼一個im2jpeg壓縮圖像
%x=jpeg2k2im(y)解碼壓縮圖像y,重構初始圖像x的一個近似值。
%y是通過im2jpeg2k返回編碼結構
%也看im2jpeg2k
error(nargchk(1,1,nargin));%檢查輸入參數
%得到解碼參數:尺度、量化向量、步長表大小、零運行編碼、數據結束編碼、小波簿記數組和步長表
n=double(y.n);
q=double(y.q)/100;
runs=double(y.runs);
rlen=length(runs);
zrc=-double(y.zrc);
eoc=zrc-1;
s=double(y.s);
s=reshape(s,n+2,2);
%計算小波變換大小
c1=prod(s(1,:));
for i=2:n+1
c1=c1+3*prod(s(i,:));
end
%通過零運行編碼執行霍夫曼編碼
r=huff2mat(y.huffman);
c=[];zi=find(r==zrc);i=1;
for j=1:length(zi)
c=[c r(i:zi(j)-1) zeros(1,runs(r(zi(j)+1)))];
i=zi(j)+2;
end
zi=find(r==eoc);%撤消終止零運行或最後非零運行
if length(zi)==1
c=[c r(i:zi-1)];
c=[c zeros(1,c1-length(c))];
else
c=[c r(i:end)];
end
%非標準化係數
c=c+(c>0)-(c<0);
for k=1:n
qi=3*k-2;
c=wavepaste('h',c,s,k,wavecopy('h',c,s,k)*q(qi));
c=wavepaste('v',c,s,k,wavecopy('v',c,s,k)*q(qi+1));
c=wavepaste('d',c,s,k,wavecopy('d',c,s,k)*q(qi+2));
end
c=wavepaste('a',c,s,k,wavecopy('a',c,s,k)*q(qi+3));
%計算逆小波變換和水平平移
x=waveback(c,s,'jpeg9.7',n);
x=uint8(x+128);
huff2mat
function x=huff2mat(y)
%huff2man源程序
function x=huff2mat(y)
%huff2man解碼一個Huffman編碼的矩陣
%x=huff2man(y)解碼一個Huffman編碼的16比特的結構y
%field:
%y.min x的最小值+32768
%y.size x的大小
%y.hist x的直方圖
%y.code Huffman編碼
%輸出x是雙精度
if ~isstruct(y) | ~isfield(y,'min') | ~isfield(y,'size') | ...
~isfield(y,'hist') | ~field(y,'code')
error('The input must be a structure as returned by MAT2HUFF');
end
sz=double(y.size);m=sz(1);n=sz(2);
xmin=double(y.min)-32768;%得到x的最小值
map=huffman(double(y.hist));%得到Huffman編碼
%爲Huffman解碼程序創造一個二維調查表
%code包含源符號字符串與連接編碼符合,
%當'link'包含映射(+)是給編碼符號字符串加上0和1,映射(-)是給解碼Huffman編碼詞放在map中。
%數組'left'是一列編碼,目前給link入口加工的。
code=cellstr(char('','0','1'));%設置開始條件
link=[2;0;0];left=[2 3];
fiund=0;tofind=length(map);%處理變量
while length(left) & (found<tofind)
look=find(strcmp(map,code{left(1)}));%map是否是字符串?
if look%是的
link(left(1))=-look;%指出 Huffman圖
left=left(2:end);%刪除當前編碼
found=found+1;%found編碼的增量
else
len=length(code);%不是的話,加上2編碼與指標
link(left(1))=len+1;%在編碼中加指標
link=[link;0;0];%加未加工的編碼
code{end+1}=strcat(code{left(1)},'0');
code{end+1}=strcat(code{left(1)},'1');
left=left(2:end);%刪除加工編碼
left=[left len+1 len+2];%加2個未加工編碼
end
end
x=unravel(y.code',link,m*n);%使用C拆散解碼
x=x+xmin-1;%調整x最小值的補償
x=reshape(x,m,n);%是向量成爲一個數組
waveback
function [varargout]=waveback(c,s,varargin)
%%wavebac源程序
function [varargout]=waveback(c,s,varargin)
%waveback函數執行一個二維n階水平部分或完整的小波分解結構[c,s]的重構
%syntax:
%y=waveback(c,s,'wname');輸出FWT的逆矩陣y
%y=waveback(c,s,lr,hr);使用低通和高通重構濾波器或名爲'wname'的波形濾波器
%[nc,ns]=waveback(c,s,'wname',n);輸出新的小波
%[nc,ns]=waveback(c,s,lr,hr,n);n步重構後的分解結構[nc,ns]
%檢查輸入和輸出參數
error(nargchk(3,5,narargin));
error(nargchk(1,2,nargout));
if(ndims(c)~=2) | (size(c,1)~=1)
error('C must be a row vector.');
end
elements=prod(s,2);
if(length(c)<elements(end)) | ~(elements(1)+3*sum(elements(2:end-1))>=elements(end))
error(['[c s] must be a standard wavelet''decomposition structure.']);%標準小波分解結構
end
%在[c,s]中的最大水平
nmax=size(s,1)-2;
%得到第三個輸入參數和開始檢查標記
wname=varargin{1};filterchk=0;nchk=0;
switch nargin
case 3
if ischar(wname)
[lp,hp]=wavefilter(wname,'r');n=nmax;
else
error('Undefined filter.');
end
if nargout~=1
error('Wrong number of output arguments.');
end
case 4
if ischar(wname)
[lp,hp]=wavefilter(wname,'r');
n=varargin{2};nchk=1;
else
lp=varargin{1};hp=varargin{2};
filterchk=1;n=nmax;
if nargout~=1
error('Wrong number of output arguments.');
end
end
case 5
lp=varargin{1};hp=varargin{2};filterchk=1;
n=varargin{3};nchk=1;
otherwise
error('Improper number of input arguments.');
end
f1=length(lp);
if filterchk
if (ndims(lp)~=2) | ~isreal(lp) | ~isnumeric(lp)...
| (ndims(hp)~=2) | ~isreal(hp) | ~isnumeric(hp)...
|(f1~=length(hp)) | rem(f1,2)~=0
error(['LP and HP must be even and equal length real,''numeric filter vectors.']);
end
end
if nchk & (~isnumeric(n) | isreal(n))
error('N must be a real numeric.');
end
if (n>nmax) & (nargout~=2)
error('Not enough output arguments.');
end
nc=c;ns=s;nnmax=nmax;
for i=1:n
%計算新的近似值
a=symconvup(wavecopy('a',nc,ns),lp,lp,f1,ns(3,:))+...
symconvup(wavecopy('h',nc,ns,nnmax),...
hp,lp,f1,ns(3,:))+...
symconvup(wavecopy('v',nc,ns,nnmax),...
lp,hp,f1,ns(3,:))+...
symconvup(wavecopy('d',nc,ns,nnmax),...
hp,hp,f1,ns(3,:));
%更新分解
nc=nc(4*prod(ns(1,:))+1:end);nc=[a(:)' nc];
ns=ns(3:end,:);
nnmax=size(ns,1)-2;
end
%爲完成重構,重定輸出格式爲二維
if nargout==1
a=nc;nc=repmat(0,ns(1,:));nc(:)=a;
end
varargout{1}=nc;
if nargout==2
varargout{2}=ns;
end
imratio.m 計算壓縮比
該函數用於表示兩幅圖像文件或者變量的比特數的比率。
imratio Computes the ratio of the bytes in two images/variables.
CR = imratio(F1, F2) returns the ratio of the number of bytes in
variables/files F1 and F2. If F1 and F2 are an original and
compressed image, respectively, CR is the compression ratio.
%imratio源函數
function cr=imratio(f1,f2)
%imratio計算兩幅圖像或兩個變量的比特數的比率
%返回f1和f2這兩幅圖像或兩個變量的比特數的比率
%f1是原始圖像,f2是壓縮後圖像,cr是壓縮比率
error(nargchk(2,2,nargin));%檢查輸入參數
cr=bytes(f1)/bytes(f2);%計算比率
%--------------------------------------------------%
function b=bytes(f)
%返回輸入f的比特數
%如果f是字符串,則它是一個圖像文件名;如果不是,它是一個圖像變量
if ischar(f)
info=dir(f);b=info.bytes;
elseif isstruct(f)
%matlab的函數報告每個結構領域的124個字節的內存,因爲matlab在內存中儲存結構。
%不要計算這額外的內存;相反,將這些內存與每個領域聯繫
b=0;
fields=fieldnames(f);
for k=1:length(fields)
b=b+bytes(f.(fields{k}));
end
else
info=whos('f');b=info.bytes;
end
compare.m 計算均方誤差
%compare源程序
function rmse=compare(f1,f2,scale)
%compare計算和展示兩個矩陣的誤差
%返回輸入f1和f2平方值得平方根誤差和展示誤差的直方圖和程度誤差圖像。
%當scale省略時,默認爲一度程度。
%檢查輸入參數和設置默認值
error(nargchk(2,3,nargin));
if nargin<3
scale=1;
end
%計算平均值的平方根誤差
e=double(f1)-double(f2);
[m,n]=size(e);
rmse=sqrt(sum(e(:).^2)/(m*n));
%如果rmse不等於0,輸出誤差圖像和直方圖
if rmse
%形成錯誤直方圖
emax=max(abs(e(:)));
[h,x]=hist(e(:),emax);
if length(h)>=1
figure;bar(x,h,'k');
%對稱地顯示誤差圖像
emax=emax/scale;
e=mat2gray(e,[-emax,emax]);
figure,imshow(e);
end
end
基礎知識 ——總有一些東西是需知的
數字圖像壓縮中,三種基本的數據冗餘:
1、編碼冗餘
壓縮:平均最優編碼長度;霍夫曼編碼
2、心理視覺冗餘
量化壓縮,會導致數據有損壓縮。心理視覺冗餘是指那些不十分重要的信息。這些冗餘在不會削弱圖像感知質量的情況下可以消除。
3、像素間冗餘
基於預測編碼可以消除像素間冗餘。
JPEG壓縮——JPEG
該算法基於離散餘弦變換DCT
JPEG壓縮——JPEG2000
基於小波變換
形態學圖像處理
膨脹與腐蝕
開操作與閉操作
開操作:先腐蝕再膨脹
閉操作:先膨脹再腐蝕
CompressionTest.m 壓縮測試
clc
clear all
f=imread('E:\University\Digital image\實驗6\實驗六 數學形態學及圖像壓縮\實驗六 數學形態學及圖像壓縮\test\euro2016.jpg');
figure(1),imshow(f);
f=rgb2gray(f); %轉換爲灰度圖像
figure(2),imshow(f);
c1=im2jpeg2k(f,5,[8 8.5]); % 使用JPEG2000近似壓縮一幅圖像Imratio
f1=jpeg2k2im(c1); %解碼IM2JPEG2K壓縮的圖像
figure(3),imshow(f1);
cr = imratio(f,c1); %計算兩幅圖像或變量中的比特率 計算壓縮比 原圖像/壓縮後圖像
rms = compare(f,f1); %計算均方誤差
f:
f1:
壓縮比:15.4382
rms:5.1758
c1=im2jpeg2k(f,8,[8 8.5]); % 使用JPEG2000近似壓縮一幅圖像Imratio
cr:114.1585
rms:18.4194