当前位置 博文首页 > 斯人若彩虹,遇上方知有!:matlab使用VGG16提取holidays的fc7特
目录
1、提取fc7特征
2、返回resultfile.dat
3、计算map
holidays数据集:Holidays下载链接
对应的groundtruth也在里面!
注:这个代码是我师兄写的,我自己又重新整理一下,大家可以转到这里-》》》》》
https://blog.csdn.net/saw009/article/details/91788671
% dataset -> Holidays Dataset:http://lear.inrialpes.fr/~jegou/data.php
% 读取holidays所有图像文件
dataset = dir('./jpg/*.jpg');
% 获取图像文件数目
file_num= size(dataset,1);
% 建立图像文件名变量
imgname = cell(file_num,1);
% 建立VGG16特征变量,每行表示一幅图像的特征,fc7共4096维
f_fc7 = zeros(file_num,4096);
% f_fc6 = zeros(file_num,4096);
% f_conv5_3 = zeros(file_num,100352);
% colorfeature = zeros(file_num,256);
% 加载VGG16模型,并获取模型对图像的输入大小要求
net = vgg16;
insz = net.Layers(1).InputSize;
% 提取所有图像的fc7层特征
for i=1:file_num
% 加载图像路径
img_path = dataset(i).folder + "\" + dataset(i).name;
% 获取图片名imgname(不包含文件格式.jpg)
pic_num = split(dataset(i).name,{'.'});
imgname(i) = pic_num(1);
% 读取图像
im = imread(img_path);
% 判断图像是否为单通道的灰度图像,若是,则将其转换为3通道的图像
if size(im,3)==1
rgb=cat(3,im,im,im);
im = mat2gray(rgb);
end
% 将读取处理的图像转换成单精度,防止零均值化后,小于零的像素值被丢弃
img = single(im);
% 将输入图像缩放至VGG16模型所要求的大小,默认使用双三次插值的imresize要比默认使用双线性插值的augmentedImageDatastore更好
img_resize = imresize(img, insz(1:2));
% 提取特征
% f_conv5_3(i,:) = activations(net,img_resize,'conv5_3','OutputAs','rows');
f_fc7(i,:) = activations(net,img_resize,'fc7','OutputAs','rows');
% 显示进度
% colorfeature(i,:) = colorhist(im);
if mod(i,100) == 0
i
end
end
% 保存中间变量
save('f_fc7.mat','f_fc7');
% save('imgname.mat','imgname');
% save('colorfeature.mat','colorfeature');
% 对提取出来的特征进行归一化后,能够进一步提高精确度
% normalize比normr精确度更高,即服从标准正态分布的数据比L2标准化要好
% normalize采用标准正态分布
% normr采用L2标准化,其使用方式为:normr(f_fc7)
% pca降维score
f_fc7_normalizing = normalize(f_fc7,2);
[f_COEFF7, f_SCORE7, f_latent7]=pca(f_fc7_normalizing);
% 将降维后的特征按序号保存,仅取前64维
for i=1:file_num
feature = f_SCORE7(i,1:256);
% feature = colorfeature(i,:);
dlmwrite(['./特征/',imgname{i},'.txt'],feature);
end
% 读取特征文件
features_file = dir('./特征/*.txt');
% 建立特征文件数量变量
features_num = size(features_file,1);
% 将特征文件读入矩阵:行表示特征,列表示维度
% 读取特征的维度,方便建立特征矩阵
feature1_path = features_file(1).folder + "\" + features_file(1).name;
features_dim = size(importdata(feature1_path),2);
% 建立特征矩阵
features = zeros(features_num,features_dim);
for i = 1:features_num
features_path = features_file(i).folder + "\" + features_file(i).name;
features(i,:) = importdata(features_path);
end
% 设置返回图像数目:注意原图像也在其中
num_return = 500;
% 建立返回结果文件变量,不知道定义多少行和多行列时,可以先定义空矩阵后元胞
resultfile = {};
l = 1;
for i=1:features_num
% 计算当前图像与所有图像的L1距离
L1 = zeros(features_num,1);
for j=1:features_num
diff = features(i,:) - features(j,:);
L1(j) = sum(abs(diff));
end
% 对L1距离的结果进行排序
% ****特别注释,sort可以直接返回排好序之后,原来对应的索引index
[L1_sorted, index] = sort(L1);
% 先将查询图像名放在元胞中,然后通过for循环将返回排序号和返回图像依次放在后面,以下是python代码中的定义
% result_line = query_image_name query_result*
% query_result = rank result_image_name
%将文件名从.txt转为.jpg,因为保存的是图片名
query_image_name = split(features_file(i).name,'.');
result_line = [query_image_name{1},'.jpg'];
% 值保存500幅查询图像的返回结果
if mod(str2double(query_image_name{1}),100)==0
% k从2开始取值,因为返回图像不包含查询图像
for k=2:num_return
% 序号rank要从0开始,因此要减2
rank = k-2;
result_image_name = split(features_file(index(k)).name,'.');
query_result = [num2str(rank),' ',result_image_name{1},'.jpg'];
%这个步骤很重要,通过中间变量temp产生新的result_line,可惜MATLAB没有python中.append()那样的功能
temp = [result_line,' ',query_result];
result_line = temp;
end
resultfile{l,1} = result_line;
l=l+1;
end
end
% 保存返回结果文件,保存之前先清空
dlmwrite('resultfile.dat','');
for i=1:size(resultfile,1)
dlmwrite('resultfile.dat',resultfile{i,1},'delimiter', '','newline','pc','-append');
end
% 查询返回结果文件resultfile.dat格式
% 每一行为一幅图像的查询结果:查询图像 返回序号(0) 返回图像(0) 返回序号(1) 返回图像(1) ...
% 图像格式:123456.jpg
infilename = importdata('resultfile.dat');
groundtruth = importdata('holidays_images.dat');
% get_groundtruth
%%% Read datafile holidays_images.dat and output a dictionary
%%% mapping queries to the set of positive results (plus a list of all
%%% images)
allnames = groundtruth;
% 建立所有图像的groundtruth,没有找到字典的功能,只能用元胞代替了
gt = cell(500,2);
k=0;
for i=1:size(groundtruth,1)
% 单个图像的名字(包含.jpg)
imname = groundtruth{i};
imname_split = split(imname,'.');
% 单个图像的名字(不包含.jpg)
imno = str2double(imname_split(1));
% 查询图像名能被100整除,查询图像后的图像就是其相关图像,这里是if...else...就是这个作用
if mod(imno,100)==0
k = k+1;
gt{k,1} = imname;
gt{k,2} = {};
else
temp = [gt{k,2},{imname}];
gt{k,2} = temp;
end
end
% 建立所有查询图像的AP的和,以及查询图像数
sum_ap = 0;
n = 0;
for i=1:size(infilename,1)
% 提取每一行的查询图像query_name,返回结果和序号results
infilename_line = split(infilename{i},' ');
query_name = infilename_line{1};
query_name_split = split(query_name,'.');
imno = str2double(query_name_split(1));
% 如果不是查询图像则不计算AP
if ~mod(imno,100)==0
continue
end
results = infilename_line(2:end);
% 提取查询图像在gt中所在的位置,方便查找相关图像(由于MATLAB没有字典,所以通过该方式实现)
[row,col] = ind2sub(size(gt),find(cellfun(@(x)strcmp(x,query_name),{gt{:,1}})));
gt_results = gt{row,2};
% tp_ranks是相关图像的序号,rank_shift用于移除查询图像是相关图像的情况
tp_ranks=[];
rank_shift=0;
for j=1:size(results,1)/2
rank = results(j*2-1);
returned_name = results(j*2);
% 返回图像不在数据集中,执行报错
if ~ismember(returned_name,allnames)
error(returned_name + " is not in holidays dataset")
end
if returned_name{1}==query_name
rank_shift=-1;
elseif ismember(returned_name,gt_results)
tp_ranks = [tp_ranks,str2double(rank{1})+rank_shift];
end
end
% score_ap_from_ranks_1,计算ap的函数
% 其中值得注意的是ntp=j-1,由于python中是从0开始,所以参与运算时减1;作为索引时不减
ranks = tp_ranks;
nres = size(gt_results,2);
ap=0;
recall_step=1.0/nres;
for j=1:size(ranks,2)
rank = ranks(j);
ntp = j-1;
if rank==0
precision_0=1.0;
else
precision_0=ntp/rank;
end
precision_1=(ntp+1)/(rank+1);
ap = ap + (precision_1+precision_0)*recall_step/2.0;
end
sum_ap = sum_ap+ap;
n=n+1;
end
map = sum_ap/n;
disp("MAP:"+ map*100 +"%");
MAP:70.5346%
?
cs