function object_recognition(threshold, load_images)
% function object_recognition(threshold, load_images)
%
% small demo opening live image stream from webcam. Grabs
% sequentially some images of different objects, performs feature 
% extraction and live classification in the subsequent live-stream
%
% threshold is the distance of the feature-vectors, which must not
% be exceeded. Default is 10000
%  low threshold  -> almost no recognition, but mostly correct
%  high threshold -> almost always recognition, but mostly wrong,
%  even background is classified as object if the threshold is too large...
%
% if load_images is set to one, then no training image capturing is
% performed, but the images are loaded from file from the last session
% default is 0 (no loading but acuiring images one by one)
%
% default use: object_recognition(10000,0);

% Bernard Haasdonk 14.1.2006

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% set some constants, please modify freely
object_names = {'Hand','Musik-CD','MegaMinx',...
		'Tannenzäpfle','Shake-Egg'};
number_of_images_per_object = 5;
recognition_loop_length = 1000; % length in images
display_histogram = 0; % 0: no display of histogram, 1: display of histogram
display_classification_details = 1; % 0: no display, 1: display of details 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if (nargin < 2) | (isempty(load_images))
  load_images = 0;
end;

if (nargin < 1) | (isempty(threshold))
  threshold = 10000;
end;


%%%%%%%%%%%%%%%%%%%%%%%%%%%% get training set %%%%%%%%%%%%%%%%%%%%%%%%%%%
if ~load_images 
  a = vcapg2;  % open webcam 
  f = figure;  % open figure
  set(f,'doublebuffer','on'); 
  number_objects = length(object_names);
  
  % get backgroundimage:
  input('Bitte Eingabetaste zum Aufnehmen des Hintergrundes');
  bimage = vcapg2;
  bimaged = double(bimage); 
  subplot(number_objects+1,number_of_images_per_object,1);
  imshow(bimage);
  
  % get object feature-vectors
  labels = [];
  features = [];
  for objectnumber = 1:length(object_names);
    for imagenumber = 1:number_of_images_per_object;
      input(['Bitte Eingabetaste zum Aufnehmen von Bild ',...
	     num2str(imagenumber),...
	     ' von ', object_names{objectnumber}]);
      a = double(vcapg2);
      segmented_image = segment_image(a,bimaged);
      features = [features, get_image_features(segmented_image)];
      labels = [labels, objectnumber];
      subplot(number_objects+1,number_of_images_per_object,...
	      imagenumber+objectnumber*number_of_images_per_object);
      imshow(uint8(segmented_image));
    end;
  end;
  save('object_training_set','labels','features','bimaged','object_names')
else % load images
  load('object_training_set');  
end;
% result: large matrix "features", each column is the feature
% vector of one sample, the labels are stored in "labels"

%%%%%%%%%%%%%%%%%%%%%%%%%%%% start recognition loop %%%%%%%%%%%%%%%%%%%%%%%%%%%
f = figure;  % open figure
set(f,'doublebuffer','on'); 
disp('Erkennung wird gestartet:');
for i = 1:1000; 
  a = double(vcapg2); 
  segmented_image = segment_image(a,bimaged);
  featurevec = get_image_features(segmented_image);
  if display_histogram
    disp(featurevec);      
  end;
  [class,dist] = nearest_neighbour(featurevec,features,labels);
  if display_classification_details
    disp(['Wahrscheinlichstes Objekt: ',object_names{class},', '...
	  'Abstand der Merkmalsvektoren: ',num2str(dist)]);
  end;
  imshow(uint8(a));
  if (dist<threshold)
    text(0,150,object_names{class},'color','green',...
  	 'fontsize', 50);
  end;
  drawnow; 
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%% auxiliary functions %%%%%%%%%%%%%%%%%%%%%%%%%%%
function segmented_image = segment_image(aimage, bimage)
% function segmenting the actual camera image "aimage" by
% subtracting the background image "bimage", 
% binarizing the image and performing a noise removal
cdo = aimage-bimage;
cdo = sum(cdo.^2,3)>400; 
c = uint8(cdo);
segment_mask = double(imerode(c,ones(5,5)));
segmented_image = zeros(size(aimage));
for i = 1:3;
  segmented_image(:,:,i) = aimage(:,:,i) .* segment_mask;
end;

function featurevec = get_image_features(segmented_image);
% function taking the segmented camera image "segmented_image", 
% and computing the simple red histogram, green histogram and blue
% histogram which are connected into a vector with 24 entries
histedges = 0:(256/8):256;
featurevec = [];
for i = 1:3;
  si = segmented_image(:,:,i);
  hi = histc(si(:),histedges);
  featurevec = [featurevec; hi(1:end-1)];
end;

function [class, dist] = nearest_neighbour(fv,features,labels);
% function determining the nearest euclidean neighbour of the
% vector "fv" in the columns of the matrix "features". The minimum 
% distance and the corresponding label are returned in "class" and "dist"
fvs = repmat(fv, 1, size(features,2));
dists = sqrt(sum((fvs-features).^2,1)); % vector with distances
[dist, i] = min(dists);
class = labels(i(1));

