当前位置 博文首页 > 斯人若彩虹,遇上方知有!:matlab使用VGG16提取holidays的fc7特

    斯人若彩虹,遇上方知有!:matlab使用VGG16提取holidays的fc7特

    作者:[db:作者] 时间:2021-08-25 21:49

    目录

    1、提取fc7特征

    2、返回resultfile.dat

    3、计算map


    1、提取fc7特征

    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
    

    2、返回resultfile.dat

    % 读取特征文件
    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
    

    3、计算map

    % 查询返回结果文件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