function [detections, decision] = getDetectionsForEntDetsLogReg( ...
  detectors, ...
  pyramid, patchCanonicalSize, data, imgHome, detectionParams)
% Performs the detections in the given image.

data = data.annotation;
prSize = round(patchCanonicalSize(1) / pyramid.sbins) - 2;
pcSize = round(patchCanonicalSize(2) / pyramid.sbins) - 2;

[features, levels, indexes] = unentanglePyramid(pyramid, ...
  patchCanonicalSize);
totalProcessed = size(features, 1);

labels = ones(size(features, 1), 1);
decision = zeros(size(labels));
sparseFeats = sparse(features);
for i = 1 : length(detectors)
  [unused_labels, unused_acc, decs] = predict(labels, ...
    sparseFeats, detectors{i});
  decision(:, i) = decs;
end

selected = doSelectionForParams(detectionParams, decision);
detections = constructResultStruct(pyramid, data, prSize, ...
  pcSize, totalProcessed, features, ...
  decision, levels, indexes, selected, detectionParams, imgHome);
end

function detections = constructResultStruct(pyramid, data, prSize, ...
  pcSize, totalProcessed, features, ...
  decision, levels, indexes, selected, detectionParams, imgHome)
detections = struct('features', [], 'metadata', [], 'decision', [], ...
  'totalProcessed', totalProcessed, 'thresh', []);

numDets = size(decision, 2);
for i = 1 : numDets
  detections(i).totalProcessed = totalProcessed;
  selInds = find(selected(:, i));
  if length(selInds) < 1
    continue;
  end
  metadata = getMetadataForPositives(...
      selInds, levels, indexes, prSize, pcSize, data, ...
      pyramid, imgHome);
  picks = doNmsForImg(metadata, decision(selInds, i), ...
    detectionParams.overlap);
  detections(i).features = features(selInds(picks), :);
  detections(i).metadata = metadata(picks);
  detections(i).decision = decision(selInds(picks), i);
end
end

function [newFeat, newLev, newInds] = appendAllTogether(totalProcessed, ...
  features, levels, indexes)
newFeat = zeros(totalProcessed, size(features{1}, 2));
newLev = zeros(totalProcessed, 1);
newInds = zeros(totalProcessed, 2);

featInd = 1;
for i = 1 : length(features)
  if isempty(features{i})
    continue;
  end
  startInd = featInd;
  endInd = startInd + size(features{i}, 1) - 1;
  newFeat(startInd:endInd, :) = features{i};
  features{i} = [];
  newLev(startInd:endInd) = levels{i};
  levels{i} = [];
  newInds(startInd:endInd, :) = indexes{i};
  indexes{i} = [];
  featInd = endInd + 1;
end
end

function selected = doSelectionForParams(params, decision)
% Perform selection based on detection parameters.
if params.selectTopN
  selected = false(size(decision));
  [desc, inds] = sort(decision, 'descend');
  [rows, cols] = size(decision);
  begins = ((1:cols) - 1) * rows;
  indexes = inds + repmat(begins, rows, 1);
  numToSelect = min(size(desc, 1), params.numToSelect);
  selInds = indexes(1 : numToSelect, :);
  selected(selInds(:)) = true;
elseif params.useDecisionThresh
  if isfield(params, 'fixedDecisionThresh')
    thresh = params.fixedDecisionThresh;
  else
    error('Fixed decision thresh needs to be specified.');
  end
  selected = decision >= thresh;
else
  thresh = 0;
  selected = decision >= thresh;
end
end

function selected = doSelectionForParams2(params, decision)
% Perform selection based on detection parameters.
[desc, inds] = sort(decision, 'descend');
if params.selectTopN
  numToSelect = min(length(desc), params.numToSelect);
  selected = inds(1 : numToSelect);
elseif params.useDecisionThresh
  if isfield(params, 'fixedDecisionThresh')
    thresh = params.fixedDecisionThresh;
  else
    error('Fixed decision thresh needs to be specified.');
  end
  selected = find(decision >= thresh);
else
  thresh = 0;
  selected = find(decision >= thresh);
end
end

function [newFeat, newMeta, newDec] = appendAllTogether2(totalProcessed, ...
  features, metadata, decision, numDetectors)
newFeat = zeros(totalProcessed, size(features{1}, 2));
newDec = zeros(totalProcessed, numDetectors);
dummyMetadata = metadata{1};
newMeta(totalProcessed) = dummyMetadata(1);
featInd = 1;
for i = 1 : length(features)
  if isempty(metadata{i})
    continue;
  end
  startInd = featInd;
  endInd = startInd + size(features{i}, 1) - 1;
  newFeat(startInd:endInd, :) = features{i};
  features{i} = [];
  newMeta(startInd:endInd) = metadata{i};
  metadata{i} = [];
  newDec(startInd:endInd, :) = decision{i};
  decision{i} = [];
  featInd = endInd + 1;
end
end
