llama / llama_bachelor_MPiTK_2004_VM-1
.pdf- 51-
filez = dir([encode_dir, '*.tif']); for f = 1:length(filez)
encode_file = filez(f).name;
disp(sprintf('Preparing %s for quantization...',encode_file)); im_orig = double(imread([encode_dir, encode_file]));
if ~use_cached_quant
I = img_prepare([encode_dir, encode_file]); save(sprintf('img/img_%s.mat',encode_file),'I');
end
im_spectre = load(sprintf('img/img_%s.mat',encode_file)); im_spectre = im_spectre.I;
disp('Test started.') cnt = 1;
for k=1:length(lambda)
for j=1:length(clusters)
cluster_mtx = double(dlmread(sprintf('data/clusters_•d.txt',clusters(j)),' '));
disp('________________________________'); disp(sprintf('C=%d Lambda=%.1f',clusters(j),lambda(k)));
disp(sprintf('Building statistics for update frequency estimation...'));
if ~use_cached_update_stat
nu_upd = build_upd_stat(im_train, cluster_mtx, Quant_mtx(find(Quant_coef == 1),:), upd_freq_size);
save(sprintf('data/%s_update_stat.mat',train_file),'nu_upd');
end
res = load(sprintf('data/%s_update_stat.mat',train_file)); nu_upd = res.nu_upd;
res = test_algorithm(cluster_mtx,L,lambda(k),book_epsilon,Q,Quant_mtx,im_orig,im_spectre ,im_train,nu_upd,tau,use_cached_book,showpic_after_calc);
for i=1:length(L)
result{f}{cnt} = {encode_file,L(i),clusters(j),lambda(k),res{i}{1},res{i}{2},res{i}{3}};
cnt = cnt + 1;
end
disp('Saving results...'); save([result_out_dir, result_file],'result');
end
end end
disp('Plotting graphs...'); for f = 1:length(filez)
encode_file = filez(f).name;
display_graphs(result{f}, encode_file, [encode_dir,encode_file(1:end- 4),'/']);
end
disp('Saving graphs...'); [flag,fig] = figflag(''); fig = sort(fig);
for i=1:length(fig)
saveas(fig(i),sprintf([result_out_dir, '•d'],i),'emf'); saveas(fig(i),sprintf([result_out_dir, '•d'],i));
end
disp('Test finished.');
disp(sprintf('\n\nLog closed at %d.%d.%d %d:%d:%d\n',floor(clock))); diary off;
- 52-
Файл quantize.m
function [index,update,upd_mtx] = quantize(book,image,Quant_mtx,cb_param,nu_upd,tau)
M = size(image,1);
clusters = cb_param{1}; lambda = cb_param{2}; nu = book{end};
n_clust = max(max(clusters));
D = zeros(n_clust,M); index = cell(1,n_clust+2); update = cell(1,n_clust); nu_up = cell(1,n_clust); upd_mtx = cell(1,n_clust);
for k = 1:n_clust
L = size(book{k},1); Lmax(k) = 128;
nu{k} = nu{k} * M / 48 + 1;
i_clust = find(clusters == k); A = image(:,i_clust);
b = [book{k}; zeros(Lmax(k) - L,size(book{k},2))];
R = [nu{k}, ones(1,Lmax(k) - L)];
%[Jvq J] = minJ_adaptive(book{k}',A',R,lambda); nu_upd{k} = nu_upd{k} / sum(nu_upd{k}) * 64 + 1;
%nu_upd{k}(1ћ)
[Jvq, |
index{k}, |
|
update{k}, |
upd_mtx{k}] |
= |
gtr(b',A',R,lambda,int32(L),tau,Quant_mtx(:,i_clust)',nu_upd{k}); |
|
||||
update{k} = update{k}'; |
|
|
|
|
|
upd_mtx{k} = upd_mtx{k}'; |
= |
round(update{k} |
./ |
||
%update{k} |
|||||
repmat(Quant_mtx(i_clust),1,size(update{k},2)))'; |
|
|
|||
nu{k} = nu{k} / sum(nu{k}); |
|
|
|
||
end |
|
|
|
|
|
index{end-1} = image(:,1); |
|
|
|
|
|
param{1} = |
nu; |
|
|
|
|
param{2} = |
book; |
|
|
|
|
param{3} = |
Lmax; |
|
|
|
|
index{end} |
= param; |
|
|
|
|
disp([' |
Vectors updated: ',sprintf('%d,',cellfun('length',update))]); |
|
Файл test_algorithm.m
function res = test_algorithm(clusters,L,lambda,epsilon,Q,Quant_mtx,im_orig,im_spectre,im_train,n u_upd,tau,use_cached_book,showpic_after_calc)
codebook_file = sprintf('book_L•d_C•_La•.mat',max(L),max(max(clusters)),lambda*10);
res = cell(1,length(L));
disp('Building codebook...'); if ~use_cached_book
b = build_codebooks(clusters,im_train,L,lambda,epsilon); save(sprintf('book/vol/%s.mat',codebook_file),'b');
end
book = load(sprintf('book/vol/%s.mat',codebook_file));
- 53-
for k=1:length(L) disp('_____________'); disp(sprintf('L=%d',L(k))); disp('Encoding...');
[index, update, upd_mtx] = quantize(book.b{k},im_spectre,Quant_mtx,book.b{end},nu_upd,tau);
index{end-1} = encode_dc(index{end-1},Q);
disp('Decoding...');
restored = decode(index,update,upd_mtx,[size(im_orig,1) size(im_orig,2)],Q,Quant_mtx,book.b{end},tau);
psnr = 20 * log10(255 * sqrt(size(im_orig,1) * size(im_orig,2) / sum(sum((im_orig - restored).^2))));
disp(sprintf('\tPSNR=%.3f',psnr)); if showpic_after_calc
figure;
imshow(restored / 255); pause;
end
disp('Compressing data...');
all_data = zeros(length(index{1}), max(max(clusters))+1); for i=1:length(index)-2
%[y res] = Arith07(cell({index{i}'}));
%bits = [bits res(1,3)];
all_data(:,i) = index{i}';% - 1;
end
all_data(:,end) = index{end-1} + abs(min(index{end-1})); nsyms = max(all_data)+1;
[bits encoded_data] = arith_mex(int32(all_data),int32(nsyms)); bits = double(bits)';
upd = []; upd_q = [];
for i=1:length(update)
upd = [upd; reshape(update{i},size(update{i},1)*size(update{i},2),1)]; upd_q = [upd_q; upd_mtx{i}];
end
upd = upd + abs(min(upd)); nsyms = max(upd)+1;
if ~isempty(upd)
[bits_upd encoded_data] = arith_mex(int32(upd),int32(nsyms)); bits_upd = double(bits_upd)';
nsyms = max(upd_q)+1;
[bits_updmtx encoded_data] = arith_mex(int32(upd_q),int32(nsyms)); bits_updmtx = double(bits_updmtx)';
else
bits_upd = 0; bits_updmtx = 0; end
bits = [bits, bits_upd, bits_updmtx];
disp(sprintf('Bits for each cluster + DC + update + update codes:'));
disp([sprintf('\t'), sprintf('%d; |
',bits)]); |
|
|
|
bpp = sum(bits / (size(im_orig,1) |
* size(im_orig,2))); |
filesize=%.0f |
||
disp(sprintf('Result: |
PSNR=%.3f, |
BPP=%.3f, |
bytes',psnr,bpp,sum(bits)/8)); res{k} = {psnr,bits,bpp};
end
- 54-
Файл quant_mtx.m
function res = quant_mtx(q)
Q = |
[ % Pennebaker mtx |
24 |
40 |
51 |
61, |
||
16 |
11 |
10 |
16 |
||||
12 |
12 |
14 |
19 |
26 |
58 |
60 |
55, |
14 |
13 |
16 |
24 |
40 |
57 |
69 |
56, |
14 |
17 |
22 |
29 |
51 |
87 |
80 |
62, |
18 |
22 |
37 |
56 |
68 |
109 |
103 |
77, |
24 |
35 |
55 |
64 |
81 |
104 |
113 |
92, |
49 |
64 |
78 |
87 |
103 |
121 |
120 |
101, |
72 |
92 |
95 |
98 |
112 |
100 |
103 |
99, |
]; |
|
|
|
|
|
|
|
Q = reshape(Q',1,64);
res = zeros(length(q),64); for i=1:length(q)
res(i,:) = q(i) * Q;
end
Файл gtr.c
#include <mex.h> #include <math.h> #include <memory.h> #include <float.h>
// Доступ к матрице по-матлабовски |
|
|
|
|
||
#define array(a,i,j,Lrow) (a[j + i * Lrow]) |
|
компонент |
кодируемого |
|||
#define BLKSIZE |
64 |
// |
максимальное число |
|||
вектора |
256 |
// число различных проквантованных компонент |
||||
//#define NU_SIZE |
||||||
#define MAX_SCALAR_QUANTIZERS |
8 |
//число |
различных |
матриц |
скалярного |
квантования
/*
Алгоритм адаптивного векторного квантования GTR (Generalized Threshold Replenishment) [Fowler, 1997], с небольшими изменениями. Ищет векторы в кодовой книге book длины Lmax с наименьшим СКО от исходных К-компонентных векторов train и наименьшими битовыми затратами R (баланс задается с помошью lambda).
В соответствии с алгоритмом GTR, при выполнении условия J_вект. > J_непоср., по каналу связи передается непосредственно проквантованный (с помощью вектора Q) вектор, заносящийся в кодовую книгу. В этом случае в выходной поток индексов записывается число 0.
Изначально в кодовой книге используются только первые L векторов, затем их число может вырасти до Lmax.
Длина массива R должна быть равна Lmax, из них первые L элементов - проинициализированы.
tau - величина, близкая к 1, tau < 1 - коэффициент "устаревания" векторов кодовой книги в выходном потоке.Другими словами, c помощью tau учитывается не только частота появления вектора, но и то, насколько давно он встретился в последний раз.
Результат (индексы 1..L) в массиве Imin из M чисел.
Return Value: количество добавленных в кодовую книгу векторов. Добавленные вектора
записаны в массиве update. Если книга разрослась до Lmax векторов, то дальнейшее кодирование будет только векторным.
Jvalue - выходное суммарное значение функции J по всем векторам
*/
int min_ind(double *data,int length);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]); __inline int best_quantizer(double *train,int itrain,int *V,double *Q,int
Qlen,int K,double *Jscalar,
- 55-
double |
lambda,double *nu, int nu_len, double sum_nu); |
|
||||
int GTR(double *book,double *train,double *update,double *iquant,int L, |
||||||
|
int |
Lmax,int |
M,int |
K,double |
lambda,double |
*R,double |
*Jvalue,double *Imin, |
|
|
|
|
|
|
{ |
double tau,double *Q, int Qlen, double *nu, int nu_len) |
|
||||
i,j,k; |
|
|
|
|
|
|
int |
|
|
|
|
|
|
double |
J, Jscalar, sumR, *Rtau, sum_nu; |
|
|
|||
double |
tmp,vmin; |
|
|
|
|
|
int |
V[BLKSIZE]; |
|
|
|
|
|
int |
imin, iqscalar, effL, upd_ind, upd_cnt; |
|
|
|||
lambda |
/= log(2.0); |
|
|
|
|
|
Rtau = |
(double *)mxMalloc(Lmax*sizeof(double)); |
|
|
|||
memcpy(Rtau,R,Lmax*sizeof(double)); |
|
|
|
|||
effL = |
L; |
|
|
|
|
|
sumR = |
0.0; |
|
|
|
|
|
for (j |
= 0; j < effL; j++) |
|
|
|
|
|
sumR += R[j]; |
|
|
|
|
||
sum_nu |
= 0.0; |
|
|
|
|
|
for (j |
= 0; j < nu_len; j++) |
|
|
|
|
|
sum_nu += nu[j]; |
|
|
|
|
||
//printf("Sum_nu=%.3f, len=%d,center=%.3f\n",sum_nu,nu_len,nu[nu_len/2]); |
||||||
upd_cnt = 0; |
|
|
|
|
|
|
for (i |
= 0; i < M; i++) { |
|
|
|
|
//Оцениваем функцию J для векторного квантования и
//находим вектор кодовой книги, минимизирующий J vmin = DBL_MAX;
imin = 0;
for (j = 0; j < effL; j++) { J = 0;
for (k = 0; k < K; k++) {
tmp = array(train,i,k,K) - array(book,j,k,K); J += tmp * tmp;
}
J = sqrt(J) - lambda * log(R[j]/sumR); if (J < vmin) {
vmin = J; imin = j;
}
}
//Оцениваем функцию J для непосредственного квантования
iqscalar = best_quantizer(train,i,V,Q,Qlen,K,&Jscalar,lambda,nu,nu_len,sum_nu);
//printf("vect=%f sc=%f\n",vmin,Jscalar);
// Сравнение непосредственного и векторного квантования if (Jscalar < vmin) { // Кодируем непосредственно
if (effL < Lmax) upd_ind = effL++;
else
upd_ind = min_ind(Rtau,effL);
for (j = 0; j < K; j++) { nu[V[j] + (nu_len >> 1)]++; tmp = (double)V[j];
array(book,upd_ind,j,K) = tmp * array(Q,iqscalar,j,K); array(update,upd_cnt,j,K) = tmp;
//printf("%d ",V[j]);
}
- 56-
iquant[upd_cnt] = (double)(iqscalar + 1); //+1 for matlab
indexation
//printf("\n imin=%d Jsc=%f Jvec=%f\n",iqscalar,Jscalar,vmin);
sumR -= R[upd_ind] - 1; R[upd_ind] = 1; Rtau[upd_ind] = 1; sum_nu += K;
Jvalue[i] = Jscalar;
Imin[i] = 0; upd_cnt++;
}
else { // Кодируем векторно
Jvalue[i] = vmin; R[imin] += 1.0; Rtau[imin] += 1.0; sumR++;
Imin[i] = imin + 1;
}
for (j = 0; j < effL; j++) Rtau[j] = Rtau[j] * tau;
} |
|
|
|
|
mxFree(Rtau); |
|
|
|
|
return upd_cnt; |
|
|
|
|
} |
|
|
|
|
// call from Matlab like this: |
J, |
new_book] |
= |
|
// |
[Jvalue, |
|||
gtr(initial_codebook',encode_seq',initial_R,lambda,int32(L),tau,Q,nu_update) |
|
|||
void mexFunction(int nlhs, mxArray *plhs[], |
|
|
||
{ |
int nrhs, const mxArray *prhs[]) |
|
|
|
*book, *train, *update, *R, lambda, *final_update, |
|
|||
double |
|
*iquant, *final_iquant, tau, *Q, *nu;
double *Jvalue, *Imin;
int L,Lmax,M,K,Qlen,update_len,quantizers; mxArray *upMtx, *quant_ind;
int nu_len;
book = (double *)mxGetPr(prhs[0]); train = (double *)mxGetPr(prhs[1]); R = (double *)mxGetPr(prhs[2]);
lambda = (double)mxGetScalar(prhs[3]); L = (int)mxGetScalar(prhs[4]);
tau = (double)mxGetScalar(prhs[5]); Q = (double *)mxGetPr(prhs[6]);
nu = (double *)mxGetPr(prhs[7]);
K = mxGetM(prhs[0]); //количество компонент векторов //all transposed! Qlen = mxGetN(prhs[6]);
Lmax = mxGetN(prhs[0]);
M = mxGetN(prhs[1]); //количество векторов, подлежащих кодированию quantizers = mxGetM(prhs[7]);
nu_len = mxGetN(prhs[7]);
plhs[0] = mxCreateDoubleMatrix(1, M, mxREAL); plhs[1] = mxCreateDoubleMatrix(1, M, mxREAL);
Jvalue = (double *)mxGetPr(plhs[0]);
Imin = (double *)mxGetPr(plhs[1]);
upMtx = mxCreateDoubleMatrix(K,M, mxREAL);
- 57-
update = (double *)mxGetPr(upMtx);
quant_ind = mxCreateDoubleMatrix(1,M, mxREAL); iquant = (double *)mxGetPr(quant_ind);
// Do all
update_len = GTR(book,train,update,iquant,L,Lmax,M,K,lambda,R,Jvalue,Imin,tau,Q,Qlen,nu,nu_len)
;
//printf("L=%d,tau=%.3f,lambda=%.3f,upd_len=%d\n",L,tau,lambda,update_len);
plhs[2] = mxCreateDoubleMatrix(K,update_len, mxREAL); final_update = mxGetPr(plhs[2]);
plhs[3] = mxCreateDoubleMatrix(1, update_len, mxREAL); final_iquant = mxGetPr(plhs[3]);
memcpy(final_update,update,K*update_len*sizeof(double)); memcpy(final_iquant,iquant,update_len*sizeof(double));
mxDestroyArray(upMtx); mxDestroyArray(quant_ind);
return;
}
void main(int argc, char **argv)
{
// RD_opt(book,train,2,3,4,0.3, R, Dcum,Imin);
}
__inline int min_ind(double *data,int length)
{
int i, imin = -50; double vmin = DBL_MAX;
for (i = 0; i < length; i++) { if (data[i] < vmin) {
vmin = data[i]; imin = i;
}
}
return imin;
}
__inline int best_quantizer(double *train,int itrain,int *V,double *Q,int Qlen,int K,double *Jscalar,
double lambda,double *nu, int nu_len, double sum_nu)
{
int i,j;
double tmp, vmin, Rscalar,Jtmp[MAX_SCALAR_QUANTIZERS]; int Vtmp[MAX_SCALAR_QUANTIZERS][BLKSIZE];
int imin;
vmin = DBL_MAX;
for (i = 0; i < Qlen; i++) { Jtmp[i] = 0.0;
Rscalar = 0.0;
for (j = 0; j < K; j++) {
Vtmp[i][j] = (int)(array(train,itrain,j,K) / array(Q,i,j,K) +
0.5);
tmp = array(train,itrain,j,K) - ((double)Vtmp[i][j]) *
array(Q,i,j,K);
- 58-
Jtmp[i] += tmp * tmp;
Rscalar -= log(nu[Vtmp[i][j] + (nu_len >> 1)] / sum_nu);
}
Jtmp[i] = sqrt(Jtmp[i]) + lambda * Rscalar;
}
imin = min_ind(Jtmp,Qlen); for (i = 0; i < K; i++) {
V[i] = Vtmp[imin][i];
}
*Jscalar = Jtmp[imin]; return imin;
}