classdef SURFDetector < helpers.GenericInstaller ...
    & localFeatures.GenericLocalFeatureExtractor

  properties (SetAccess=public, GetAccess=public)
    Opts
    SURFArguments
  end

  methods
    function obj = SURFDetector(varargin)
      % def. arguments
      obj.Name = 'SURF';
      varargin = obj.configureLogger(obj.Name,varargin);
      obj.SURFArguments = obj.checkInstall(varargin);
      obj.ExtractsDescriptors = true;
    end

    function [frames, descriptors] = extractFeatures(obj, imagePath)
      import helpers.*;
      [frames, descriptors] = obj.loadFeatures(imagePath,nargout > 1);
      if numel(frames) > 0; return; end;
      img = imread(imagePath);
      if(size(img,3)>1), img = rgb2gray(img); end
      startTime = tic;
      if nargout == 1
        obj.info('Computing frames of image %s.',getFileName(imagePath));
        points = detectSURFFeatures(img);
        frames = double([points.Location(:,1)'; points.Location(:,2)'; points.Scale(:)'; points.Orientation(:)']);
      else
        obj.info('Computing frames and descriptors of image %s.',...
          getFileName(imagePath));
        points = detectSURFFeatures(img, obj.SURFArguments{:});
        frames = [points.Location(:,1)'; points.Location(:,2)'; points.Scale(:)'];
        [frames, descriptors] = obj.extractDescriptors(imagePath, frames);
      end
      timeElapsed = toc(startTime);
      obj.debug('%d Frames from image %s computed in %gs',...
        size(frames,2),getFileName(imagePath),timeElapsed);
      obj.storeFeatures(imagePath, frames, descriptors);
    end

    function [frames, descriptors] = extractDescriptors(obj, imagePath, frames)
      import localFeatures.helpers.*;
      obj.info('Computing descriptors.');
      startTime = tic;
      % Get the input image
      img = imread(imagePath);
      if size(img,3) > 1
        img = rgb2gray(img);
      end
      if size(frames,1) > 4
        % Convert frames to disks
        frames = [frames(1,:); frames(2,:); getFrameScale(frames)];
      end
      if size(frames,1) < 4
        % When no orientation, compute upright descriptors
        frames = [frames; zeros(1,size(frames,2))];
      end
      % Compute the descriptors (using scale space).
      
      scale = frames(3,:)';
      scale(scale<1.6) = 1.6;
      
      Location = [frames(1,:)', frames(2,:)'];
      points = SURFPoints(Location,'Scale',scale,'Orientation',frames(4,:)');
      
      [featVects, vpts] = extractFeatures(img, points, 'Method', 'SURF', 'SURFSize', 128, obj.SURFArguments{:});
      
      frames = double([vpts.Location(:,1)'; vpts.Location(:,2)'; vpts.Scale(:)']);
      descriptors = featVects';
    
      elapsedTime = toc(startTime);
      obj.debug('Descriptors computed in %gs',elapsedTime);
    end

    function sign = getSignature(obj)
      sign = [obj.Name,...
              helpers.cell2str(obj.SURFArguments)];
    end
  end
end
