嵌入式小波零树(EZW)算法的过程详解和Matlab代码(2)编码过程(081227-补充quantifier程序)

时间:2021-11-16 04:42:19


首先根据实际需要确定扫描次数D=codeDim,然后进行D次主扫描和辅扫描。

1、初始化
首先获取扫描次序表scanlist,表中每行的数字依次是该元素的(1)扫描序号、(2)对应于数据矩阵中位置的行号r、(3)对应于数据矩阵中位置的列号c、(4)值Mat(r,c),即
                                            
scanlist (i) = [ i, r, c, Mat(r,c) ]
编码扫描的对象就是次序表scanlist,而非数据矩阵Mat。
然后构建初始符号矩阵flagMat,其中每个元素均为字符“Z”。

2、主扫描
在第d次(1<= d <=codeDim)扫描中,输入阈值为T(d),首先依次对次序表的每一行scanlist(i)按照如下步骤扫描:
(1)    如果上一次扫描得到的flagMat中,处于位置(r,c)的符号为“O”,则表示相应的Mat(r,c)是重要的,不需要通过本次扫描再次编码,故作跳过处理。
(2)    将scanlist(i,4)(即Mat(r,c))的绝对值与阈值T(d) 比较,如果是重要的系数,则令flagMat(r,c)的值为P或N,并存入主扫描表scancode中,并将Mat(r,c)的值以及相应的行、列数(r,c)存入重要数列表imptvalue中,将符号P或N存入重要数符号列表imptflag中。
(3)    如果是不重要的系数,则首先检查flagMat(r,c),若是符号“X”,则表示这个点是不重要的,作跳过处理不再扫描。
(4)    如果点(r,c)处于第一分解级,即r>row/2或c>col/2,没有子孙系数,且其系数是不重要的,则该点flagMat的符号为Z,存入主扫描表scancode中。
(5)    如果点(r,c)满足r<row/2且c<col/2,则检查其子孙系数中是否有重要系数。有,则flagMat(r,c)的值为字符Z,存入主扫描表scancode中;否则flagMat(r,c)的值为T,存入主扫描表scancode中,并令其所有子孙系数相应的flagMat(r’,c’)值为字符X,不再作下一次扫描。
至此,扫描结束。然后,将扫描后得到的符号矩阵flagMat转存到scanflag中,再将flagMat中的字符P、N都置换为O,字符X和T都置换为Z,使得flagMat的元素只有字符O、Z两种,作为输出到下一次扫描中使用。

function [imptvalue,imptflag,scancode,scanflag,flaglist]=mainscan(Mat,scanlist,flaglist,imptvalue,imptflag,threshold)

global row col
scancode=[];
for i=1:row*col
    if flaglist(scanlist(i,2),scanlist(i,3))=='O'
        continue;
    elseif abs(scanlist(i,4))>=threshold
        if scanlist(i,4)>=0
            flaglist(scanlist(i,2),scanlist(i,3))='P';
            scancode=[scancode 'P'];
            imptvalue=[imptvalue;abs(scanlist(i,4)),scanlist(i,2),scanlist(i,3)];
            imptflag=[imptflag 'P'];
        else
            flaglist(scanlist(i,2),scanlist(i,3))='N';
            scancode=[scancode 'N'];
            imptvalue=[imptvalue;abs(scanlist(i,4)),scanlist(i,2),scanlist(i,3)];
            imptflag=[imptflag 'N'];
        end
    else
        if flaglist(scanlist(i,2),scanlist(i,3))=='X'
            continue;
        elseif i>row*col/4
            scancode=[scancode 'Z'];
        else
            [chImt,chMat]=childImportant(Mat,scanlist(i,2),scanlist(i,3),threshold,flaglist);
            if chImt
                flaglist(scanlist(i,2),scanlist(i,3))='Z';
                scancode=[scancode 'Z'];
            else
                flaglist(scanlist(i,2),scanlist(i,3))='T';
                scancode=[scancode 'T'];
                [rowch,colch]=size(chMat);
                for r=1:rowch
                    if flaglist(chMat(r,1),chMat(r,2))~='O'
                        flaglist(chMat(r,1),chMat(r,2))='X';
                    end
                end
            end
        end
    end
