用已训练模型抽取特征
在抽取特征之前,有必要稍微先来了解一下imagenet-vgg-f这个模型。这里稍微啰嗦一下上面的那个测试脚本,im_ = imresize(im_, net.normalization.imageSize(1:2))将图像缩放到统一尺寸,即224*224的大小,这点你可以看看net中normalization.imageSize,而且还必须为彩色图像。res有22个struct,从第17到20的struct分别是4096位,最后第21到22个struct是1000维的,是4096维经过softmax后的结果,这里我们要用的是第20个struct的数据(自己测过第19个struct,检索效果比采用第20个struct的特征差)。这个网络有8层构成,从第6层到第8层都是全连接层。关于这个网络的结构,暂时到这里。
大致了解了这个网络结构后,我们便可以使用该网络抽取图像的特征了,抽取特征的代码(完整的图像检索代码见文末最后给出的链接)如下:
% Author: Yong Yuan
% Homepage: yongyuan.name
clear all;close all;clc;
% version: matconvnet-1.0-beta17
%run ./matconvnet-1.0-beta17/matlab/vl_compilenn
run ./matconvnet-1.0-beta17/matlab/vl_setupnn
%% Step 1 lOADING PATHS
path_imgDB = ‘./database/’;
addpath(path_imgDB);
addpath tools;
% viesion: matconvnet-1.0-beta17
net = load(‘imagenet-vgg-f.mat’) ;
%% Step 2 LOADING IMAGE AND EXTRACTING FEATURE
imgFiles = dir(path_imgDB);
imgNamList = {imgFiles(~[imgFiles.isdir]).name};
clear imgFiles;
imgNamList = imgNamList’;
numImg = length(imgNamList);
feat = [];
rgbImgList = {};
%parpool;
%parfor i = 1:numImg
for i = 1:numImg
oriImg = imread(imgNamList{i, 1});
if size(oriImg, 3) == 3
im_ = single(oriImg) ; % note: 255 range
im_ = imresize(im_, net.meta.normalization.imageSize(1:2)) ;
im_ = im_ - net.meta.normalization.averageImage ;
res = vl_simplenn(net, im_) ;
% viesion: matconvnet-1.0-beta17
featVec = res(20).x;
featVec = featVec(:);
feat = [feat; featVec'];
fprintf('extract %d image\n\n', i);
else
im_ = single(repmat(oriImg,[1 1 3])) ; % note: 255 range
im_ = imresize(im_, net.meta.normalization.imageSize(1:2)) ;
im_ = im_ - net.meta.normalization.averageImage ;
res = vl_simplenn(net, im_) ;
% viesion: matconvnet-1.0-beta17
featVec = res(20).x;
featVec = featVec(:);
feat = [feat; featVec'];
fprintf('extract %d image\n\n', i);
end
end
feat_norm = normalize1(feat);
save(‘feat4096Norml.mat’,‘feat_norm’, ‘imgNamList’, ‘-v7.3’);
在倒数第二行,对特征进行了L2归一化,方便后面用余弦距离度量,L2归一化方法如下:
function [X] = normalize1(X)
% X:n*d
for i=1:size(X,1)
if(norm(X(i,:))==0)
else
X(i,:) = X(i,:)./norm(X(i,:));
end
end