% 12.2.01 - Stephan Dale - CS6441 Computer Vision
% mystereogram.m

% function the_stereogram = mystereogram(Z,colourmnum_colours,pixel_size,eye_dist)
% this function returns a random dot stereogram.
%
% input variables:
% Z is a depth map constaining values ranging from 0-1.
%   a value of 1 indicates that that point of the 3D object sits on the 
%   stereogram image plane, 0 indicates that the point is on the back plane.
% colour gives the range of colours to select from.  this can be 'r' for reds, 
%   'g' for greens, or 'b' for the blues.  Anything else defaults to the 
%   entire range of colours.
% num_colours (>=2) gives the number of colours the stereogram is made with.
% pixel_size (in mm) gives the width and height of a pixel (which are assumed to be square).
% eye_dist (in mm) gives the distance of the eyes from the stereogram.
%
% output variables:
% the_stereogram is the stereogram produced.  It contains value 0-255.


function the_stereogram = mystereogram(Z,colour,num_colours,pixel_size,eye_dist)

% set separation of eyes and distance of eyes from stereogram plane
% can be user-defined values in the future
eye_sep = 65; % mm
%eye_dist = 300; % mm
%pixel_size = 1; % mm

% set colour info
%num_colours = 10; % smallest allowable number of colours is 2
num_colours = num_colours-1;
min_colour = 0;
max_colour = 64;
if colour=='b'
   min_colour = 0;
   max_colour = max_colour/3;
elseif colour=='g'
   min_colour = max_colour/3;
   max_colour = (max_colour/3)*2;
elseif colour=='r'
   min_colour = (max_colour/3)*2;
   max_colour = max_colour;
end;
colour_range = max_colour-min_colour;

height = size(Z,1);
width = size(Z,2);

% convert distance measures into pixel values
eye_sep = eye_sep/pixel_size;
eye_dist = eye_dist/pixel_size;

% make the maximum depth the same as eye_dist (so you can use your reflection as a focus point)
Z = Z*eye_dist;  

for y=1:height
      
   % these matrices store the links between the points on a scan-line of the stereogram
   for x=1:width
      look_left(x) = x;
      look_right(x) = x;
   end;
   
   for x=1:width
      % caluculate depth (from stereogram plane, which is of distance 'eye_dist' from the depth map base)
      depth = eye_dist-Z(y,x);
      
      % calculate separation
      sep = round( (depth*eye_sep)/(depth+eye_dist) ); 
      
      % calculate left and right points
      left = round(x - (sep/2));
      right = left + sep;
      
      % assume point is visible to both eyes
      visible = 1;
      
      % if both points are within the image
      if left>=1 & right<=width
         % if the right point is already linked
         if look_left(right)~=right
            % if the old link is wider than the new one
            if look_left(right)<left
               % break the old links
               look_right(look_left(right)) = look_left(right);
               look_left(right) = right;
            else
               visible = 0;
            end;
         end;
         % do the same for the left point
         if look_right(left)~=left
            if look_right(left)>right
               look_left(look_right(left)) = look_right(left);
               look_right(left) = left;
            else
               visible = 0;
            end;
         end;
         % if no link already (maybe because broken above because better one found)
         if visible
            % make a new link
            look_left(right) = left;
            look_right(left) = right;
         end;
      end;
   end;
   
   % make colour matrix for current scan-line
   for x=1:width
      % if linked to itself, set as random colour
      if look_left(x)==x
         colours(x) = uint8( min_colour + ((colour_range/num_colours)*round(num_colours*rand(1))) );
      else % otherwise set right point to same colour as left point
         colours(x) = colours(look_left(x));
      end;
   end;   
   
   for x=1:width
      % transfer the colour to the stereogram matrix
      the_stereogram(y,x) = colours(x);
   end;
   
end; 
