%% Copyright (C) 2012 Telematic and Telecommunication Laboratory (LTT),       
% Dipartimento di Ingegneria dell'Informazione- Università di Siena
% via Roma 56 53100 - Siena, Italy                   
% 
%----------------------------------------------------------------------
%Permission to use, copy, or modify this software and its documentation
%for educational and research purposes only and without fee is hereby
%granted, provided that this copyright notice and the original authors'
%names appear on all copies and supporting documentation. This program
%shall not be used, rewritten, or adapted as the basis of a commercial
%software or hardware product without first obtaining permission of the
%authors. The authors make no representations about the suitability of
%this software for any purpose. It is provided "as is" without express
%or implied warranty.
%----------------------------------------------------------------------
%
%This is an implementation of the algorithm for removing statistical
%traces left into the histogram of an image by any processing operator. 
%Please refer to the following paper:
%
%M. Barni, M. Fontani, B. Tondi, "A Universal Technique to Hide Traces of 
%Histogram-Based Image Manipulations", ACM Int. Workshop on Multimedia and 
%Security (MMSEC) 2012, Coventry, UK, 2012.
%
%Kindly report any suggestions or corrections to marco.fontani@unisi.it
%
%----------------------------------------------------------------------
function[matching_hist, mindist, fname] = MMfind_best_match(img, N, DBfile, varargin)
%function[matching_hist, mindist, fname] = MMfind_best_match(img, N, DBfile, varargin)
%Given an image, finds the best N with matching histogram among those in the "res"
%cell array contained in file DBfile.
%"res" array is expected to have in its right-most position the array that
%will be used to evaluate the euclidean distance.
%
%--- INPUT ARGS ---
%-> img: given image (grayscale, if RGB will be converted!)
%-> N: number of histograms to be returned (best matching will be the
%   first, then comes the second and so on..)
%-> DBfile: file containing the cell array of features
%-> plotFig: plot figures, press any key to continue after plotting.
%
%--- OUTPUT ARGS ---
%-> matching_hist: cell array of the 10 best-matching histograms in the DB
%                  (best one is in first position)
%-> mindist: euclidean distance of the best matching entry in DB.
%-> fname: name of the file retaining the best match

%Evaluate features (as those extracted by "generateDB function".
    if size(img,3)>1
        img = rgb2gray(img);
    end
    img = double(img);    
    h = hist(img(:),0:1:255);
    media = mean2(img)/255;
    Imax = max(img(:));
    Imin = min(img(:));
    %contrasto = std2(img) %RMS contrast
    contrasto = (Imax-Imin)/(Imax+Imin); %Michelson contrast
    %[dummy results] = multimodality(uint8(img),0);
    results = 0;
    %keep only clusters having at least 10% of pixels
    

    
   %feat_array = [results.mean(results.proportion>0.2)/255, contrasto];
        
    
    load(DBfile);
    
    if strcmpi(varargin{1},'prefilt') || (length(varargin)>1 && strcmpi(varargin{2},'prefilt'))
        %filter the DB: keep only histograms having the right number of modes.
        nmodi = sum(results.proportion>0.2);        
        filt_res = cat(1,res(logical([res{:,end-1}]==nmodi),:));
    else
        filt_res = res;        
%        filt_res = res(1:500,:);display('WARNING: USING REDUCED DATASET!!!!!!!');
    end
    
%% FEATURE BASED DISTANCES
    %evaluate distance from given feature array from all others in the DB
%    distanze = dist2(feat_array, cat(1,filt_res{:,6}));
    
    %evaluate chi-square distance from given feature array from all others in DB

%% QUADRATIC-CHI DISTANCES
%     display('Computing distances with Quadratic-Chi metric')
%     distanze = ones(size(filt_res,1),1)*Inf;
%     for k=1:size(filt_res,1)
%        distanze(k) = ChiSquareDist(h,filt_res{k,2},'normalize');      
%     end
    
%% EMD DISTANCES
%      display('Computing distances with EMD metric')
%      load ground_dist.mat
%      distanze = ones(size(filt_res,1),1)*Inf;
%      extra_mass_penalty= -1;     
%      for k=1:size(filt_res,1)
%         distanze(k) = emd_hat_gd_metric_mex(normalizeHist(h)',normalizeHist(filt_res{k,2})',D,extra_mass_penalty);
%      end
%     
    
    %% CHI-SQUARE DISTANCES
   % display('Computing distances with Chi-Square dist.')
   distanze = ones(size(filt_res,1),1)*Inf;
   for k=1:size(filt_res,1)
      distanze(k) = chi2dist(h,filt_res{k,2},'normalize');      
   end


    %%
    %sort and take indices
    [M IDXs] = sort(distanze);
    
    %prepare output (select the first N smaller distances among those
    %HAVING THE SAME NUMBER OF MODES)
    matching_hist = cell(N,1);
    mindist = cell(1,N);
    fname = cell(1,N);
    z=1;
    i=1;
    while z-1<N && i<length(IDXs)
 %       if filt_res{IDXs(i),4} >= contrasto %take only histograms with equal or higher contrast
            matching_hist{z} = filt_res{IDXs(i),2};
            mindist{z} = distanze(IDXs(i));
            fname{z} = filt_res{IDXs(i),1};
            z=z+1;
 %       end
        i = i+1;
    end    
    
    if strcmpi(varargin{1},'plot') || (length(varargin)>1 && strcmpi(varargin{2},'plot'))
        N=size(matching_hist,1);
        figure();set(gcf,'OuterPosition',[0 0 1000 1000]);
        for p=1:N
            chisqdist = chi2dist(h,matching_hist{p},'normalize');
            subplot(ceil(sqrt(N)),max(1,floor(sqrt(N))),p); bar(matching_hist{p}/sum(matching_hist{p}));title(sprintf('Rank: %d� - CSQ: %.3f',p,chisqdist));
        end
        figure();set(gcf,'OuterPosition',[800 50 250 250]);
        bar(h/sum(h),'red');title(sprintf('Query histogram'));        
        pause;close all;
    end
end

function[MSE] = getHistMSE(hist1, hist2)
    MSE = mean((hist1-hist2).^2);
end