基於稀疏表示的圖像檢索實現
稀疏表示:
稀疏表示就是將原始的信號(本文指的是圖像特徵)在一個變換基獨立且不相關的過完備字典上進行分解,使得原始複雜冗餘的信號可以由分解得到的很少的一組“基元”(特徵)進行完全或近似的線性表示[68],稱該自然信號(本文指的是自然圖像)在“基元組合”變換域中具有稀疏性,而所有的“基元”則組成一個過完備的字典矩陣。稀疏表示的字典獲取方式有多種,最簡單的獲取方式可以採用固定的字典即可,而相對比較好的獲取方式可以通過不同樣本集訓練學習自適應得到,因爲通過這樣訓練學習得到的字典不僅更加適用當前的圖像數據集,也會更加靈活。
下面詳細介紹最基本的稀疏表示模型:
假設一個信號y∈R^N可以由過完備字典D線性稀疏表示,字典D=[d_1,d_2,…,d_K]∈R^N (N≪K),是包含K列的過完備字典,x是待求的稀疏係數向量,那麼原始信號y可由字典D中有限個原子的線性組合近似表示。
稀疏編碼一般都分爲兩個過程:
(1)基向量的學習過程,也可以稱爲字典的學習。在這個過程中,通過無監督學習方法,利用大量的訓練樣本,學習獲得一組冗餘的基向量,這組基向量通常反映了訓練樣本中一些帶有本質特徵的基元,如圖像中的邊界、角點,實驗表明,經稀疏編碼方法學習獲得的基向量在朝向、位置和頻率的選擇上與人類視覺皮層的V1區具有很大的相似性,換言之就是,字典的學習過程模擬了人類視覺皮層對信息的處理過程。圖像中學習得到的字典與人爲設定的模板字典有很大的相似性,在一定程度上反映了圖像的基本單元。
(2)稀疏係數的求解過程。這個過程根據不同的約束條件,可以得到不同的稀疏係數,然後用該係數向量表示圖像特徵。
實現步驟:
(1)首先對所有肝臟病變CT圖像的腫瘤區域提取SIFT局部特徵,並切成
大小爲7×7的塊(也可嘗試其他大小的塊,如5×5等);
(2)使用稀疏表示的方法對這些塊進行學習,這個學習過程分爲以下兩個階段:
基向量的學習過程,也就是字典訓練過程。通過K-SVD算法對這些塊進行學習,訓練得到一個自適應的過完備字典;
稀疏係數的求解。利用已經訓練好的字典通過OMP算法求解稀疏係數,並用該係數向量表示圖像特徵;
(3)利用相似性度量方法中的歐氏距離來計算待查詢圖像與數據集中其他圖像之間的距離,其實就是求它們特徵向量之間的距離;
(4)對求得的這些距離按照從小到大進行排序,距離越小就代表兩幅肝臟病變CT圖像的差異越小,按照距離從小到大輸出檢索出的圖像,實現最終的檢索功能;
(5)利用查準率-查全率、F_1- measure等圖像檢索的性能評價指標來評估檢索的效果。
實現代碼:
%% 清空環境變量
close all;
clear;
clc;
%% 讀取數據並選取訓練集和測試樣本
data = importdata('AllTypesART.mat');
data1 = importdata('AllTypeART.mat');
[m,n,s] = size(data);
[mm,nn,ss] = size(data1);
p = pwd;
addpath(fullfile(p, '/functions')) % K-SVD dictionary training algorithm
addpath(fullfile(p, '/ksvdbox')) % K-SVD dictionary training algorithm
addpath(fullfile(p, '/ompbox')) % Orthogonal Matching Pursuit algorithm
% load('oneLiver_ART322.mat')
conf.dict_sizes = 256; % 字典大小
conf.window = [7 7]; % 圖像塊大小7x7
conf.border = [1 1];
conf.overlap = 1; % 重疊部分爲1
imgs = {};
dess = {};
tic;
for ii = 1:ss
% imgs{ii} = double(data1(:,:,ii));
im = double(data1(:,:,ii));
figure;
imshow(im,[]);
% 採樣
msgbox('Please separate tumour samples','tumour Samples','help');
pause;
[x,y] = ginput(2);
hold on;
plot(x,y,'r*');
x = uint16(x);
y = uint16(y);
%imgss{ii} = zeros(49,49,'double');
imgs{ii} = double(im(y(1):y(2),x(1):x(2)));
[im1, des1, loc1] = sift(imgs{ii}); % 提取sift特徵
savecommand=['save ','F:\test\DES\',num2str(ii-1),' des1;'];
eval(savecommand);
savecommand=['save ','F:\test\LOC\',num2str(ii-1),' loc1;'];
eval(savecommand);
dess{ii} = des1;
end
patches = collect(conf, dess, 1, {}); % 切成特徵塊, {}處表示無需提取特徵
% patches = dess;
% Set KSVD configuration
ksvd_conf.iternum = 20; % 迭代次數
ksvd_conf.memusage = 'normal';
ksvd_conf.dictsize = conf.dict_sizes; % 字典大小
ksvd_conf.Tdata = 10; % maximal sparsity: 最大稀疏度
ksvd_conf.samples = size(patches,2);
ksvd_conf.data = double(patches);
tic;
fprintf('Training [%d x %d] dictionary on %d vectors using K-SVD\n', ...
size(ksvd_conf.data, 1), ksvd_conf.dictsize, size(ksvd_conf.data, 2))
[conf.dict, gamma] = ksvd(ksvd_conf); % k-svd算法
D = conf.dict;
T = ksvd_conf.Tdata;
toc;
%ps = randperm(s,1);
%testData = double(data(:,:,ps)); % 測試樣本 待查圖像
testData = double(data(:,:,36)); % 測試樣本 待查圖像
%str = sprintf('Im %d:',ps);
%imshow(testData,[]);
%title(str);
[im_test, des_test, loc_test] = sift(testData);
dess_tsets = {};
[x,y,u] = size(des_test);
for ii = 1:u
dess_tsets{ii} = des_test;
end
patches1 = collect(conf, dess_tsets, 1, {}); % 切成特徵塊, {}處表示無需提取特徵
patches1 = double(patches1);
gamma_test = omp(D,patches1,D'*D,T);% des1 = D*gamma 求解稀疏係數
% gamma_test_mean = mean(gamma_test,2);
gamma_test_mean = mean(full(gamma_test),2); % 池化 平均池化
%if ps >1
% pss = [1:ps-1,ps+1:s];
%else
% pss = [ps+1:s];
%end
pss = [1:35 37:100];
trainDatas = double(data(:,:,pss));
% 訓練樣本個數
Nfiles = s-1;
% 閾值
t = 0.010;
t2 = 0.8;
fprintf('開始查找...\n');
range = 0.0:0.1:1.0;
rangeNew = 0.0:0.05:1.0;
[a,b,c] = meshgrid(range);
[a2,b2,c2] = meshgrid(rangeNew); % 座標軸
Similarity = zeros(Nfiles, 1); % Nfiles訓練樣本數量 Similarity表示與Nfiles個訓練樣本的相似度量值
nResults = 0;
for ii = 1:Nfiles
trainData = double(trainDatas(:,:,ii));
[im_train, des_train, loc_train] = sift(trainData);
des_trains = {};
[x2,y2,u2] = size(des_train);
for k = 1:u2
des_trains{k} = des_train;
end
patches2 = collect(conf, des_trains, 1, {}); % 切成特徵塊, {}處表示無需提取特徵
patches2 = double(patches2);
gamma_train = omp(D,patches2,D'*D,T);% des1 = D*gamma 求解稀疏係數
%gamma_train_mean = mean(gamma_train,2);
gamma_train_mean = mean(full(gamma_train),2);
% 計算歐式距離
%DIFF = abs(gamma_test_mean-gamma_train_mean) ./ gamma_test_mean;
DIFF = sum((gamma_test_mean-gamma_train_mean).^2); % 歐式距離
% 保持與相關查詢圖像的距離值大於預先設定的閾值
%DIFF = DIFF(gamma_test_mean>t);
% keep error values which are smaller than 1:
%DIFF2 = DIFF(DIFF<t2);
%L2 = length(DIFF2);
% 計算相似度
Similarity(ii) = DIFF;
% (interface): plot images with small similarity measures:
plotThres = 0.50 * 10 / length(DIFF);
if (Similarity(ii) < plotThres)
% fprintf('%70s %5.2f %5d %5d\n', files{i}, median(DIFF2),
% length(DIFF), L2);
nResults = nResults+1;
subplot(2,2,1);imshow(testData,[]);title('Query image');
im_trainData = trainData;
subplot(2,2,2);imshow(im_trainData,[]);
title('A similar image ... Still Searching ...');
subplot(2,2,3);
plot(DIFF)
%if (length(DIFF2)>1)
% subplot(2,2,4); plot(DIFF2);
% axis([1 length(DIFF2) 0.2 1])
%end
drawnow
end
end
% find the nResult "closest" images:
% Similarity = 1./Similarity;
[Sorted, ISorted] = sort(Similarity); % 相似度從小到大排序 升序(直方圖相似距離越小 越相似)
nResults = 11;
NRows = ceil((nResults+1) / 3); % ceil(x)大於x的最小整數
% plot query image:
subplot(NRows,3,1); imshow(testData,[]); title('Query Image');
% ... plot similar images:
for (i=1:nResults)
im_trainData = double(trainDatas(:,:,ISorted(i)));
str = sprintf('Im %d: %.3f',i,100*Sorted(i));
subplot(NRows,3,i+1); imshow(im_trainData,[]); title(str);
end
toc;
disp(['檢索時間: ',num2str(toc)]);
fprintf('Done\n');