├── RCC └── RCC │ ├── predict.m │ ├── modifyDiffs.m │ ├── Var.m │ ├── utils │ ├── arith_decode.mexw64 │ ├── arith_encode.mexw64 │ ├── Readme.txt │ ├── nonCrossEdge.m │ ├── entropyEmbed.m │ ├── compressOhead.m │ ├── recursiveConstruct.m │ ├── compressFun.m │ ├── arith_encode.m │ ├── arith_decode.m │ ├── bi2de.m │ ├── minDistortionEmr.m │ ├── arith_decode.c │ ├── de2bi.m │ └── arith_encode.c │ ├── embedding.m │ ├── testEmbed.m │ └── imageEmbed.m ├── Matrix.m ├── RDHCE.m ├── decode.m ├── encode.m ├── PEE ├── scale.m ├── PEEmain.m ├── RevMat.m ├── AfterPEE.bmp ├── PEEdecode.m ├── prediction.m └── test.m ├── PEEtest.m ├── PCQI ├── ref.png ├── contrast_changed.png ├── demo.m └── PCQI.m ├── IWT ├── IWTdebed.m ├── IWTembed.m ├── lenagray.tif ├── test.m ├── IIWT.m └── IWT.m ├── functions ├── psnr.m ├── loadim.m ├── quantize.m ├── similarity.m ├── move.m ├── locationmap.m ├── H_of_X.m ├── runlengthcoding.m ├── standard.m ├── cross_entropy.m ├── runlengthdecoding.m ├── outlook.m ├── entropy.m ├── dequantize.m └── fxssim.m ├── test_image ├── dip.tif ├── beans.tif ├── city.tif ├── lena.tif ├── puppy.jpg ├── wood.jpg ├── einstein.tif ├── lenagray.tif └── photographer.tif ├── arithmetic ├── ps_replace.m ├── arithdecode.m ├── arithencode.m ├── dec2bin_zero.m ├── allocate.m ├── bin2dec_zero.m └── huff.m ├── measurement.m ├── README.md └── Arith07.m /RCC/RCC/predict.m: -------------------------------------------------------------------------------- 1 | function rst=predict(u,l,d,r) 2 | 3 | rst=floor((u+l+d+r)/4); 4 | 5 | end -------------------------------------------------------------------------------- /Matrix.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/Matrix.m -------------------------------------------------------------------------------- /RDHCE.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/RDHCE.m -------------------------------------------------------------------------------- /decode.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/decode.m -------------------------------------------------------------------------------- /encode.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/encode.m -------------------------------------------------------------------------------- /PEE/scale.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/PEE/scale.m -------------------------------------------------------------------------------- /PEEtest.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/PEEtest.m -------------------------------------------------------------------------------- /PCQI/ref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/PCQI/ref.png -------------------------------------------------------------------------------- /PEE/PEEmain.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/PEE/PEEmain.m -------------------------------------------------------------------------------- /PEE/RevMat.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/PEE/RevMat.m -------------------------------------------------------------------------------- /IWT/IWTdebed.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/IWT/IWTdebed.m -------------------------------------------------------------------------------- /IWT/IWTembed.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/IWT/IWTembed.m -------------------------------------------------------------------------------- /IWT/lenagray.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/IWT/lenagray.tif -------------------------------------------------------------------------------- /PEE/AfterPEE.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/PEE/AfterPEE.bmp -------------------------------------------------------------------------------- /PEE/PEEdecode.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/PEE/PEEdecode.m -------------------------------------------------------------------------------- /PEE/prediction.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/PEE/prediction.m -------------------------------------------------------------------------------- /functions/psnr.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/functions/psnr.m -------------------------------------------------------------------------------- /functions/loadim.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/functions/loadim.m -------------------------------------------------------------------------------- /test_image/dip.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/test_image/dip.tif -------------------------------------------------------------------------------- /RCC/RCC/modifyDiffs.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/RCC/RCC/modifyDiffs.m -------------------------------------------------------------------------------- /functions/quantize.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/functions/quantize.m -------------------------------------------------------------------------------- /test_image/beans.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/test_image/beans.tif -------------------------------------------------------------------------------- /test_image/city.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/test_image/city.tif -------------------------------------------------------------------------------- /test_image/lena.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/test_image/lena.tif -------------------------------------------------------------------------------- /test_image/puppy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/test_image/puppy.jpg -------------------------------------------------------------------------------- /test_image/wood.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/test_image/wood.jpg -------------------------------------------------------------------------------- /arithmetic/ps_replace.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/arithmetic/ps_replace.m -------------------------------------------------------------------------------- /functions/similarity.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/functions/similarity.m -------------------------------------------------------------------------------- /test_image/einstein.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/test_image/einstein.tif -------------------------------------------------------------------------------- /test_image/lenagray.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/test_image/lenagray.tif -------------------------------------------------------------------------------- /PCQI/contrast_changed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/PCQI/contrast_changed.png -------------------------------------------------------------------------------- /RCC/RCC/Var.m: -------------------------------------------------------------------------------- 1 | function rst=Var(u,l,d,r) 2 | s=zeros(1,4); 3 | s(1)=abs(d-l);s(2)=abs(l-u); 4 | s(3)=abs(u-r);s(4)=abs(r-d); 5 | rst=var(s,1); 6 | end -------------------------------------------------------------------------------- /arithmetic/arithdecode.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/arithmetic/arithdecode.m -------------------------------------------------------------------------------- /arithmetic/arithencode.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/arithmetic/arithencode.m -------------------------------------------------------------------------------- /arithmetic/dec2bin_zero.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/arithmetic/dec2bin_zero.m -------------------------------------------------------------------------------- /test_image/photographer.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/test_image/photographer.tif -------------------------------------------------------------------------------- /PEE/test.m: -------------------------------------------------------------------------------- 1 | a=[1 2 3 4 5 6]; 2 | i=1; 3 | while i<=length(a) 4 | if a(i)<3 5 | a(i)=[]; 6 | i=i-1; 7 | end 8 | i=i+1; 9 | end -------------------------------------------------------------------------------- /RCC/RCC/utils/arith_decode.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/RCC/RCC/utils/arith_decode.mexw64 -------------------------------------------------------------------------------- /RCC/RCC/utils/arith_encode.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingqichao/Histogram-Transfer-Based-RDH-with-Contrast-Enhancement/HEAD/RCC/RCC/utils/arith_encode.mexw64 -------------------------------------------------------------------------------- /IWT/test.m: -------------------------------------------------------------------------------- 1 | Img=imread('lenagray.tif'); 2 | addpath 'C:\Users\yqc_s\Desktop\new'; 3 | [W,encode,auxlen,ImgOut]=IWTembed(Img); 4 | [Z,code,auxlen1]=IWTdebed(Img,ImgOut); 5 | -------------------------------------------------------------------------------- /functions/move.m: -------------------------------------------------------------------------------- 1 | function ImgOut=move(ImgIn,Origin,Revise) 2 | ImgOut=ImgIn; 3 | [r,c]=find(ImgIn==Origin); 4 | for i=1:length(r) 5 | ImgOut(r(i),c(i))=Revise; 6 | end -------------------------------------------------------------------------------- /functions/locationmap.m: -------------------------------------------------------------------------------- 1 | function LM=locationmap(ImgIn,ImgOut,i,j) 2 | [r,c]=find(ImgOut==j);LM=[]; 3 | for k=1:length(r) 4 | if ImgIn(r(k),c(k))==i 5 | LM=[LM 1]; 6 | else 7 | LM=[LM 0]; 8 | end 9 | end 10 | 11 | -------------------------------------------------------------------------------- /arithmetic/allocate.m: -------------------------------------------------------------------------------- 1 | function SYMLEN=allocate(len) 2 | slen=ceil(len/10);smod=mod((slen*10-len),10); 3 | SYMLEN=[]; 4 | SYMLEN(1:slen)=10; 5 | k=1; 6 | for i=1:smod 7 | SYMLEN(k)=SYMLEN(k)-1; 8 | k=k+1; 9 | if k>slen 10 | k=1; 11 | end 12 | end -------------------------------------------------------------------------------- /functions/H_of_X.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %%% Calculate H(X). 3 | %%% Inouts:H(1D Histogram of an image) 4 | %%% Outputs:EntrophyX 5 | %%% 2017.10.1 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | 8 | function EntrophyX=H_of_X(H) 9 | EntrophyX=cross_entropy(H',1); 10 | 11 | -------------------------------------------------------------------------------- /PCQI/demo.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%This is a demo for the usage of PCQI with default settings%%%%%%%%%%%%%%%%%% 2 | addpath 'C:\Users\yqc_s\Desktop\new'; 3 | 4 | im1=imread('lenagray.tif'); 5 | im2=imread('compare.bmp'); 6 | im3=imread('target.bmp'); 7 | im1=double(im1); 8 | im2=double(im2); 9 | im3=double(im3); 10 | [mpcqi(1),~]=PCQI(im1,im2); 11 | [mpcqi(2),~]=PCQI(im1,im3); 12 | -------------------------------------------------------------------------------- /functions/runlengthcoding.m: -------------------------------------------------------------------------------- 1 | function [RLC]=runlengthcoding(BW,bits) 2 | [r,c]=size(BW);RLC=[];zero=0; 3 | for i=1:r 4 | for j=1:c 5 | if abs(BW(i,j))==1 6 | RLC=[RLC dec2bin(zero,bits)-48]; 7 | zero=0; 8 | else 9 | if zero==2^bits-1%(5bits) 10 | zero=0;RLC=[RLC 1 1 1 1 1]; 11 | else 12 | zero=zero+1; 13 | end 14 | end 15 | end 16 | end -------------------------------------------------------------------------------- /functions/standard.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %%% Calculate similarity index. 3 | %%% Inputs:I,W 4 | %%% Outputs:RCE,REE,RMBE,RSS 5 | %%% 2017.10.1 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | 8 | function std=standard(I) 9 | std=0;[row,col]=size(I);I=double(I); 10 | Mean=sum(sum(I))/row/col; 11 | for i=1:row 12 | for j=1:col 13 | std=std+(I(i,j)-Mean)^2; 14 | end 15 | end 16 | std=sqrt(std/row/col); -------------------------------------------------------------------------------- /arithmetic/bin2dec_zero.m: -------------------------------------------------------------------------------- 1 | function dec=bin2dec_zero(bin) 2 | %======================================================================== 3 | % dec=bin2dec_zero(bin) 4 | % Input: a binary sequence that only contains 0 or 1 5 | % Output: the relevant decimal number 6 | % Author: William Ying 7 | %---------------------------------------------------------------------- 8 | dec=0; 9 | for i=1:length(bin) 10 | if bin(i)==1 11 | dec=dec+2^(-i); 12 | end 13 | end -------------------------------------------------------------------------------- /RCC/RCC/utils/Readme.txt: -------------------------------------------------------------------------------- 1 | 1, firstly goto the utils directory, run following commands inside Matlab (you need a c++ compiler installed): 2 | mex arith_encode.c 3 | mex arith_decode.c 4 | 2, Back to the RCC directory, and run testEmbed.m, after few seconds you'll see the results~ 5 | 6 | 7 | I tested it using Matlab R2012b. 8 | 9 | 10 | ************************************* 11 | the utils directory offers functions to do optimization problem and recursively embedding messages. -------------------------------------------------------------------------------- /IWT/IIWT.m: -------------------------------------------------------------------------------- 1 | function [I]=IIWT(V,H,D,A) 2 | [row,col]=size(V); 3 | I=zeros(2*row,2*col); 4 | for p=1:row 5 | for q=1:col 6 | I(2*p-1,2*q-1)=A(p,q)-floor(H(p,q)/2)-floor((V(p,q)-floor(D(p,q)/2))/2); 7 | I(2*p,2*q-1)=A(p,q)+floor((H(p,q)+1)/2)-floor((V(p,q)+floor((D(p,q)+1)/2))/2); 8 | I(2*p-1,2*q)=A(p,q)-floor(H(p,q)/2)+floor((V(p,q)-floor(D(p,q)/2)+1)/2); 9 | I(2*p,2*q)=A(p,q)+floor((H(p,q)+1)/2)+floor((V(p,q)+floor((D(p,q)+1)/2)+1)/2); 10 | end 11 | end -------------------------------------------------------------------------------- /RCC/RCC/embedding.m: -------------------------------------------------------------------------------- 1 | function [ bpp,psnr,embedded ] = embedding( img,bpp ) 2 | %EMBEDDING Summary of this function goes here 3 | % Detailed explanation goes here 4 | 5 | [waterMark,mesLen1] = imageEmbed(img,bpp,0); 6 | [waterMark,mesLen2] = imageEmbed(waterMark,bpp,1); 7 | 8 | origin = img(:); 9 | embedded = waterMark(:); 10 | psnr = 10*log10( 255*255*length(origin)/sum((embedded-origin).*(embedded-origin)) ); 11 | 12 | [m,n] = size(img); 13 | bpp = (mesLen1+mesLen2)/(m*n); 14 | 15 | 16 | end 17 | 18 | -------------------------------------------------------------------------------- /IWT/IWT.m: -------------------------------------------------------------------------------- 1 | function [V,H,D,A]=IWT(I) 2 | [row,col]=size(I); 3 | V=zeros(row/2,col/2);H=zeros(row/2,col/2);D=zeros(row/2,col/2);A=zeros(row/2,col/2); 4 | for p=1:row/2 5 | for q=1:col/2 6 | A(p,q)=floor((floor((I(2*p-1,2*q-1)+I(2*p-1,2*q))/2)+floor((I(2*p,2*q-1)+I(2*p,2*q))/2))/2); 7 | V(p,q)=floor((I(2*p-1,2*q)-I(2*p-1,2*q-1)+I(2*p,2*q)-I(2*p,2*q-1))/2); 8 | H(p,q)=floor((I(2*p,2*q-1)+I(2*p,2*q))/2)-floor((I(2*p-1,2*q-1)+I(2*p-1,2*q))/2); 9 | D(p,q)=I(2*p,2*q)-I(2*p,2*q-1)-I(2*p-1,2*q)+I(2*p-1,2*q-1); 10 | end 11 | end 12 | 13 | % [A,H,V,D]=dwt2(I,'bior3.7'); -------------------------------------------------------------------------------- /measurement.m: -------------------------------------------------------------------------------- 1 | function measurement(OriIm,ImgCmp) 2 | addpath 'C:\Users\yqc_s\Desktop\new\IWT'; 3 | addpath 'C:\Users\yqc_s\Desktop\new\arithmetic'; 4 | addpath 'C:\Users\yqc_s\Desktop\new\functions'; 5 | addpath 'C:\Users\yqc_s\Desktop\new\PCQI'; 6 | addpath 'C:\Users\yqc_s\Desktop\new\PEE'; 7 | % OriIm=loadim();ImgCmp=loadim(); 8 | [RCE,REE,RMBE]=similarity(OriIm,ImgCmp); 9 | [SSIM, ~] = ssim(OriIm,ImgCmp); 10 | % [PCQI, ~] = PCQI(double(OriIm),double(ImgCmp)); 11 | [PSNR,~]=psnr(OriIm,ImgCmp); 12 | disp(['RCE REE RMBE SSIM PSNR=' num2str(RCE) num2str(REE) num2str(RMBE) num2str(SSIM) num2str(PSNR)]); -------------------------------------------------------------------------------- /RCC/RCC/utils/nonCrossEdge.m: -------------------------------------------------------------------------------- 1 | function [Qxy,Qyx]=nonCrossEdge(Px,Py) 2 | 3 | m = length(Px); 4 | CPx = zeros(m+1,1); 5 | for i=1:m 6 | CPx(i+1)=CPx(i)+Px(i); 7 | end 8 | 9 | n = length(Py); 10 | CPy = zeros(n+1,1); 11 | for i=1:n 12 | CPy(i+1)=CPy(i)+Py(i); 13 | end 14 | 15 | Qxy = zeros(m,n); 16 | Qyx = zeros(m,n); 17 | for x=0:(m-1) 18 | for y=0:(n-1) 19 | jval = max(0,min(CPx(x+2),CPy(y+2))-max(CPx(x+1),CPy(y+1))); 20 | 21 | Qxy(x+1,y+1)= jval/(Px(x+1)+eps); 22 | Qyx(x+1,y+1)= jval/(Py(y+1)+eps); 23 | end 24 | end 25 | Qyx=Qyx'; 26 | 27 | end -------------------------------------------------------------------------------- /RCC/RCC/testEmbed.m: -------------------------------------------------------------------------------- 1 | close all;clc;clear; 2 | 3 | img = imread('lena.tif'); 4 | % check if is gray image 5 | [imh,imw,imc] = size(img); 6 | assert(imc==1); 7 | 8 | img = double(img); 9 | 10 | Zh_lena = zeros(50,2); 11 | ind = 0; 12 | for hr=0.11:0.1:1 % embedding rate 13 | [b,p,embedded] = embedding(img,hr); 14 | %as=double(embedded)-double(img(:)); 15 | disp([hr b p]); 16 | if b>0 17 | ind = ind+1; 18 | Zh_lena(ind,1) = b; 19 | Zh_lena(ind,2) = p; 20 | end 21 | end 22 | Zh_lena=Zh_lena(1:ind,:); 23 | 24 | 25 | figure; 26 | plot(Zh_lena(:,1),Zh_lena(:,2),'-r.');grid on; -------------------------------------------------------------------------------- /functions/cross_entropy.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %%% Calculate one row's H(Y|X).To calculate H(X|Y) use T' 3 | %%% Inouts:T(transfer matrix),row(row or column number) 4 | %%% Outputs:Entrophy(H(Y|X)) 5 | %%% 2017.10.1 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | 8 | function Entrophy=cross_entropy(T,row) 9 | Sum_row=sum(T,2);Entrophy=0; 10 | if Sum_row(row)==0 11 | return; 12 | else 13 | for k=1:256 14 | Trow=T(row,k)/Sum_row(row); 15 | if Trow~=0 16 | Entrophy=Entrophy-Sum_row(row)*Trow*log2(Trow); 17 | end 18 | end 19 | end -------------------------------------------------------------------------------- /functions/runlengthdecoding.m: -------------------------------------------------------------------------------- 1 | function [seq_rest,BW,casted]=runlengthdecoding(seq,row,col,bits) 2 | BW=zeros(row,col);N=row*col;runned=0;casted=0; 3 | while(runnedN 8 | break; 9 | else 10 | seq(1:bits)=[];casted=casted+bits; 11 | end 12 | end 13 | value=value+bin2dec(char(seq(1:bits)+48)); 14 | if runned+value>N 15 | break; 16 | else 17 | runned=runned+1+value; 18 | BW(runned)=1; 19 | seq(1:bits)=[];casted=casted+bits; 20 | end 21 | end 22 | BW=BW';seq_rest=seq; 23 | 24 | -------------------------------------------------------------------------------- /functions/outlook.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %%% Assume secret information bits are hidden randomly with the matrix 3 | %%% Inouts:T(transfer matrix),I(original image),quan(If the matrix is quantized in advance) 4 | %%% Outputs:X(Embedded image. 5 | %%% 2017.10.1 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | 8 | function [X]=outlook(T,I,quan) 9 | X=I; 10 | for i=1:256 11 | [r,c]=find(I==i-1);len=length(r); 12 | if sum(T(i,:),2)==0 13 | continue; 14 | else 15 | index=ones(len,1)*i;start=1; 16 | for j=1:256 17 | if T(i,j)>0 18 | index(start:round(start-1+T(i,j)*quan))=j; 19 | start=round(start+T(i,j)*quan); 20 | end 21 | end 22 | for k=1:len 23 | X(r(k),c(k))=index(k)-1; 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /RCC/RCC/utils/entropyEmbed.m: -------------------------------------------------------------------------------- 1 | function [ stego,mesLen ] = entropyEmbed( cover,mess,Qxy,xRange,yRange) 2 | %ENTROPYEMBED Summary of this function goes here 3 | % Detailed explanation goes here 4 | % cover: the cover signal 5 | % mess: the message to embed 6 | % Qxy: the conditional probability Py|x 7 | 8 | stego = cover; 9 | mesLen = 0; 10 | [mB,nB] = size(Qxy); 11 | for xi=1:mB 12 | pos = find(cover==xRange(xi)); 13 | xN = length(pos); 14 | if xN>0 15 | yi = find(abs(Qxy(xi,:)-1.0) < eps); 16 | if yi 17 | stego(pos) = yRange(yi)*ones(xN,1); 18 | else%if abs(sum(Qxy(xi,:))-1.0)<1e-8 19 | fq = repmat(Qxy(xi,:),xN,1); 20 | [symbols,mLen] = arith_decode(mess(mesLen+1:end),fq); 21 | stego(pos) = yRange(symbols); 22 | mesLen = mesLen+mLen; 23 | end 24 | end 25 | end 26 | 27 | 28 | 29 | end 30 | 31 | -------------------------------------------------------------------------------- /RCC/RCC/utils/compressOhead.m: -------------------------------------------------------------------------------- 1 | function [ compSeq ] = compressOhead( stego,cover,Qyx,xRange,yRange) 2 | %COMPRESSOHEAD Summary of this function goes here 3 | % Detailed explanation goes here 4 | 5 | [nB,mB]=size(Qyx); 6 | 7 | coverLen = length(cover); 8 | coverind = zeros(coverLen,1); 9 | for xi=1:mB 10 | coverind(cover==xRange(xi)) = xi; 11 | end 12 | cover = coverind; 13 | 14 | compSeq = zeros(coverLen,1); 15 | compLen = 0; 16 | for yi=1:nB 17 | pos = find(stego==yRange(yi)); 18 | if ~isempty(pos) && ~any(abs(Qyx(yi,:)-1.0)=0) 28 | pfor=pfor+1; 29 | difs(pfor)=I(i,j)-pre; 30 | xpos(pfor)=i; 31 | ypos(pfor)=j; 32 | preV(pfor)=pre; 33 | 34 | %end 35 | %end 36 | end 37 | end 38 | 39 | overLen = 4000; 40 | [mod_diffs,messLen,nLast] = modifyDiffs(difs(1:pfor-overLen),bpp); 41 | mod_diffs = [mod_diffs;difs(pfor-overLen+1:pfor)]; 42 | 43 | %% overflow and underflow handling 44 | pforInd = sub2ind(size(waterMark),xpos(1:pfor-overLen),ypos(1:pfor-overLen)); 45 | waterMark(pforInd) = preV(1:pfor-overLen)+mod_diffs(1:pfor-overLen); 46 | fLen = sum( waterMark(pforInd)<0 | waterMark(pforInd)>255 ); 47 | tmp = waterMark(pforInd); 48 | tmp(tmp<0)=0;tmp(tmp>255)=255; 49 | waterMark(pforInd)=tmp; 50 | 51 | allLen = sum(waterMark(pforInd)==0 | waterMark(pforInd)==255); 52 | op = fLen/(allLen+eps); 53 | headLen = -(op*log2(op+eps)+(1-op)*log2(1-op+eps)); 54 | headLen = ceil(allLen*headLen)+nLast+20; 55 | 56 | % lsb substitute 57 | oh = (rand(headLen,1)>0.5); 58 | tmp = preV(pfor-headLen+1:pfor); %oh = ~mod(tmp,2); 59 | tmp =2*floor(tmp/2)+oh; 60 | preV(pfor-headLen+1:pfor) = tmp; 61 | lsbInd = sub2ind(size(waterMark),xpos(pfor-headLen+1:pfor),ypos(pfor-headLen+1:pfor)); 62 | waterMark(lsbInd) = preV(pfor-headLen+1:pfor)+mod_diffs(pfor-headLen+1:pfor); 63 | 64 | if headLen>overLen 65 | disp('too large headLen'); 66 | disp(headLen-overLen); 67 | end 68 | messLen = messLen-headLen; 69 | 70 | end 71 | 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Histogram Transfer Based Reversible Data Hiding with Image Enhancement 2 | 3 | This repository offers some codes for embedding test of the following paper: 4 | 5 | Citation: 6 | > Q. Ying, Z. Qian, X. Zhang, and D. Ye, Reversible Data Hiding with Image Enhancement using Histogram Shifting, IEEE Access, 7(1): 46506-46521, 2019. 7 | 8 | PDF is available through IEEE Xplore: 9 | > https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=8682110 10 | 11 | Abstract: 12 | Traditional reversible data hiding (RDH) focuses on enlarging the embedding payloads while minimizing the distortion with a criterion of mean square error (MSE). Since imperceptibility can also be achieved via image processing, we propose a novel method of RDH with contrast enhancement (RDH-CE) using histogram shifting. Instead of minimizing the MSE, the proposed method generates marked images with good quality with the sense of structural similarity. The proposed method contains two parts: the baseline embedding and the extensive embedding. In the baseline part, we first merge the least significant bins to reserve spare bins and then embed additional data by a histogram shifting approach using arithmetic encoding. During histogram shifting, we propose to construct the transfer matrix by maximizing the entropy of the histogram. After embedding, the marked image containing additional data has a larger contrast than the original image. In the extensive embedding part, we further propose to concatenate the baseline embedding with an MSE-based embedding. On the recipient side, the additional data can be extracted exactly, and the original image can be recovered losslessly. Comparing with existing RDH-CE approaches, the proposed method can achieve a better embedding payload. 13 | 14 | Usages: 15 | It may takes several minutes for embedding and extracting (mainly depends on the size of input images). User needs to rewrite some pathnames in the files. 16 | Run encode.m and select host images in test_images. You can either randomly generate secret information (0-1 sequence with equal possibility), or you can compress secret images (or texts) into binary sequence as input. 17 | Run decode.m to extract secret information and get the lossless host image. 18 | 19 | 20 | Acknowledgment: 21 | Specially Thank to Professor Zhenxing Qian, Xinpeng Zhang from Fudan University for kindly offering guidance and help in this work! 22 | For more detailed information in RDH-CE, I may refer you to a well-known efficient data hiding scheme called "Reversible Data Hiding With Optimal Value Transfer", which is proposed by my professor Dr. Xinpeng Zhang from Fudan University. 23 | Citation: 24 | > Zhang X. Reversible data hiding with optimal value transfer[J]. IEEE Transactions on Multimedia, 2012, 15(2): 316-325. 25 | 26 | Link: 27 | > https://ieeexplore.ieee.org/document/6359955/ 28 | 29 | Contact me if you have any suggestion/comment or find any bug while using the codes, or new idea about RDH-CE or even applying deep neural network(DNN) on RDH (which seems to be impossible so far simply cuz no way can we strictly let the training loss equal to zero), via: 30 | Email: 31 | > shinydotcom@163.com. 32 | 33 | Wechat account: 34 | > acshu123 35 | 36 | Twitter account: 37 | >Shinylaa 38 | 39 | And I will quickly reply. :) 40 | -------------------------------------------------------------------------------- /PCQI/PCQI.m: -------------------------------------------------------------------------------- 1 | function [mpcqi, pcqi_map]= PCQI(img1, img2, window, L) 2 | %======================================================================== 3 | %PCQI Index, Version 1.0, Sep. 2015 4 | % 5 | %This is an implementation of the algorithm for calculating the patch-based contrast 6 | %quality index (PCQI) between two images. Please refer to the following paper: 7 | % 8 | %S. Wang, K. Ma, H. Yeganeh, Z. Wang and W. Lin, A Patch-Structure Representation 9 | %Method for Quality Assessment of Contrast Changed Images, IEEE Signal Processing 10 | %Letter, 2015. 11 | % 12 | %Kindly report any suggestions or corrections to sqwang1986@gmail.com 13 | % 14 | %---------------------------------------------------------------------- 15 | % 16 | %Input : (1) img1: the first image being compared 17 | % (2) img2: the second image being compared 18 | % (4) window: local window for statistics (see the above 19 | % reference). default widnow is Gaussian given by 20 | % window = fspecial('gaussian', 11, 1.5); 21 | % (5) L: dynamic range of the images. default: L = 256 22 | % 23 | %Output: (1) mpcqi : the mean PCQI index value between 2 images. 24 | % (2) pcqi_map: the PCQI map of the test image. 25 | %Default Usage: 26 | % Given 2 test images img1 and img2, whose dynamic range is 0-255 27 | % [mpcqi pcqi_map] = PCQI(img1, img2); 28 | % 29 | %Advanced Usage: 30 | % User defined parameters. For example 31 | % window = ones(8); 32 | % L = 100; 33 | % [mpcqi pcqi_map] = PCQI(img1, img2, window, L); 34 | %======================================================================== 35 | 36 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 37 | if (nargin < 2 || nargin > 4) 38 | mpcqi = -Inf; 39 | pcqi_map = -Inf; 40 | return; 41 | end 42 | 43 | if (size(img1) ~= size(img2)) 44 | mpcqi = -Inf; 45 | pcqi_map = -Inf; 46 | return; 47 | end 48 | 49 | [M N] = size(img1); 50 | 51 | if (nargin == 2) 52 | if ((M < 11) || (N < 11)) 53 | mpcqi = -Inf; 54 | pcqi_map = -Inf; 55 | return 56 | end 57 | window = fspecial('gaussian', 11, 1.5); % 58 | L = 256; % 59 | end 60 | 61 | if (nargin == 3) 62 | [H W] = size(window); 63 | if ((H*W) < 4 || (H > M) || (W > N)) 64 | mpcqi = -Inf; 65 | pcqi_map = -Inf; 66 | return 67 | end 68 | L = 255; 69 | end 70 | 71 | if (nargin == 4) 72 | [H W] = size(window); 73 | if ((H*W) < 4 || (H > M) || (W > N)) 74 | mpcqi = -Inf; 75 | pcqi_map = -Inf; 76 | return 77 | end 78 | end 79 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 80 | 81 | window = window/sum(sum(window)); 82 | 83 | mu1 = filter2(window, img1, 'valid'); 84 | mu2 = filter2(window, img2, 'valid'); 85 | mu1_sq = mu1.*mu1; 86 | mu2_sq = mu2.*mu2; 87 | mu1_mu2 = mu1.*mu2; 88 | sigma1_sq = filter2(window, img1.*img1, 'valid') - mu1_sq; 89 | sigma2_sq = filter2(window, img2.*img2, 'valid') - mu2_sq; 90 | sigma12 = filter2(window, img1.*img2, 'valid') - mu1_mu2; 91 | 92 | 93 | sigma1_sq = max(0, sigma1_sq); 94 | sigma2_sq = max(0, sigma2_sq); 95 | 96 | C=3; 97 | 98 | pcqi_map = (4/pi) *atan((sigma12 + C )./(sigma1_sq + C )); 99 | pcqi_map = pcqi_map .*((sigma12 + C) ./(sqrt(sigma1_sq).*sqrt(sigma2_sq) + C)); 100 | pcqi_map = pcqi_map .*exp(-abs(mu1-mu2)/L); 101 | 102 | mpcqi = mean2(pcqi_map); 103 | 104 | return 105 | 106 | 107 | -------------------------------------------------------------------------------- /RCC/RCC/utils/bi2de.m: -------------------------------------------------------------------------------- 1 | function d = bi2de(b, varargin) 2 | %BI2DE Convert binary vectors to decimal numbers. 3 | % D = BI2DE(B) converts a binary vector B to a decimal value D. When B is 4 | % a matrix, the conversion is performed row-wise and the output D is a 5 | % column vector of decimal values. The default orientation of the binary 6 | % input is Right-MSB; the first element in B represents the least 7 | % significant bit. 8 | % 9 | % In addition to the input matrix, two optional parameters can be given: 10 | % 11 | % D = BI2DE(...,P) converts a base P vector to a decimal value. 12 | % 13 | % D = BI2DE(...,MSBFLAG) uses MSBFLAG to determine the input orientation. 14 | % MSBFLAG has two possible values, 'right-msb' and 'left-msb'. Giving a 15 | % 'right-msb' MSBFLAG does not change the function's default behavior. 16 | % Giving a 'left-msb' MSBFLAG flips the input orientation such that the 17 | % MSB is on the left. 18 | % 19 | % Examples: 20 | % B = [0 0 1 1; 1 0 1 0]; 21 | % T = [0 1 1; 2 1 0]; 22 | % 23 | % D = bi2de(B) 24 | % E = bi2de(B,'left-msb') 25 | % F = bi2de(T,3) 26 | % 27 | % See also DE2BI. 28 | 29 | % Copyright 1996-2008 The MathWorks, Inc. 30 | % $Revision: 1.15.4.5 $ $Date: 2008/08/01 12:17:30 $ 31 | 32 | 33 | % Typical error checking. 34 | error(nargchk(1,3,nargin,'struct')); 35 | 36 | % --- Placeholder for the signature string. 37 | sigStr = ''; 38 | flag = ''; 39 | p = []; 40 | 41 | % Check the type of the input B 42 | if ~(isnumeric(b) || islogical(b)) 43 | error('comm:bi2de:InvalidInput','The binary input must be numeric or logical.'); 44 | end 45 | 46 | inType = class(b); 47 | b = double(b); % To allow non-doubles to work 48 | 49 | % --- Identify string and numeric arguments 50 | for i=1:length(varargin) 51 | if(i>1) 52 | sigStr(size(sigStr,2)+1) = '/'; 53 | end 54 | % --- Assign the string and numeric flags 55 | if(ischar(varargin{i})) 56 | sigStr(size(sigStr,2)+1) = 's'; 57 | elseif(isnumeric(varargin{i})) 58 | sigStr(size(sigStr,2)+1) = 'n'; 59 | else 60 | error('comm:bi2de:InvalidInputArg','Optional parameters must be string or numeric.'); 61 | end 62 | end 63 | 64 | % --- Identify parameter signitures and assign values to variables 65 | switch sigStr 66 | 67 | % --- bi2de(d) 68 | case '' 69 | 70 | % --- bi2de(d, p) 71 | case 'n' 72 | p = varargin{1}; 73 | 74 | % --- bi2de(d, flag) 75 | case 's' 76 | flag = varargin{1}; 77 | 78 | % --- bi2de(d, p, flag) 79 | case 'n/s' 80 | p = varargin{1}; 81 | flag = varargin{2}; 82 | 83 | % --- bi2de(d, flag, p) 84 | case 's/n' 85 | flag = varargin{1}; 86 | p = varargin{2}; 87 | 88 | % --- If the parameter list does not match one of these signatures. 89 | otherwise 90 | error('comm:bi2de:InvalidSeqArg','Syntax error.'); 91 | end 92 | 93 | if isempty(b) 94 | error('comm:bi2de:InputEmpty','Required parameter empty.'); 95 | end 96 | 97 | if max(max(b < 0)) || max(max(~isfinite(b))) || (~isreal(b)) || ... 98 | (max(max(floor(b) ~= b))) 99 | error('comm:bi2de:InvalidInput','Input must contain only finite real positive integers.'); 100 | end 101 | 102 | % Set up the base to convert from. 103 | if isempty(p) 104 | p = 2; 105 | elseif max(size(p)) > 1 106 | error('comm:bi2de:NonScalarBase','Source base must be a scalar.'); 107 | elseif (floor(p) ~= p) || (~isfinite(p)) || (~isreal(p)) 108 | error('comm:bi2de:InvalidBase','Source base must be a finite real integer.'); 109 | elseif p < 2 110 | error('comm:bi2de:BaseLessThan2','Source base must be greater than or equal to two.'); 111 | end 112 | 113 | if max(max(b)) > (p-1) 114 | error('comm:bi2de:InvalidInputElement','The elements of the matrix are larger than the base can represent.'); 115 | end 116 | 117 | n = size(b,2); 118 | 119 | % If a flag is specified to flip the input such that the MSB is to the left. 120 | if isempty(flag) 121 | flag = 'right-msb'; 122 | elseif ~(strcmp(flag, 'right-msb') || strcmp(flag, 'left-msb')) 123 | error('comm:bi2de:InvalidFlag','Invalid string flag.'); 124 | end 125 | 126 | if strcmp(flag, 'left-msb') 127 | 128 | b2 = b; 129 | b = b2(:,n:-1:1); 130 | 131 | end 132 | 133 | %%% The conversion 134 | max_length = 1024; 135 | pow2vector = p.^(0:1:(size(b,2)-1)); 136 | size_B = min(max_length,size(b,2)); 137 | d = b(:,1:size_B)*pow2vector(:,1:size_B).'; 138 | 139 | % handle the infs... 140 | idx = find(max(b(:,max_length+1:size(b,2)).') == 1); 141 | d(idx) = inf; 142 | 143 | % data type conversion 144 | if ~strcmp(inType, 'logical') 145 | d = feval(inType, d); 146 | end 147 | 148 | % [EOF] 149 | -------------------------------------------------------------------------------- /RCC/RCC/utils/minDistortionEmr.m: -------------------------------------------------------------------------------- 1 | function [ Py,Dav,exitfg,iters] = minDistortionEmr(Px,Dxy,Hy) 2 | % Miniminze average distortion between stego-signal and cover-signal 3 | % 4 | % Input: 5 | % Px : cover-signal probability distribution 6 | % Dxy : square error distortion matrix 7 | % Hy : expected stego-signal entropy 8 | % 9 | % Output: 10 | % Py : stego-signal probability distribution 11 | % Dav : corresponding minimized distortion value 12 | % exitfg : exit flag: 0-->success -1-->invalid input 1-->failed 13 | % iters : number of iterations 14 | %%******************************************************************** 15 | % 16 | % author: Xiaocheng Hu 17 | % college: University of Science and Technology of China 18 | % date: 9/2/2012 19 | % 20 | %%********************************************************************* 21 | 22 | [m,n] = size(Dxy); 23 | 24 | % input validation 25 | % 26 | if ( abs(sum(Px)-1.0) > 1e-8 ) || (Hy > log(n)) || (Hy < -sum(Px.*log(Px))) 27 | Pxy=zeros(m,n);Dav=0;exitfg=-1; 28 | disp('minDistortionEmr invalid input!'); 29 | return; 30 | end 31 | %} 32 | 33 | % 34 | MPx = Px(:,ones(n,1));%repmat(Px,1,n); 35 | Dxy = MPx.*Dxy; 36 | 37 | %parameters 38 | MAXITERS = 300; 39 | Tol = 1e-8; 40 | NTTol = 1e-8; 41 | MU = 20; 42 | Alpha = 0.01; 43 | Beta = 0.6; 44 | 45 | % initialize x0 46 | x = zeros(n+m+1,1);%+1.0; 47 | x(1:n) = log(1/n)+1.0; 48 | x(n+1:n+m) = abs(x(1))+0.01; 49 | x(n+m+1) = 1.0; 50 | 51 | % initialize t0 with least square 52 | Mfx = Dxy+repmat(x(n+1:n+m),1,n)+Px*(x(1:n)'); 53 | fx = [Mfx(:);x(n+m+1)]; 54 | lA = [exp(x(1:n)/x(n+m+1)-1);ones(m,1);sum(exp(x(1:n)/x(n+m+1)-1).*(x(n+m+1)-x(1:n)))/x(n+m+1)-Hy]; 55 | lb = [(sum(MPx./Mfx))';sum(1./Mfx,2);1/x(n+m+1)]; 56 | t = (lA'*lb)/(lA'*lA); 57 | t = ceil(t); 58 | %t=1; 59 | 60 | % 61 | for iters=1:MAXITERS 62 | % calculate function value and it's gratitude 63 | val=t*(x(n+m+1)*sum(exp(x(1:n)/x(n+m+1)-1))+sum(x(n+1:n+m))-Hy*x(n+m+1))-sum(log(fx)); 64 | grad=t*([exp(x(1:n)/x(n+m+1)-1);ones(m,1);sum(exp(x(1:n)/x(n+m+1)-1).*(x(n+m+1)-x(1:n)))/x(n+m+1)-Hy])-[(sum(MPx./Mfx))';sum(1./Mfx,2);1/x(n+m+1)]; 65 | 66 | 67 | %{ 68 | Hf0=[diag(exp(x(1:n)/x(n+m+1)-1)/x(n+m+1)),zeros(n,m),-exp(x(1:n)/x(n+m+1)-1).*x(1:n)/(x(n+m+1)^2); ... 69 | zeros(m,m+n+1); ... 70 | -(exp(x(1:n)/x(n+m+1)-1).*x(1:n)/(x(n+m+1)^2))',zeros(1,m),sum(exp(x(1:n)/x(n+m+1)-1).*(x(1:n).^2))/(x(n+m+1)^3)]; 71 | Hfx=[-diag(sum((MPx./Mfx).^2)) , -(MPx./(Mfx.^2))', zeros(n,1); ... 72 | -(MPx./(Mfx.^2)) , -diag(sum(1./(Mfx.^2),2)), zeros(m,1); ... 73 | zeros(1,n) , zeros(1,m) , -1/(x(n+m+1)^2)]; 74 | hess=t*Hf0-Hfx; 75 | Dx=-hess\grad; 76 | %} 77 | % Calculate Newton step, fast 78 | Dx=fast_linear_solver(t*exp(x(1:n)/x(n+m+1)-1)/x(n+m+1)+(sum((MPx./Mfx).^2))', ... 79 | t*[zeros(n,m),-exp(x(1:n)/x(n+m+1)-1).*x(1:n)/(x(n+m+1)^2)]+[(MPx./(Mfx.^2))',zeros(n,1)], ... 80 | t*[zeros(m,m),zeros(m,1);zeros(1,m),sum(exp(x(1:n)/x(n+m+1)-1).*(x(1:n).^2))/(x(n+m+1)^3)]+[diag(sum(1./(Mfx.^2),2)),zeros(m,1);zeros(1,m),1/(x(n+m+1)^2)], ... 81 | -grad); 82 | fprime=grad'*Dx; 83 | 84 | % Solved Centering step and update t 85 | if( (-fprime < NTTol)) 86 | gap=(m*n+1)/t; 87 | 88 | % stopping criterion 89 | if( gap < Tol ),break;end; 90 | 91 | % update t and continue the next Centering step 92 | t=MU*t; 93 | continue; 94 | end 95 | 96 | % Backtracking step 1, ensure the domain of fx 97 | step=1; 98 | DMf=repmat(Dx(n+1:n+m),1,n)+Px*(Dx(1:n)');Dff=[DMf(:);Dx(n+m+1)]; 99 | while any((fx+step*Dff)<=0) 100 | step=Beta*step; 101 | end 102 | 103 | newx = x+step*Dx; 104 | newfx = fx+step*Dff; 105 | % Backtracking step 2, decrease fx sufficiently 106 | % 107 | while ( (t*(newx(n+m+1)*sum(exp(newx(1:n)/newx(n+m+1)-1))+sum(newx(n+1:n+m))-Hy*newx(n+m+1))-sum(log(newfx))) > (val+Alpha*step*fprime) ) 108 | step=Beta*step; 109 | newx=x+step*Dx; 110 | newfx=fx+step*Dff; 111 | end 112 | %} 113 | 114 | % update variables 115 | x = newx; 116 | fx = newfx; 117 | Mfx = Mfx+step*DMf; 118 | 119 | 120 | end 121 | 122 | % Output 123 | Py = exp(x(1:n)/x(n+m+1)-1); 124 | Dav = -(x(n+m+1)*sum(exp(x(1:n)/x(n+m+1)-1))+sum(x(n+1:n+m))-Hy*x(n+m+1)); 125 | 126 | % check if success 127 | if( abs(sum(Py)-1.0) < 1e-8 ) 128 | exitfg=0; 129 | else 130 | exitfg=1; 131 | end 132 | fprintf('minDistortionEmr Iters: %d\t Distortion: %f\t Sum of Py: %f\n',iters,Dav,sum(Py)); 133 | 134 | %% Block elimination method to solve linear equations 135 | function [sx]=fast_linear_solver(A11,A12,A22,b) 136 | [sn,sm]=size(A12); 137 | b1=b(1:sn); 138 | b2=b(sn+1:sn+sm); 139 | 140 | invA11=1./A11; 141 | Tm=repmat(invA11',sm,1).*(A12'); 142 | S=A22-Tm*A12; 143 | bs=b2-Tm*b1; 144 | % check if S is positive definite 145 | % 146 | [L,p]=chol(S,'lower'); 147 | if (p > 0) 148 | sx=zeros(sn+sm,1); 149 | return; 150 | end 151 | 152 | zz=L\bs; 153 | x2=L'\zz; 154 | %} 155 | %topts.SYM=true;topts.POSDEF=true; 156 | %[x2,Rf]=linsolve(S,bs,topts); 157 | %x2=S\bs; 158 | x1=invA11.*(b1-A12*x2); 159 | sx=[x1;x2]; 160 | end 161 | 162 | end 163 | 164 | -------------------------------------------------------------------------------- /RCC/RCC/utils/arith_decode.c: -------------------------------------------------------------------------------- 1 | /* MEX ROUTINE FOR ARITHMETIC DECODING */ 2 | 3 | /* 4 | Matlab MEX routine for arithmetic coding, modified from the adaptive 5 | arithmetic coding software by R. M. Neal contained in the following 6 | reference: 7 | 8 | Witten, I. H., Neal, R. M., and Cleary, J. G. (1987) 9 | "Arithmetic coding for data compression", Communications 10 | of the ACM, vol. 30, no. 6 (June). 11 | 12 | This modified version of the arithmetic coding software allows 13 | frequencies to be passed for each symbol, rather than estimating them 14 | adaptively. 15 | 16 | Accepts a Nx1 array of bits, and an NxS array of symbol frequencies. 17 | Returns an Nx1 output array of symbols ranging from 1..S. 18 | 19 | Adapted to MEX format by Phil Sallee 6/19/00 20 | Modified for steganography embedding by Phil Sallee 6/03 21 | */ 22 | 23 | 24 | #include 25 | #include "math.h" 26 | 27 | 28 | /* SIZE OF ARITHMETIC CODE VALUES. */ 29 | #define code_value_bits 16 /* Number of bits in a code value */ 30 | #define max_freq 16383 31 | typedef long code_value; /* Type of an arithmetic code value */ 32 | #define top_value (((long)1< 3) 65 | mexErrMsgTxt("Too many output arguments"); 66 | 67 | maxip = mxGetM(prhs[0])*mxGetN(prhs[0]); 68 | if (mxGetM(prhs[0]) != 1 & mxGetN(prhs[0]) != 1) 69 | mexErrMsgTxt("Input bit array must be a vector"); 70 | 71 | numsymval = mxGetN(prhs[1]); 72 | numsym = mxGetM(prhs[1]); 73 | 74 | /* create output array */ 75 | plhs[0] = mxCreateDoubleMatrix(numsym,1,mxREAL); 76 | 77 | /* get pointers to arrays */ 78 | symarr = mxGetPr(plhs[0]); 79 | inarr = mxGetPr(prhs[0]); 80 | farr = mxGetPr(prhs[1]); 81 | 82 | /* input bits to fill the code value */ 83 | value = 0; 84 | for (i = 0; i1)) mexErrMsgTxt("bad input bit!\n"); 88 | value += (long) inarr[ip++]; 89 | } 90 | } 91 | 92 | /* initialize code range and bits_to_follow */ 93 | low = 0; 94 | high = top_value; 95 | 96 | /* allocate cumulative frequency array */ 97 | cf = mxMalloc((numsymval+1) * sizeof(long)); 98 | if (cf==NULL) mexErrMsgTxt("Couldn't allocate cumulative freq array"); 99 | 100 | /* decode symbols */ 101 | for (i=0; i numsymval) { 121 | printf("cf[0]=%d, cf[1]=%d, cf[2]=%d, cum=%d\n",cf[0],cf[1],cf[2],cum); 122 | mexErrMsgTxt("Internal error: bad symbol!\n"); 123 | } 124 | 125 | /* Narrow code range for this symbol */ 126 | high = low + (range*cf[symbol])/cfsum - 1; 127 | low = low + (range*cf[symbol-1])/cfsum; 128 | 129 | if (high < low) 130 | mexErrMsgTxt("Internal error: bad range!\n"); 131 | 132 | /* Loop to input bits */ 133 | for (;;) { 134 | if (high=half) { 138 | value -= half; 139 | low -= half; 140 | high -= half; 141 | br+=btf; btf=1; 142 | } 143 | else if (low>=first_qtr && high1) mexErrMsgTxt("bad input bit!\n"); 157 | value += inarr[ip++]; 158 | } 159 | else { 160 | lastbit = !lastbit; 161 | value += lastbit; 162 | } 163 | } 164 | 165 | symarr[i] = symbol; 166 | sd++; 167 | 168 | /* check for too many garbage bits */ 169 | if (br >= maxip) break; 170 | } 171 | 172 | /* return number of bits read that can be uniquely obtained 173 | from the symbols that were decoded regardless of any other 174 | symbols that may follow (necessary for steganographic use) */ 175 | if (nlhs > 1) { 176 | plhs[1] = mxCreateDoubleMatrix(1,1,mxREAL); 177 | p = mxGetPr(plhs[1]); 178 | *p = br; 179 | } 180 | 181 | /* return number of symbols decoded */ 182 | if (nlhs > 2) { 183 | plhs[2] = mxCreateDoubleMatrix(1,1,mxREAL); 184 | p = mxGetPr(plhs[2]); 185 | *p = sd; 186 | } 187 | 188 | mxFree(cf); 189 | } 190 | -------------------------------------------------------------------------------- /RCC/RCC/utils/de2bi.m: -------------------------------------------------------------------------------- 1 | function b = de2bi(varargin) 2 | %DE2BI Convert decimal numbers to binary numbers. 3 | % B = DE2BI(D) converts a nonnegative integer decimal vector D to a 4 | % binary matrix B. Each row of the binary matrix B corresponds to one 5 | % element of D. The default orientation of the binary output is 6 | % Right-MSB; the first element in B represents the lowest bit. 7 | % 8 | % In addition to the vector input, three optional parameters can be 9 | % given: 10 | % 11 | % B = DE2BI(...,N) uses N to define how many digits (columns) are output. 12 | % 13 | % B = DE2BI(...,N,P) uses P to define which base to convert the decimal 14 | % elements to. 15 | % 16 | % B = DE2BI(...,MSBFLAG) uses MSBFLAG to determine the output 17 | % orientation. MSBFLAG has two possible values, 'right-msb' and 18 | % 'left-msb'. Giving a 'right-msb' MSBFLAG does not change the 19 | % function's default behavior. Giving a 'left-msb' MSBFLAG flips the 20 | % output orientation to display the MSB to the left. 21 | % 22 | % Examples: 23 | % E = [12; 5]; 24 | % 25 | % A = de2bi(E) 26 | % B = de2bi(E,5) 27 | % C = de2bi(E,[],3) 28 | % D = de2bi(E,5,'left-msb') 29 | % 30 | % See also BI2DE. 31 | 32 | % Copyright 1996-2008 The MathWorks, Inc. 33 | % $Revision: 1.19.4.4 $ $Date: 2008/08/01 12:17:33 $ 34 | 35 | % Typical error checking. 36 | error(nargchk(1,4,nargin,'struct')); 37 | 38 | % --- Placeholder for the signature string. 39 | sigStr = ''; 40 | msbFlag = ''; 41 | p = []; 42 | n = []; 43 | 44 | % --- Identify string and numeric arguments 45 | for i=1:nargin 46 | if(i>1) 47 | sigStr(size(sigStr,2)+1) = '/'; 48 | end; 49 | % --- Assign the string and numeric flags 50 | if(ischar(varargin{i})) 51 | sigStr(size(sigStr,2)+1) = 's'; 52 | elseif(isnumeric(varargin{i})) 53 | sigStr(size(sigStr,2)+1) = 'n'; 54 | else 55 | error('comm:de2bi:InvalidArg','Only string and numeric arguments are accepted.'); 56 | end; 57 | end; 58 | 59 | % --- Identify parameter signitures and assign values to variables 60 | switch sigStr 61 | % --- de2bi(d) 62 | case 'n' 63 | d = varargin{1}; 64 | 65 | % --- de2bi(d, n) 66 | case 'n/n' 67 | d = varargin{1}; 68 | n = varargin{2}; 69 | 70 | % --- de2bi(d, msbFlag) 71 | case 'n/s' 72 | d = varargin{1}; 73 | msbFlag = varargin{2}; 74 | 75 | % --- de2bi(d, n, msbFlag) 76 | case 'n/n/s' 77 | d = varargin{1}; 78 | n = varargin{2}; 79 | msbFlag = varargin{3}; 80 | 81 | % --- de2bi(d, msbFlag, n) 82 | case 'n/s/n' 83 | d = varargin{1}; 84 | msbFlag = varargin{2}; 85 | n = varargin{3}; 86 | 87 | % --- de2bi(d, n, p) 88 | case 'n/n/n' 89 | d = varargin{1}; 90 | n = varargin{2}; 91 | p = varargin{3}; 92 | 93 | % --- de2bi(d, n, p, msbFlag) 94 | case 'n/n/n/s' 95 | d = varargin{1}; 96 | n = varargin{2}; 97 | p = varargin{3}; 98 | msbFlag = varargin{4}; 99 | 100 | % --- de2bi(d, n, msbFlag, p) 101 | case 'n/n/s/n' 102 | d = varargin{1}; 103 | n = varargin{2}; 104 | msbFlag = varargin{3}; 105 | p = varargin{4}; 106 | 107 | % --- de2bi(d, msbFlag, n, p) 108 | case 'n/s/n/n' 109 | d = varargin{1}; 110 | msbFlag = varargin{2}; 111 | n = varargin{3}; 112 | p = varargin{4}; 113 | 114 | % --- If the parameter list does not match one of these signatures. 115 | otherwise 116 | error('comm:de2bi:InvalidArgSeq','Syntax error.'); 117 | end; 118 | 119 | if isempty(d) 120 | error('comm:de2bi:NoInput','Required parameter empty.'); 121 | end 122 | 123 | inType = class(d); 124 | d = double(d(:)); 125 | len_d = length(d); 126 | 127 | if max(max(d < 0)) || max(max(~isfinite(d))) || (~isreal(d)) || (max(max(floor(d) ~= d))) 128 | error('comm:de2bi:InvalidInput','Input must contain only finite real positive integers.'); 129 | end 130 | 131 | % Assign the base to convert to. 132 | if isempty(p) 133 | p = 2; 134 | elseif max(size(p) ~= 1) 135 | error('comm:de2bi:NonScalarBase','Destination base must be scalar.'); 136 | elseif (~isfinite(p)) || (~isreal(p)) || (floor(p) ~= p) 137 | error('comm:de2bi:InvalidBase','Destination base must be a finite real integer.'); 138 | elseif p < 2 139 | error('comm:de2bi:BaseLessThan2','Cannot convert to a base of less than two.'); 140 | end; 141 | 142 | % Determine minimum length required. 143 | tmp = max(d); 144 | if tmp ~= 0 % Want base-p log of tmp. 145 | ntmp = floor( log(tmp) / log(p) ) + 1; 146 | else % Since you can't take log(0). 147 | ntmp = 1; 148 | end 149 | 150 | % This takes care of any round off error that occurs for really big inputs. 151 | if ~( (p^ntmp) > tmp ) 152 | ntmp = ntmp + 1; 153 | end 154 | 155 | % Assign number of columns in output matrix. 156 | if isempty(n) 157 | n = ntmp; 158 | elseif max(size(n) ~= 1) 159 | error('comm:de2bi:NonScalarN','Specified number of columns must be scalar.'); 160 | elseif (~isfinite(n)) || (~isreal(n)) || (floor(n) ~= n) 161 | error('comm:de2bi:IvalidN','Specified number of columns must be a finite real integer.'); 162 | elseif n < ntmp 163 | error('comm:de2bi:SmallN','Specified number of columns in output matrix is too small.'); 164 | end 165 | 166 | % Check if the string msbFlag is valid. 167 | if isempty(msbFlag) 168 | msbFlag = 'right-msb'; 169 | elseif ~(strcmp(msbFlag, 'right-msb') || strcmp(msbFlag, 'left-msb')) 170 | error('comm:de2bi:InvalidMsbFlag','Invalid string msbFlag.'); 171 | end 172 | 173 | % Initial value. 174 | b = zeros(len_d, n); 175 | 176 | % Perform conversion. 177 | %Vectorized conversion for P=2 case 178 | if(p==2) 179 | [f,e]=log2(max(d)); % How many digits do we need to represent the numbers? 180 | b=rem(floor(d*pow2(1-max(n,e):0)),p); 181 | if strcmp(msbFlag, 'right-msb') 182 | b = fliplr(b); 183 | end; 184 | else 185 | for i = 1 : len_d % Cycle through each element of the input vector/matrix. 186 | j = 1; 187 | tmp = d(i); 188 | while (j <= n) && (tmp > 0) % Cycle through each digit. 189 | b(i, j) = rem(tmp, p); % Determine current digit. 190 | tmp = floor(tmp/p); 191 | j = j + 1; 192 | end; 193 | end; 194 | % If a msbFlag is specified to flip the output such that the MSB is to the left. 195 | if strcmp(msbFlag, 'left-msb') 196 | b2 = b; 197 | b = b2(:,n:-1:1); 198 | end; 199 | end; 200 | 201 | b = feval(inType, b); % data type conversion 202 | 203 | % [EOF] 204 | -------------------------------------------------------------------------------- /RCC/RCC/utils/arith_encode.c: -------------------------------------------------------------------------------- 1 | /* MEX ROUTINE FOR ARITHMETIC ENCODING */ 2 | 3 | /* 4 | Matlab MEX routine for arithmetic coding, modified from the adaptive 5 | arithmetic coding software by R. M. Neal contained in the following 6 | reference: 7 | 8 | Witten, I. H., Neal, R. M., and Cleary, J. G. (1987) 9 | "Arithmetic coding for data compression", Communications 10 | of the ACM, vol. 30, no. 6 (June). 11 | 12 | This modified version of the arithmetic coding software allows 13 | frequencies to be passed for each symbol, rather than estimating them 14 | adaptively. 15 | 16 | Accepts a Nx1 array of symbols 1..S, and an NxS array of 17 | symbol frequencies. Returns an Nx1 output array of bits. 18 | 19 | Adapted to MEX format by Phil Sallee 6/19/00 20 | Modified for steganography decoding by Phil Sallee 6/03 21 | */ 22 | 23 | 24 | #include 25 | #include "math.h" 26 | 27 | 28 | /* SIZE OF ARITHMETIC CODE VALUES. */ 29 | #define code_value_bits 16 /* Number of bits in a code value */ 30 | #define max_freq 16383 31 | typedef long code_value; /* Type of an arithmetic code value */ 32 | #define top_value (((long)1< 1) 60 | mexErrMsgTxt("Too many output arguments"); 61 | 62 | if (mxGetN(prhs[0]) != 1) 63 | mexErrMsgTxt("Input symbol array must be a column vector"); 64 | 65 | numsymval = mxGetN(prhs[1]); 66 | numsym = mxGetM(prhs[0]); 67 | 68 | if (mxGetM(prhs[1]) != numsym) 69 | mexErrMsgTxt("Frequency array must have same num of rows as symbol array"); 70 | 71 | /* allocate extra large buffer to hold output */ 72 | maxop = numsym * numsymval + 100; 73 | outbuf = mxCalloc(maxop, sizeof(int)); 74 | 75 | /* get pointers to arrays */ 76 | symarr = mxGetPr(prhs[0]); 77 | farr = mxGetPr(prhs[1]); 78 | 79 | /* allocate cumulative frequency array */ 80 | cf = mxMalloc((numsymval+1) * sizeof(long)); 81 | if (cf==NULL) mexErrMsgTxt("Couldn't allocate cumulative freq array"); 82 | 83 | /* start encoding, initialize code range and bits_to_follow */ 84 | low = 0; 85 | high = top_value; 86 | bits_to_follow = 0; 87 | 88 | /* encode symbols */ 89 | for (i=0; i numsymval)) 108 | mexErrMsgTxt("Symbol out of range\n"); 109 | 110 | if (cf[symbol-1] == cf[symbol]) 111 | mexErrMsgTxt("Can't encode symbol with zero frequency\n"); 112 | 113 | /* Narrow code range for this symbol */ 114 | range = (long)(high-low)+1; 115 | high = low + (range*cf[symbol])/cfsum - 1; 116 | low = low + (range*cf[symbol-1])/cfsum; 117 | 118 | /* Loop to output bits */ 119 | for (;;) { 120 | 121 | if (op + bits_to_follow > maxop - 4) { 122 | maxop = maxop * 2; 123 | printf("reallocating memory for %d ints\n",maxop); 124 | tmpptr = mxRealloc(outbuf, maxop * sizeof(int)); 125 | if (tmpptr == NULL) mexErrMsgTxt("Can't reallocate memory"); 126 | else outbuf = tmpptr; 127 | } 128 | 129 | if (high 0) { 132 | outbuf[op++] = 1; 133 | bits_to_follow -= 1; 134 | } 135 | } 136 | else if (low>=half) { /* Output 1 if in high half.*/ 137 | outbuf[op++] = 1; 138 | while (bits_to_follow > 0) { 139 | outbuf[op++] = 0; 140 | bits_to_follow -= 1; 141 | } 142 | low -= half; 143 | high -= half; /* Subtract offset to top. */ 144 | } 145 | else if (low>=first_qtr /* Output an opposite bit */ 146 | && high 0) { 168 | outbuf[op++] = 1; 169 | bits_to_follow -= 1; 170 | } 171 | } 172 | else { 173 | outbuf[op++] = 1; 174 | while (bits_to_follow > 0) { 175 | outbuf[op++] = 0; 176 | bits_to_follow -= 1; 177 | } 178 | } 179 | */ 180 | 181 | /* create new output array of correct size and fill it */ 182 | plhs[0] = mxCreateDoubleMatrix(op,1,mxREAL); 183 | outarr = mxGetPr(plhs[0]); 184 | for (i=0; i 5) 79 | ssim_index = -Inf; 80 | ssim_map = -Inf; 81 | return; 82 | end 83 | 84 | if (size(img1) ~= size(img2)) 85 | ssim_index = -Inf; 86 | ssim_map = -Inf; 87 | return; 88 | end 89 | 90 | [M N] = size(img1); 91 | 92 | if (nargin == 2) 93 | if ((M < 11) | (N < 11)) 94 | ssim_index = -Inf; 95 | ssim_map = -Inf; 96 | return 97 | end 98 | window = fspecial('gaussian', 11, 1.5); % 99 | K(1) = 0.01; % default settings 100 | K(2) = 0.03; % 101 | L = 255; % 102 | end 103 | 104 | if (nargin == 3) 105 | if ((M < 11) | (N < 11)) 106 | ssim_index = -Inf; 107 | ssim_map = -Inf; 108 | return 109 | end 110 | window = fspecial('gaussian', 11, 1.5); 111 | L = 255; 112 | if (length(K) == 2) 113 | if (K(1) < 0 | K(2) < 0) 114 | ssim_index = -Inf; 115 | ssim_map = -Inf; 116 | return; 117 | end 118 | else 119 | ssim_index = -Inf; 120 | ssim_map = -Inf; 121 | return; 122 | end 123 | end 124 | 125 | if (nargin == 4) 126 | [H W] = size(window); 127 | if ((H*W) < 4 | (H > M) | (W > N)) 128 | ssim_index = -Inf; 129 | ssim_map = -Inf; 130 | return 131 | end 132 | L = 255; 133 | if (length(K) == 2) 134 | if (K(1) < 0 | K(2) < 0) 135 | ssim_index = -Inf; 136 | ssim_map = -Inf; 137 | return; 138 | end 139 | else 140 | ssim_index = -Inf; 141 | ssim_map = -Inf; 142 | return; 143 | end 144 | end 145 | 146 | if (nargin == 5) 147 | [H W] = size(window); 148 | if ((H*W) < 4 | (H > M) | (W > N)) 149 | ssim_index = -Inf; 150 | ssim_map = -Inf; 151 | return 152 | end 153 | if (length(K) == 2) 154 | if (K(1) < 0 | K(2) < 0) 155 | ssim_index = -Inf; 156 | ssim_map = -Inf; 157 | return; 158 | end 159 | else 160 | ssim_index = -Inf; 161 | ssim_map = -Inf; 162 | return; 163 | end 164 | end 165 | 166 | 167 | img1 = double(img1); 168 | img2 = double(img2); 169 | 170 | % automatic downsampling 171 | f = max(1,round(min(M,N)/256)); 172 | %downsampling by f 173 | %use a simple low-pass filter 174 | if(f>1) 175 | lpf = ones(f,f); 176 | lpf = lpf/sum(lpf(:)); 177 | img1 = imfilter(img1,lpf,'symmetric','same'); 178 | img2 = imfilter(img2,lpf,'symmetric','same'); 179 | 180 | img1 = img1(1:f:end,1:f:end); 181 | img2 = img2(1:f:end,1:f:end); 182 | end 183 | 184 | C1 = (K(1)*L)^2; 185 | C2 = (K(2)*L)^2; 186 | window = window/sum(sum(window)); 187 | 188 | mu1 = filter2(window, img1, 'valid'); 189 | mu2 = filter2(window, img2, 'valid'); 190 | mu1_sq = mu1.*mu1; 191 | mu2_sq = mu2.*mu2; 192 | mu1_mu2 = mu1.*mu2; 193 | sigma1_sq = filter2(window, img1.*img1, 'valid') - mu1_sq; 194 | sigma2_sq = filter2(window, img2.*img2, 'valid') - mu2_sq; 195 | sigma12 = filter2(window, img1.*img2, 'valid') - mu1_mu2; 196 | 197 | if (C1 > 0 & C2 > 0) 198 | ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2)); 199 | else 200 | numerator1 = 2*mu1_mu2 + C1; 201 | numerator2 = 2*sigma12 + C2; 202 | denominator1 = mu1_sq + mu2_sq + C1; 203 | denominator2 = sigma1_sq + sigma2_sq + C2; 204 | ssim_map = ones(size(mu1)); 205 | index = (denominator1.*denominator2 > 0); 206 | ssim_map(index) = (numerator1(index).*numerator2(index))./(denominator1(index).*denominator2(index)); 207 | index = (denominator1 ~= 0) & (denominator2 == 0); 208 | ssim_map(index) = numerator1(index)./denominator1(index); 209 | end 210 | 211 | mssim = mean2(ssim_map); 212 | 213 | return -------------------------------------------------------------------------------- /Arith07.m: -------------------------------------------------------------------------------- 1 | function varargout = Arith07(xC) 2 | % Arith07 Arithmetic encoder or decoder 3 | % Vectors of integers are arithmetic encoded, 4 | % these vectors are collected in a cell array, xC. 5 | % If first argument is a cell array the function do encoding, 6 | % else decoding is done. 7 | % 8 | % [y, Res] = Arith07(xC); % encoding 9 | % y = Arith07(xC); % encoding 10 | % xC = Arith07(y); % decoding 11 | % ------------------------------------------------------------------ 12 | % Arguments: 13 | % y a column vector of non-negative integers (bytes) representing 14 | % the code, 0 <= y(i) <= 255. 15 | % Res a matrix that sum up the results, size is (NumOfX+1)x4 16 | % one line for each of the input sequences, the columns are 17 | % Res(:,1) - number of elements in the sequence 18 | % Res(:,2) - unused (=0) 19 | % Res(:,3) - bits needed to code the sequence 20 | % Res(:,4) - bit rate for the sequence, Res(:,3)/Res(:,1) 21 | % Then the last line is total (which include bits needed to store NumOfX) 22 | % xC a cell array of column vectors of integers representing the 23 | % symbol sequences. (should not be to large integers) 24 | % If only one sequence is to be coded, we must make the cell array 25 | % like: xC=cell(2,1); xC{1}=x; % where x is the sequence 26 | % ------------------------------------------------------------------ 27 | % Note: this routine is extremely slow since it is all Matlab code 28 | 29 | % SOME NOTES ON THE FUNCTION 30 | % This function is almost like Arith06, but some important changes have 31 | % been done. Arith06 is buildt almost like Huff06, but this close connection 32 | % is removed in Arith07. This imply that to understand the way Arith06 33 | % works you should read the dokumentation for Huff06 and especially the 34 | % article on Recursive Huffman Coding. To understand how Arith07 works it is 35 | % only confusing to read about the recursive Huffman coder, Huff06. 36 | % 37 | % Arith07 code each of the input sequences in xC in sequence, the 38 | % method used for each sequence depends on what kind (xType) the 39 | % sequence is. We have 40 | % xType Explanation 41 | % 0 Empty sequence (L=0) 42 | % 1 Only one symbol (L=1) and x>1 43 | % 9 Only one symbol (L=1) and x=0/1 44 | % 11 Only one symbol (L=1) and x<0 45 | % 2 all symbols are equal, L>1, x(1)=x(2)=...=x(L)>1 46 | % 8 all symbols are equal, L>1, x(1)=x(2)=...=x(L)=0/1 47 | % 10 all symbols are equal, L>1, x(1)=x(2)=...=x(L)<0 48 | % 3 non-negative integers, 0<=x(l)<=1000 49 | % 4 not to large integers, -1000<=x(l)<=1000 50 | % 5 large non-negative integers possible, 0<=x(l) 51 | % 6 also possible with large negative numbers 52 | % 7 A binary sequence, x(l)=0/1. 53 | % Many functions are defined in this m-file: 54 | % PutBit, GetBit read and write bit from/to bitstream 55 | % PutABit, GetABit Arithmetic encoding of a bit, P{0}=P{1}=0.5 56 | % PutVLIC, GetVLIC Variable Length Integer Code 57 | % PutS(x,S,C), GetS(S,C) A symbol x, which is in S, is aritmetic coded 58 | % according to the counts given by C. 59 | % Ex: A binary variable with the givene probabilities 60 | % P{0}=0.8 and P{1}=0.2, PutS(x,[0,1],[4,1]). 61 | % PutN(x,N), GetN(N) Arithmetic coding of a number x in range 0<=x<=N where 62 | % we assume equal probability, P{0}=P{1}=...=P{N}=1/(N+1) 63 | 64 | %---------------------------------------------------------------------- 65 | % Copyright (c) 1999-2001. Karl Skretting. All rights reserved. 66 | % Hogskolen in Stavanger (Stavanger University), Signal Processing Group 67 | % Mail: karl.skretting@tn.his.no Homepage: http://www.ux.his.no/~karlsk/ 68 | % 69 | % HISTORY: 70 | % Ver. 1.0 19.05.2001 KS: Function made (based on Arith06 and Huff06) 71 | %---------------------------------------------------------------------- 72 | 73 | % these global variables are used to read from or write to the compressed sequence 74 | global y Byte BitPos 75 | % and these are used by the subfunctions for arithmetic coding 76 | global high low range ub hc lc sc K code 77 | 78 | Mfile='Arith07'; 79 | K=24; % number of bits to use in integers (4 <= K <= 24) 80 | Display=1; % display progress and/or results 81 | 82 | % check input and output arguments, and assign values to arguments 83 | if (nargin < 1); 84 | error([Mfile,': function must have input arguments, see help.']); 85 | end 86 | if (nargout < 1); 87 | error([Mfile,': function must have output arguments, see help.']); 88 | end 89 | 90 | if (~iscell(xC)) 91 | Encode=0;Decode=1; 92 | y=xC(:); % first argument is y 93 | y=[y;0;0;0;0]; % add some zeros to always have bits available 94 | else 95 | Encode=1;Decode=0; 96 | NumOfX = length(xC); 97 | end 98 | 99 | Byte=0;BitPos=1; % ready to read/write into first position 100 | low=0;high=2^K-1;ub=0; % initialize the coder 101 | code=0; 102 | % we just select some probabilities which we belive will work quite well 103 | TypeS=[ 3, 4, 5, 7, 6, 1, 9, 11, 2, 8, 10, 0]; 104 | TypeC=[100, 50, 50, 50, 20, 10, 10, 10, 4, 4, 2, 1]; 105 | 106 | if Encode 107 | Res=zeros(NumOfX,4); 108 | % initalize the global variables 109 | y=zeros(10,1); % put some zeros into y initially 110 | % start encoding, first write VLIC to give number of sequences 111 | PutVLIC(NumOfX); 112 | % now encode each sequence continuously 113 | Ltot=0; 114 | for num=1:NumOfX 115 | x=xC{num}; 116 | x=full(x(:)); % make sure x is a non-sparse column vector 117 | L=length(x); 118 | Ltot=Ltot+L; 119 | y=[y(1:Byte);zeros(50+2*L,1)]; % make more space available in y 120 | StartPos=Byte*8-BitPos+ub; % used for counting bits 121 | % find what kind of sequenqe we have, save this in xType 122 | if (L==0) 123 | xType=0; 124 | elseif L==1 125 | if (x==0) | (x==1) % and it is 0/1 126 | xType=9; 127 | elseif (x>1) % and it is not 0/1 (and positive) 128 | xType=1; 129 | else % and it is not 0/1 (and negative) 130 | xType=11; 131 | end 132 | else 133 | % now find some more info about x 134 | maxx=max(x); 135 | minx=min(x); 136 | rangex=maxx-minx+1; 137 | if (rangex==1) % only one symbol 138 | if (maxx==0) | (maxx==1) % and it is 0/1 139 | xType=8; 140 | elseif (maxx>1) % and it is not 0/1 (and positive) 141 | xType=2; 142 | else % and it is not 0/1 (and negative) 143 | xType=10; 144 | end 145 | elseif (minx == 0) & (maxx == 1) % a binary sequence 146 | xType=7; 147 | elseif (minx >= 0) & (maxx <= 1000) 148 | xType=3; 149 | elseif (minx >= 0) 150 | xType=5; 151 | elseif (minx >= -1000) & (maxx <= 1000) 152 | xType=4; 153 | else 154 | xType=6; 155 | end 156 | end % if (L==0) 157 | if Display >= 2 158 | disp([Mfile,': sequence ',int2str(num),' has xType=',int2str(xType)]); 159 | end 160 | % 161 | if sum(xType==[4,6]) % negative values are present 162 | I=find(x); % non-zero entries in x 163 | Sg=(sign(x(I))+1)/2; % the signs will be needed later, 0/1 164 | x=abs(x); 165 | end 166 | if sum(xType==[5,6]) % we take the logarithms of the values 167 | I=find(x); % non-zero entries in x 168 | xa=x; % additional bits 169 | x(I)=floor(log2(x(I))); 170 | xa(I)=xa(I)-2.^x(I); 171 | x(I)=x(I)+1; 172 | end 173 | % now do the coding of this sequence 174 | PutS(xType,TypeS,TypeC); 175 | if (xType==1) % one symbol and x=x(1)>1 176 | PutVLIC(x-2); 177 | elseif (xType==2) % L>1 but only one symbol, x(1)=x(2)=...=x(L)>1 178 | PutVLIC(L-2); 179 | PutVLIC(x(1)-2); 180 | elseif sum(xType==[3,4,5,6]) % now 'normalized' sequences: 0 <= x(i) <= 1000 181 | PutVLIC(L-2); 182 | M=max(x); 183 | PutN(M,1000); % some bits for M 184 | % initialize model 185 | T=[ones(M+2,1);0]; 186 | Tu=flipud((-1:(M+1))'); % (-1) since ESC never is used in Tu context 187 | % and code the symbols in the sequence x 188 | for l=1:L 189 | sc=T(1); 190 | m=x(l); 191 | hc=T(m+1);lc=T(m+2); 192 | if hc==lc % unused symbol, code ESC symbol first 193 | hc=T(M+2);lc=T(M+3); 194 | EncodeSymbol; % code escape with T table 195 | sc=Tu(1);hc=Tu(m+1);lc=Tu(m+2); % symbol with Tu table 196 | Tu(1:(m+1))=Tu(1:(m+1))-1; % update Tu table 197 | end 198 | EncodeSymbol; % code actual symbol with T table (or Tu table) 199 | % update T table, MUST be identical in Encode and Decode 200 | % this avoid very large values in T even if sequence is very long 201 | T(1:(m+1))=T(1:(m+1))+1; 202 | if (rem(l,5000)==0) 203 | dT=T(1:(M+2))-T(2:(M+3)); 204 | dT=floor(dT*7/8+1/8); 205 | for m=(M+2):(-1):1; T(m)=T(m+1)+dT(m); end; 206 | end 207 | end % for l=1:L 208 | % this end the "elseif sum(xType==[3,4,5,6])"-clause 209 | elseif (xType==7) % L>1 and 0 <= x(i) <= 1 210 | PutVLIC(L-2); 211 | EncodeBin(x,L); % code this sequence a special way 212 | elseif (xType==8) % L>1 and 0 <= x(1)=x(2)=...=x(L) <= 1 213 | PutVLIC(L-2); 214 | PutABit(x(1)); 215 | elseif (xType==9) % L=1 and 0 <= x(1) <= 1 216 | PutABit(x(1)); 217 | elseif (xType==10) % L>1 and x(1)=x(2)=...=x(L) <= -1 218 | PutVLIC(L-2); 219 | PutVLIC(-1-x(1)); 220 | elseif (xType==11) % L=1 and x(1) <= -1 221 | PutVLIC(-1-x); 222 | end % if (xType==1) 223 | % additional information should be coded as well 224 | if 0 % first the way it is not done any more 225 | if sum(xType==[4,6]) % sign must be stored 226 | for i=1:length(Sg); PutABit(Sg(i)); end; 227 | end 228 | if sum(xType==[5,6]) % additional bits must be stored 229 | for i=1:L 230 | for ii=(x(i)-1):(-1):1 231 | PutABit(bitget(xa(i),ii)); 232 | end 233 | end 234 | end 235 | else % this is how we do it 236 | if sum(xType==[4,6]) % sign must be stored 237 | EncodeBin(Sg,length(I)); % since length(I)=length(Sg) 238 | end 239 | if sum(xType==[5,6]) % additional bits must be stored 240 | b=zeros(sum(x)-length(I),1); % number of additional bits 241 | bi=0; 242 | for i=1:L 243 | for ii=(x(i)-1):(-1):1 244 | bi=bi+1; 245 | b(bi)=bitget(xa(i),ii); 246 | end 247 | end 248 | if (bi~=(sum(x)-length(I))) 249 | error([Mfile,': logical error, bi~=(sum(x)-length(I)).']); 250 | end 251 | EncodeBin(b,bi); % since bi=(sum(x)-length(I)) 252 | end 253 | end 254 | % 255 | EndPos=Byte*8-BitPos+ub; % used for counting bits 256 | bits=EndPos-StartPos; 257 | Res(num,1)=L; 258 | Res(num,2)=0; 259 | Res(num,3)=bits; 260 | if L>0; Res(num,4)=bits/L; else Res(num,4)=bits; end; 261 | % if Display 262 | % disp([Mfile,': Sequence ',int2str(num),' of ',int2str(L),' symbols ',... 263 | % 'encoded using ',int2str(bits),' bits.']); 264 | % end 265 | end % for num=1:NumOfX 266 | % flush the arithmetic coder 267 | PutBit(bitget(low,K-1)); 268 | ub=ub+1; 269 | while ub>0 270 | PutBit(~bitget(low,K-1)); 271 | ub=ub-1; 272 | end 273 | % flush is finished 274 | y=y(1:Byte); 275 | varargout(1) = {y}; 276 | if (nargout >= 2) 277 | % now calculate results for the total 278 | Res(NumOfX+1,1)=Ltot; 279 | Res(NumOfX+1,2)=0; 280 | Res(NumOfX+1,3)=Byte*8; 281 | if (Ltot>0); Res(NumOfX+1,4)=Byte*8/Ltot; else Res(NumOfX+1,4)=Byte*8; end; 282 | varargout(2) = {Res}; 283 | end 284 | end % if Encode 285 | 286 | if Decode 287 | for k=1:K 288 | code=code*2; 289 | code=code+GetBit; % read bits into code 290 | end 291 | NumOfX=GetVLIC; % first read number of sequences 292 | xC=cell(NumOfX,1); 293 | for num=1:NumOfX 294 | % find what kind of sequenqe we have, xType, stored first in sequence 295 | xType=GetS(TypeS,TypeC); 296 | % now decode the different kind of sequences, each the way it was stored 297 | if (xType==0) % empty sequence, no more symbols coded 298 | x=[]; 299 | elseif (xType==1) % one symbol and x=x(1)>1 300 | x=GetVLIC+2; 301 | elseif (xType==2) % L>1 but only one symbol, x(1)=x(2)=...=x(L)>1 302 | L=GetVLIC+2; 303 | x=ones(L,1)*(GetVLIC+2); 304 | elseif sum(xType==[3,4,5,6]) % now 'normalized' sequences: 0 <= x(i) <= 1000 305 | L=GetVLIC+2; 306 | x=zeros(L,1); 307 | M=GetN(1000); % M is max(x) 308 | % initialize model 309 | T=[ones(M+2,1);0]; 310 | Tu=flipud((-1:(M+1))'); % (-1) since ESC never is used in Tu context 311 | % and decode the symbols in the sequence x 312 | for l=1:L 313 | sc=T(1); 314 | range=high-low+1; 315 | count=floor(( (code-low+1)*sc-1 )/range); 316 | m=2; while (T(m)>count); m=m+1; end; 317 | hc=T(m-1);lc=T(m);m=m-2; 318 | RemoveSymbol; 319 | if (m>M) % decoded ESC symbol, find symbol from Tu table 320 | sc=Tu(1);range=high-low+1; 321 | count=floor(( (code-low+1)*sc-1 )/range); 322 | m=2; while (Tu(m)>count); m=m+1; end; 323 | hc=Tu(m-1);lc=Tu(m);m=m-2; 324 | RemoveSymbol; 325 | Tu(1:(m+1))=Tu(1:(m+1))-1; % update Tu table 326 | end 327 | x(l)=m; 328 | % update T table, MUST be identical in Encode and Decode 329 | % this avoid very large values in T even if sequence is very long 330 | T(1:(m+1))=T(1:(m+1))+1; 331 | if (rem(l,5000)==0) 332 | dT=T(1:(M+2))-T(2:(M+3)); 333 | dT=floor(dT*7/8+1/8); 334 | for m=(M+2):(-1):1; T(m)=T(m+1)+dT(m); end; 335 | end 336 | end % for l=1:L 337 | % this end the "elseif sum(xType==[3,4,5,6])"-clause 338 | elseif (xType==7) % L>1 and 0 <= x(i) <= 1 339 | L=GetVLIC+2; 340 | x=DecodeBin(L); % decode this sequence a special way 341 | elseif (xType==8) % L>1 and 0 <= x(1)=x(2)=...=x(L) <= 1 342 | L=GetVLIC+2; 343 | x=ones(L,1)*GetABit; 344 | elseif (xType==9) % L=1 and 0 <= x(1) <= 1 345 | x=GetABit; 346 | elseif (xType==10) % L>1 and x(1)=x(2)=...=x(L) <= -1 347 | L=GetVLIC+2; 348 | x=ones(L,1)*(-1-GetVLIC); 349 | elseif (xType==11) % L=1 and x(1) <= -1 350 | x=(-1-GetVLIC); 351 | end % if (xType==0) 352 | % additional information should be decoded as well 353 | L=length(x); 354 | I=find(x); 355 | if 0 356 | if sum(xType==[4,6]) % sign must be retrieved 357 | Sg=zeros(size(I)); 358 | for i=1:length(I); Sg(i)=GetABit; end; % and the signs (0/1) 359 | Sg=Sg*2-1; % (-1/1) 360 | end 361 | if sum(xType==[5,6]) % additional bits must be retrieved 362 | xa=zeros(L,1); 363 | for i=1:L 364 | for ii=2:x(i) 365 | xa(i)=2*xa(i)+GetABit; 366 | end 367 | end 368 | x(I)=2.^(x(I)-1); 369 | x=x+xa; 370 | end 371 | else 372 | if sum(xType==[4,6]) % sign must be retrieved 373 | Sg=DecodeBin(length(I)); % since length(I)=length(Sg) 374 | Sg=Sg*2-1; % (-1/1) 375 | end 376 | if sum(xType==[5,6]) % additional bits must be retrieved 377 | bi=sum(x)-length(I); % number of additional bits 378 | b=DecodeBin(bi); 379 | bi=0; 380 | xa=zeros(L,1); 381 | for i=1:L 382 | for ii=2:x(i) 383 | bi=bi+1; 384 | xa(i)=2*xa(i)+b(bi); 385 | end 386 | end 387 | x(I)=2.^(x(I)-1); 388 | x=x+xa; 389 | end 390 | end 391 | if sum(xType==[4,6]) % sign must be used 392 | x(I)=x(I).*Sg; 393 | end 394 | % now x is the retrieved sequence 395 | xC{num}=x; 396 | end % for num=1:NumOfX 397 | varargout(1) = {xC}; 398 | end 399 | 400 | return % end of main function, Arith07 401 | %---------------------------------------------------------------------- 402 | %---------------------------------------------------------------------- 403 | 404 | % --- The functions for binary sequences: EncodeBin and DecodeBin ------- 405 | % These function may call themselves recursively 406 | function EncodeBin(x,L) 407 | global y Byte BitPos 408 | global high low range ub hc lc sc K code 409 | 410 | Display=0; 411 | x=x(:); 412 | if (length(x)~=L); error('EncodeBin: length(x) not equal L.'); end; 413 | 414 | % first we try some different coding methods to find out which one 415 | % that might do best. Many more methods could have been tried, for 416 | % example methods to check if x is a 'byte' sequence, or if the bits 417 | % are grouped in other ways. The calling application is the best place 418 | % to detect such dependencies, since it will (might) know the process and 419 | % possible also its statistical (or deterministic) properties. 420 | % Here we just check some few coding methods: direct, split, diff, diff+split 421 | % The main variables used for the different methods are: 422 | % direct: x, I, J, L11, b0 423 | % split: x is split into x1 and x2, L1, L2, b1 is bits needed 424 | % diff: x3 is generated from x, I3, J3 L31, b2 425 | % diff+split: x3 is split into x4 and x5, L4, L5, b3 426 | % 427 | MetS=[0,1,2,3]; % the different methods, direct, split, diff, diff+split 428 | MetC=[9,3,3,1]; % and the counts (which gives the probabilities) 429 | % first set how many bits needed to code the method 430 | b0=log2(sum(MetC))-log2(MetC(1)); 431 | b1=log2(sum(MetC))-log2(MetC(2)); 432 | b2=log2(sum(MetC))-log2(MetC(3)); 433 | b3=log2(sum(MetC))-log2(MetC(4)); 434 | 435 | I=find(x(1:(L-1))==1); % except last element in x 436 | J=find(x(1:(L-1))==0); 437 | L11=length(I); 438 | % perhaps is 'entropy' interesting 439 | % N1=L11+x(L); 440 | % N0=L-N1; 441 | % b=N1*log2(L/N1)+N0*log2(L/N0); 442 | % disp(['L=',int2str(L),', N1=',int2str(N1),', (e)bits=',num2str(b)]); 443 | b0=b0+BitEst(L,L11+x(L)); % bits needed for the sequence without splitting 444 | if Display 445 | disp(['EncodeBin: x of length ',int2str(L),' and ',int2str(L11+x(L)),... 446 | ' ones (p=',num2str((L11+x(L))/L,'%1.3f'),... 447 | ') can be coded by ',num2str(b0,'%6.0f'),' bits.']); 448 | end 449 | % diff with a binary sequence is to indicate wether or not a symbol is 450 | % the same as preceeding symbol or not, x(0) is assumed to be '0' (zero). 451 | % This is the DPCM coding scheme on a binary sequence 452 | x3=abs(x-[0;x(1:(L-1))]); 453 | I3=find(x3(1:(L-1))==1); % except last element in x3 454 | J3=find(x3(1:(L-1))==0); 455 | L31=length(I3); 456 | b2=b2+BitEst(L,L31+x3(L)); % bits needed for the sequence without splitting 457 | if Display 458 | disp(['EncodeBin: diff x, L=',int2str(L),' gives ',int2str(L31+x3(L)),... 459 | ' ones (p=',num2str((L31+x3(L))/L,'%1.3f'),... 460 | ') can be coded by ',num2str(b2,'%6.0f'),' bits.']); 461 | end 462 | % 463 | if (L>40) 464 | % only now we try to split the sequences x and x3 465 | if (L11>3) & ((L-L11)>3) 466 | % try to split x into x1 and x2, depending on previous symbol 467 | if L11<(L/2) 468 | x1=x(I+1); 469 | x2=[x(1);x(J+1)]; 470 | L1=L11;L2=L-L11; 471 | else 472 | x1=[x(1);x(I+1)]; 473 | x2=x(J+1); 474 | L1=L11+1;L2=L-L11-1; 475 | end 476 | b11=BitEst(L1,length(find(x1))); % bits needed for x1 477 | b12=BitEst(L2,length(find(x2))); % bits needed for x2 478 | % b1 is bits to code: Method, L11, x1 and x2 479 | b1=b1+log2(L)+b11+b12; 480 | if Display 481 | disp(['EncodeBin, x -> x1+x2: lengths are ',int2str(L1),'+',int2str(L2),... 482 | ' bits are ',num2str(b11,'%6.0f'),'+',num2str(b12,'%6.0f'),... 483 | '. Total is ',num2str(b1,'%6.0f'),' bits.']); 484 | end 485 | else 486 | b1=b0+1; % just to make this larger 487 | end 488 | if (L31>3) & ((L-L31)>3) 489 | % try to split x3 into x4 and x5, depending on previous symbol 490 | if L31<(L/2) 491 | x4=x3(I3+1); 492 | x5=[x3(1);x3(J3+1)]; 493 | L4=L31;L5=L-L31; 494 | else 495 | x4=[x3(1);x3(I3+1)]; 496 | x5=x3(J3+1); 497 | L4=L31+1;L5=L-L31-1; 498 | end 499 | b31=BitEst(L4,length(find(x4))); % bits needed for x4 500 | b32=BitEst(L5,length(find(x5))); % bits needed for x5 501 | % b3 is bits to code: Method, L31, x4 and x5 502 | b3=b3+log2(L)+b31+b32; 503 | if Display 504 | disp(['EncodeBin, diff x -> x4+x5: lengths are ',int2str(L4),'+',int2str(L5),... 505 | ' bits are ',num2str(b31,'%6.0f'),'+',num2str(b32,'%6.0f'),... 506 | '. Total is ',num2str(b3,'%6.0f'),' bits.']); 507 | end 508 | else 509 | b3=b2+1; % just to make this larger 510 | end 511 | else 512 | b1=b0+1; % just to make this larger 513 | b3=b2+1; % just to make this larger 514 | end 515 | % now code x by the best method of those investigated 516 | [b,MetI]=min([b0,b1,b2,b3]); 517 | MetI=MetI-1; 518 | PutS(MetI,MetS,MetC); % code which method to use 519 | % 520 | if MetI==0 521 | % code the sequence x 522 | N1=L11+x(L); 523 | N0=L-N1; 524 | PutN(N1,L); % code N1, 0<=N1<=L 525 | for n=1:L 526 | if ~(N0*N1); break; end; 527 | PutS(x(n),[0,1],[N0,N1]); % code x(n) 528 | N0=N0-1+x(n);N1=N1-x(n); % update model (of rest of the sequence) 529 | end 530 | elseif MetI==1 531 | % code x1 and x2 532 | clear x4 x5 x3 x I3 J3 I J 533 | PutN(L11,L-1); % 0<=L11<=(L-1) 534 | EncodeBin(x1,L1); 535 | EncodeBin(x2,L2); 536 | elseif MetI==2 537 | % code the sequence x3 538 | N1=L31+x3(L); 539 | N0=L-N1; 540 | PutN(N1,L); % code N1, 0<=N1<=L 541 | for n=1:L 542 | if ~(N0*N1); break; end; 543 | PutS(x3(n),[0,1],[N0,N1]); % code x3(n) 544 | N0=N0-1+x3(n);N1=N1-x3(n); % update model (of rest of the sequence) 545 | end 546 | elseif MetI==3 547 | % code x4 and x5 548 | clear x1 x2 x3 x I3 J3 I J 549 | PutN(L31,L-1); % 0<=L31<=(L-1) 550 | EncodeBin(x4,L4); 551 | EncodeBin(x5,L5); 552 | end 553 | return % end of EncodeBin 554 | 555 | function x = DecodeBin(L) 556 | global y Byte BitPos 557 | global high low range ub hc lc sc K code 558 | 559 | % these must be as in EncodeBin 560 | MetS=[0,1,2,3]; % the different methods, direct, split, diff, diff+split 561 | MetC=[9,3,3,1]; % and the counts (which gives the probabilities) 562 | MetI=GetS(MetS,MetC); % encode which method to use 563 | 564 | if (MetI==1) | (MetI==3) % a split was done 565 | L11=GetN(L-1); % 0<=L11<=(L-1) 566 | if L11<(L/2) 567 | L1=L11;L2=L-L11; 568 | else 569 | L1=L11+1;L2=L-L11-1; 570 | end 571 | x1=DecodeBin(L1); 572 | x2=DecodeBin(L2); 573 | % build sequence x from x1 and x2 574 | x=zeros(L,1); 575 | if L11<(L/2) 576 | x(1)=x2(1); 577 | n1=0;n2=1; % index for the last in x1 and x2 578 | else 579 | x(1)=x1(1); 580 | n1=1;n2=0; % index for the last in x1 and x2 581 | end 582 | for n=2:L 583 | if (x(n-1)) 584 | n1=n1+1; 585 | x(n)=x1(n1); 586 | else 587 | n2=n2+1; 588 | x(n)=x2(n2); 589 | end 590 | end 591 | else % no split 592 | N1=GetN(L); 593 | N0=L-N1; 594 | x=zeros(L,1); 595 | for n=1:L 596 | if (N0==0); x(n:L)=1; break; end; 597 | if (N1==0); break; end; 598 | x(n)=GetS([0,1],[N0,N1]); % decode x(n) 599 | N0=N0-1+x(n);N1=N1-x(n); % update model (of rest of the sequence) 600 | end 601 | end 602 | 603 | if (MetI==2) | (MetI==3) % x is diff coded 604 | for n=2:L 605 | x(n)=x(n-1)+x(n); 606 | end 607 | x=rem(x,2); 608 | end 609 | 610 | return % end of DecodeBin 611 | 612 | 613 | % ------- Other subroutines ------------------------------------------------ 614 | 615 | % Functions to write and read a Variable Length Integer Code word 616 | % This is a way of coding non-negative integers that uses fewer 617 | % bits for small integers than for large ones. The scheme is: 618 | % '00' + 4 bit - integers from 0 to 15 619 | % '01' + 8 bit - integers from 16 to 271 620 | % '10' + 12 bit - integers from 272 to 4367 621 | % '110' + 16 bit - integers from 4368 to 69903 622 | % '1110' + 20 bit - integers from 69940 to 1118479 623 | % '1111' + 24 bit - integers from 1118480 to 17895695 624 | % not supported - integers >= 17895696 (=2^4+2^8+2^12+2^16+2^20+2^24) 625 | function PutVLIC(N) 626 | global y Byte BitPos 627 | global high low range ub hc lc sc K code 628 | if (N<0) 629 | error('Arith07-PutVLIC: Number is negative.'); 630 | elseif (N<16) 631 | PutABit(0);PutABit(0); 632 | for (i=4:-1:1); PutABit(bitget(N,i)); end; 633 | elseif (N<272) 634 | PutABit(0);PutABit(1); 635 | N=N-16; 636 | for (i=8:-1:1); PutABit(bitget(N,i)); end; 637 | elseif (N<4368) 638 | PutABit(1);PutABit(0); 639 | N=N-272; 640 | for (i=12:-1:1); PutABit(bitget(N,i)); end; 641 | elseif (N<69940) 642 | PutABit(1);PutABit(1);PutABit(0); 643 | N=N-4368; 644 | for (i=16:-1:1); PutABit(bitget(N,i)); end; 645 | elseif (N<1118480) 646 | PutABit(1);PutABit(1);PutABit(1);PutABit(0); 647 | N=N-69940; 648 | for (i=20:-1:1); PutABit(bitget(N,i)); end; 649 | elseif (N<17895696) 650 | PutABit(1);PutABit(1);PutABit(1);PutABit(1); 651 | N=N-1118480; 652 | for (i=24:-1:1); PutABit(bitget(N,i)); end; 653 | else 654 | error('Arith07-PutVLIC: Number is too large.'); 655 | end 656 | return 657 | 658 | function N=GetVLIC 659 | global y Byte BitPos 660 | global high low range ub hc lc sc K code 661 | N=0; 662 | if GetABit 663 | if GetABit 664 | if GetABit 665 | if GetABit 666 | for (i=1:24); N=N*2+GetABit; end; 667 | N=N+1118480; 668 | else 669 | for (i=1:20); N=N*2+GetABit; end; 670 | N=N+69940; 671 | end 672 | else 673 | for (i=1:16); N=N*2+GetABit; end; 674 | N=N+4368; 675 | end 676 | else 677 | for (i=1:12); N=N*2+GetABit; end; 678 | N=N+272; 679 | end 680 | else 681 | if GetABit 682 | for (i=1:8); N=N*2+GetABit; end; 683 | N=N+16; 684 | else 685 | for (i=1:4); N=N*2+GetABit; end; 686 | end 687 | end 688 | return 689 | 690 | % Aritmetic coding of a number or symbol x, the different symbols (numbers) 691 | % are given in the array S, and the counts (which gives the probabilities) 692 | % are given in C, an array of same length as S. 693 | % x must be a number in S. 694 | % example with symbols 0 and 1, where probabilites are P{0}=0.8, P{1}=0.2 695 | % PutS(x,[0,1],[4,1]) and x=GetS([0,1],[4,1]) 696 | % An idea: perhaps the array S should be only in the calling function, and 697 | % that it do not need to be passed as an argument at all. 698 | % Hint: it may be best to to the most likely symbols (highest counts) in 699 | % the beginning of the tables S and C. 700 | function PutS(x,S,C) 701 | global y Byte BitPos 702 | global high low range ub hc lc sc K code 703 | N=length(S); % also length(C) 704 | m=find(S==x); % m is a single value, index in S, 1 <= m <= N 705 | sc=sum(C); 706 | lc=sc-sum(C(1:m)); 707 | hc=lc+C(m); 708 | % disp(['PutS: lc=',int2str(lc),' hc=',int2str(hc),' sc=',int2str(sc),' m=',int2str(m)]); 709 | EncodeSymbol; % code the bit 710 | return 711 | 712 | function x=GetS(S,C) 713 | global y Byte BitPos 714 | global high low range ub hc lc sc K code 715 | range=high-low+1; 716 | sc=sum(C); 717 | count=floor(( (code-low+1)*sc-1 )/range); 718 | m=1; 719 | lc=sc-C(1); 720 | while (lc>count); m=m+1; lc=lc-C(m); end; 721 | hc=lc+C(m); 722 | x=S(m); 723 | % disp(['GetS: lc=',int2str(lc),' hc=',int2str(hc),' sc=',int2str(sc),' m=',int2str(m)]); 724 | RemoveSymbol; 725 | return 726 | 727 | % Aritmetic coding of a number x, 0<=x<=N, P{0}=P{1}=...=P{N}=1/(N+1) 728 | function PutN(x,N) % 0<=x<=N 729 | global y Byte BitPos 730 | global high low range ub hc lc sc K code 731 | sc=N+1; 732 | lc=x; 733 | hc=x+1; 734 | EncodeSymbol; % code the bit 735 | return 736 | 737 | function x=GetN(N) 738 | global y Byte BitPos 739 | global high low range ub hc lc sc K code 740 | range=high-low+1; 741 | sc=N+1; 742 | x=floor(( (code-low+1)*sc-1 )/range); 743 | hc=x+1;lc=x; 744 | RemoveSymbol; 745 | return 746 | 747 | % Aritmetic coding of a bit, probability is 0.5 for both 1 and 0 748 | function PutABit(Bit) 749 | global y Byte BitPos 750 | global high low range ub hc lc sc K code 751 | sc=2; 752 | if Bit 753 | hc=1;lc=0; 754 | else 755 | hc=2;lc=1; 756 | end 757 | EncodeSymbol; % code the bit 758 | return 759 | 760 | function Bit=GetABit 761 | global y Byte BitPos 762 | global high low range ub hc lc sc K code 763 | range=high-low+1; 764 | sc=2; 765 | count=floor(( (code-low+1)*sc-1 )/range); 766 | if (1>count) 767 | Bit=1;hc=1;lc=0; 768 | else 769 | Bit=0;hc=2;lc=1; 770 | end 771 | RemoveSymbol; 772 | return; 773 | 774 | % The EncodeSymbol function encode a symbol, (correspond to encode_symbol page 149) 775 | function EncodeSymbol 776 | global y Byte BitPos 777 | global high low range ub hc lc sc K code 778 | range=high-low+1; 779 | high=low+floor(((range*hc)/sc)-1); 780 | low=low+floor((range*lc)/sc); 781 | while 1 % for loop on page 149 782 | if bitget(high,K)==bitget(low,K) 783 | PutBit(bitget(high,K)); 784 | while ub > 0 785 | PutBit(~bitget(high,K)); 786 | ub=ub-1; 787 | end 788 | elseif (bitget(low,K-1) & (~bitget(high,K-1))) 789 | ub=ub+1; 790 | low=bitset(low,K-1,0); 791 | high=bitset(high,K-1,1); 792 | else 793 | break 794 | end 795 | low=bitset(low*2,K+1,0); 796 | high=bitset(high*2+1,K+1,0); 797 | end 798 | return 799 | 800 | % The RemoveSymbol function removes (and fill in new) bits from 801 | % file, y, to code 802 | function RemoveSymbol 803 | global y Byte BitPos 804 | global high low range ub hc lc sc K code 805 | range=high-low+1; 806 | high=low+floor(((range*hc)/sc)-1); 807 | low=low+floor((range*lc)/sc); 808 | while 1 809 | if bitget(high,K)==bitget(low,K) 810 | % do nothing (shift bits out) 811 | elseif (bitget(low,K-1) & (~bitget(high,K-1))) 812 | code=bitset(code,K-1,~bitget(code,K-1)); % switch bit K-1 813 | low=bitset(low,K-1,0); 814 | high=bitset(high,K-1,1); 815 | else 816 | break 817 | end 818 | low=bitset(low*2,K+1,0); 819 | high=bitset(high*2+1,K+1,0); 820 | code=bitset(code*2+GetBit,K+1,0); 821 | end 822 | if (low > high); error('low > high'); end; 823 | return 824 | 825 | % Functions to write and read a Bit 826 | function PutBit(Bit) 827 | global y Byte BitPos 828 | BitPos=BitPos-1; 829 | if (~BitPos); Byte=Byte+1; BitPos=8; end; 830 | y(Byte) = bitset(y(Byte),BitPos,Bit); 831 | return 832 | 833 | function Bit=GetBit 834 | global y Byte BitPos 835 | BitPos=BitPos-1; 836 | if (~BitPos); Byte=Byte+1; BitPos=8; end; 837 | Bit=bitget(y(Byte),BitPos); 838 | return 839 | 840 | function b=BitEst(N,N1); 841 | if (N1>(N/2)); N1=N-N1; end; 842 | N0=N-N1; 843 | if (N>1000) 844 | b=(N+3/2)*log2(N)-(N0+1/2)*log2(N0)-(N1+1/2)*log2(N1)-1.3256; 845 | elseif (N1>20) 846 | b=(N+3/2)*log2(N)-(N0+1/2)*log2(N0)-(N1+1/2)*log2(N1)-0.020984*log2(log2(N))-1.25708; 847 | else 848 | b=log2(N+1)+sum(log2(N-(0:(N1-1))))-sum(log2(N1-(0:(N1-1)))); 849 | end 850 | return 851 | --------------------------------------------------------------------------------