数字图像处理:数学形态及图像压缩

实验六 数学形态及图像压缩

实验要求

对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

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值