end
scanflag=flaglist;
for r=1:row
    for c=1:col
        switch flaglist(r,c)
            case {'P','N'}
                flaglist(r,c)='O';
            case {'X','T'}
                flaglist(r,c)='Z';
        end
    end
end
 
 
function [chImt,chMat]=childImportant(Mat,chRows,chCols,threshold,flaglist)
global row col
chMat=childMat(Mat,chRows,chCols);
if max(abs(chMat(:,3)))>=threshold
    chImt=1;
else
    chImt=0;
end

3、辅扫描
辅扫描是对输出符号为P和N的系数进行量化,并将量化符号存入辅扫描表quantiflag中。在主扫描中,将输出符号为P和N的系数的符号信息和数值分别储存在列表imptflag和imptvalue中。辅扫描的具体过程是:
(1)构造量化器
量化器的构造比较简单,不过关键的问题是要确定每一级扫描中量化器的数目。首先,量化区间的最大区间值应该是初始阈值的2倍,最小值是当前的阈值,故第d级扫描时,总的量化区间为[ T(d), 2*T(1) );而量化间隔为T(d),故第d级扫描的量化器数目为:Q = [2*T(1) — T(d)] / T(d) 。
确定量化器数目后,就要确定每个量化器中“0”“1”对应的量化值。根据算法原理,第q个量化器中,相应于符号“0”的量化值为:T(d)*(q+0.25),相应于符号“1”的量化值为:T(d)*(q+0.75)。至此,量化器构造完成。

function [quantifierMat,threshold]=quantifier(T1,level)
quantifierMat=[];
maxInterValue=2*T1;
threshold=T1/2^(level-1);
intervalNum=maxInterValue/threshold-1;
for i=1:intervalNum
    quantifierMat=[quantifierMat;threshold*(i+0.25) threshold*(i+0.75)];
end

 


(2)辅扫描过程
首先要确定这个重要系数属于量化器。根据总量化区间与量化间隔的关系,只要将重要系数除以量化间隔,所得的商就是该重要系数所在的量化器编号。即:
                                                   
rI=flor(imptvalue(j) /threshold);
将重要系数减去量化器的起始值,所得的值与量化间隔的二分之一值相比较,

 

小于的话,则量化符号为“0”,大于则量化符号为“1”。然后选择量化重构值,存入重构列表recvalue中。

function [quantilist,quantiflag,recvalue,quantifierMat]=assistscan(imptvalue,dim,T1)
quantilist=[];
quantiflag=[];
recvalue=[];
 
[quantifierMat,threshold]=quantifier(T1,dim);
 
[imRow,imCol]=size(imptvalue);
for j=1:imRow
    rI=flor(imptvalue(j)/threshold);
    flag01=imptvalue(j)-rI*threshold;
    if flag01<threshold/2
        quantiflag=[quantiflag;0];
        recvalue=[recvalue;quantifierMat(rI,1)];
    else
        quantiflag=[quantiflag;1];
        recvalue=[recvalue;quantifierMat(rI,2)];
    end
end
quantilist=[imptvalue(:,1),quantiflag,recvalue,imptvalue(:,2),imptvalue(:,3)];

4、编码输出
每级扫描完成后,把主扫描输出的主扫描表scanlist存入列表Codelist中,并用一个辅助列表LenSubCL记录这一级主扫描表的表长(在信号传输应用中不一定用得上);把辅扫描输出的量化符号列表quantiflag存入列表QuantiFlagList中,并用一个辅助列表LenSubQFL记录辅扫描表的表长。

以下是经过3次扫描后的编码输出

code_level =     1
scancode =      ZPPPTTTTTTTTTTTT
quantiflag =     011

code_level =     2
scancode =      PZTTTZNTTTTTTTZTNTTTZNTTTZZZNZNZZZZNZZZZZ
quantiflag =     1111000110

code_level =     3
scancode =     NPTTNNZTNTTTNTPNPTTNZNZTTZZTTZZTTNTTTZZZZNZZZPPNZZNZPZPZZZZ
ZZZNZ
                      NZZZNNPZZZZPZZPPZZPZZZNZZZZZZZ

quantiflag =    101101001001100110001010100101011000110