function suitValueIndices = identifySingleCard(cardImage,ulcCoords)

% Ray Wagner
% Elec 301
% Gang Project

% This function returns a vector specifying the
% indices of the suit and value of a playing card (for use
% in extracting the strings corresponding to suit
% and value from two vectors), given an image
% of the card as an input.  The image must be a 
% two-dimensional array of grayscale values represented
% as 8-bit unsigned integers.

% A set of library images are loaded as a workspace (library.mat).
% These contain the reference images for the suits (named club, diamond,
% heart, and spade) and the value (named one,two,three,four,five,six,seven
% eight,nine,ten,jack,queen,king,ace). The library images are represented
% as double floating-point matrices (needed for the correlation calculation).

load library;


% ********************************
% ********************************

% The next task is to extract from the card image the area in
% the card's upper left corner (ULC) which contains the information
% about the suit and value.  An window of width 30 and height 65, with it's
% ULC in the same position as the card's ULC, will take in the suit and value
% on any card. The coordinates of the ULC are the input argument vector ulcCoords.  
% These are then used to extract the card's ULC into the matrix
% infoArea. This matrix is then converted to a double-floating point matrix.

% Note: The function findspot called in identifyMultipleCards (which
% calls this function with returns from findspot) sometimes returns ULC's
% for windows in the lower right-hand of the card.  Sometimes these coordinates
% make the window exceed the matrix dimensions, so a check and fix for this
% is necessary.


sizeCardImage=size(cardImage);

windowWidth=35;
windowHeight=65;

startRow=ulcCoords(1,1);
bottomOverHang=startRow+windowHeight-sizeCardImage(1,1);
if (bottomOverHang>0)
   startRow=startRow-bottomOverHang;
end


startCol=ulcCoords(1,2);
rightOverHang=startCol+windowWidth-sizeCardImage(1,2);
if (rightOverHang>0)
   startCol=startCol-rightOverHang;
end


stopRow=startRow+windowHeight;
stopCol=startCol+windowWidth;

infoArea=double(cardImage(startRow:stopRow,startCol:stopCol));

infoAreaSize=size(infoArea);

infoAreaHeight=infoAreaSize(1,1);
infoAreaWidth=infoAreaSize(1,2);



%random test crap:
%imagesc(infoArea);
%colormap(gray(256));
%axis('square');


% ********************************
% ********************************


% Here's a brief description of the process used to identify the suit: A window of
% area 23x23 is moved over the infoArea.  At each windowing point, the correlation
% of the windowed image is taken with each of the four rightside-up library suit images.  The results
% of these successive correlations are stored in four vectors (clubCorrValues,heartCorrValues,
% etc.).  Then the correlation is taken with each of the four upside-down library suit images,
% and the results are again added to the four correlation vectors.  When the windowing 
% process is complete, the max of each of these four vectors
% is stored in the vector maxSuitCorrValues.  The index of the max of this vector is found, and
% it is returned for later use in selecting the appropriate string from a matrix of strings.

% The correlation process is as follows:  When two images are correlated, they are
% first reshaped as vectors and them normalized.  The inner product of the resulting 
% vectors is then taken to produce the correlation factor.

% First, we will reshape and normalize the suit library images.  This includes creating 
% library entries for upside-down suits by using the flipud() and fliplr() matrix operators.

UDclub=fliplr(flipud(club));
UDdiamond=fliplr(flipud(diamond));
UDheart=fliplr(flipud(heart));
UDspade=fliplr(flipud(spade));


club=club(:);
club=club./norm(club);

UDclub=UDclub(:);
UDclub=UDclub./norm(UDclub);

diamond=diamond(:);
diamond=diamond./norm(diamond);

UDdiamond=UDdiamond(:);
UDdiamond=UDdiamond./norm(UDdiamond);

heart=heart(:);
heart=heart./norm(heart);

UDheart=UDheart(:);
UDheart=UDheart./norm(UDheart);

spade=spade(:);
spade=spade./norm(spade);

UDspade=UDspade(:);
UDspade=UDspade./norm(UDspade);

% the windowing loop:


suitWindowHeight=23;
suitWindowWidth=23;

nextSuitCorrIndex=1;

%nextRowCorrIndex=1;
%nextColCorrIndex=1;


for n=1:(infoAreaHeight-suitWindowHeight)
   for m=1:(infoAreaWidth-suitWindowWidth)
      suitWindow=infoArea(n:(n+suitWindowHeight-1),m:(m+suitWindowWidth-1));
      suitWindow=suitWindow(:);
      suitWindow=suitWindow./norm(suitWindow);
            
      clubCorrValues(nextSuitCorrIndex)=dot(suitWindow,club);
      diamondCorrValues(nextSuitCorrIndex)=dot(suitWindow,diamond);
      heartCorrValues(nextSuitCorrIndex)=dot(suitWindow,heart);
      spadeCorrValues(nextSuitCorrIndex)=dot(suitWindow,spade);
      
      %spadeRowCorrIndices(nextRowCorrIndex)=n;
      %spadeColCorrIndices(nextColCorrIndex)=m;
      %nextRowCorrIndex=nextRowCorrIndex+1;
      %nextColCorrIndex=nextColCorrIndex+1;
      
      nextSuitCorrIndex=nextSuitCorrIndex+1;

      clubCorrValues(nextSuitCorrIndex)=dot(suitWindow,UDclub);
      diamondCorrValues(nextSuitCorrIndex)=dot(suitWindow,UDdiamond);
      heartCorrValues(nextSuitCorrIndex)=dot(suitWindow,UDheart);
      spadeCorrValues(nextSuitCorrIndex)=dot(suitWindow,UDspade);
      
      %spadeRowCorrIndices(nextRowCorrIndex)=n;
      %spadeColCorrIndices(nextColCorrIndex)=m;
      %nextRowCorrIndex=nextRowCorrIndex+1;
      %nextColCorrIndex=nextColCorrIndex+1;

      
      nextSuitCorrIndex=nextSuitCorrIndex+1;
   end
end

% collecting the max of each suit's correlation vector:
maxSuitCorrelations(1)=max(clubCorrValues);
maxSuitCorrelations(2)=max(diamondCorrValues);
maxSuitCorrelations(3)=max(heartCorrValues);
maxSuitCorrelations(4)=max(spadeCorrValues);


%[Y,I]=max(spadeCorrValues)

%size(spadeRowCorrIndices)
%size(spadeColCorrIndices)

%size(spadeCorrValues)

%theMaxSpadeCorrIndex=[spadeRowCorrIndices(1,I),spadeColCorrIndices(1,I)]


% finding the index of the max of maxSuitCorrelations and using it to
% select the suit name:
[maxSuitCorrValue,maxSuitCorrIndex]=max(maxSuitCorrelations);

suitIndex=maxSuitCorrIndex(1);



% ********************************
% ********************************

% Now, we will determine the value of the card.  
% Here's a brief description of the process used to identify the value: A window of
% area 21x29 is moved over the infoArea.  At each windowing point, the correlation
% of the windowed image is taken with each of the 13 rightside-up library suit images.  The results
% of these successive correlations are stored in 13 vectors (twoCorrValues,threeCorrValues,
% etc.).  Then the correlation process is repeated with the upside-down images, and the results
% are stored in each of the 13 correlation vectors.  When the windowing process is complete, 
% the max of each of these 13 vectors
% is stored in the vector maxValueCorrValues.  The index of the max of this vector is found, and
% it is returned for later use in selecting the appropriate string from a matrix of strings.

% The correlation process is as follows:  When two images are correlated, they are
% first reshaped as vectors and them normalized.  The inner product of the resulting 
% vectors is then taken to produce the correlation factor.

% First, we will reshape and normalize the value library images.  This includes defining the upside-
% down library images with the flipud() and fliplr() commands:

UDtwo=fliplr(flipud(two));
UDthree=fliplr(flipud(three));
UDfour=fliplr(flipud(four));
UDfive=fliplr(flipud(five));
UDsix=fliplr(flipud(six));
UDseven=fliplr(flipud(seven));
UDeight=fliplr(flipud(eight));
UDnine=fliplr(flipud(nine));
UDten=fliplr(flipud(ten));
UDjack=fliplr(flipud(jack));
UDqueen=fliplr(flipud(queen));
UDking=fliplr(flipud(king));
UDace=fliplr(flipud(ace));

two=two(:);
two=two./norm(two);

UDtwo=UDtwo(:);
UDtwo=UDtwo./norm(UDtwo);

three=three(:);
three=three./norm(three);

UDthree=UDthree(:);
UDthree=UDthree./norm(UDthree);

four=four(:);
four=four./norm(four);

UDfour=UDfour(:);
UDfour=UDfour./norm(UDfour);

five=five(:);
five=five./norm(five);

UDfive=UDfive(:);
UDfive=UDfive./norm(UDfive);

six=six(:);
six=six./norm(six);

UDsix=UDsix(:);
UDsix=UDsix./norm(UDsix);

seven=seven(:);
seven=seven./norm(seven);

UDseven=UDseven(:);
UDseven=UDseven./norm(UDseven);

eight=eight(:);
eight=eight./norm(eight);

UDeight=UDeight(:);
UDeight=UDeight./norm(UDeight);

nine=nine(:);
nine=nine./norm(nine);

UDnine=UDnine(:);
UDnine=UDnine./norm(UDnine);

ten=ten(:);
ten=ten./norm(ten);

UDten=UDten(:);
UDten=UDten./norm(UDten);

jack=jack(:);
jack=jack./norm(jack);

UDjack=UDjack(:);
UDjack=UDjack./norm(UDjack);

queen=queen(:);
queen=queen./norm(queen);

UDqueen=UDqueen(:);
UDqueen=UDqueen./norm(UDqueen);

king=king(:);
king=king./norm(king);

UDking=UDking(:);
UDking=UDking./norm(UDking);

ace=ace(:);
ace=ace./norm(ace);

UDace=UDace(:);
UDace=UDace./norm(UDace);


% the windowing loop:

valueWindowHeight=29;
valueWindowWidth=21;

nextValueCorrIndex=1;

for n=1:(infoAreaHeight-valueWindowHeight)
   for m=1:(infoAreaWidth-valueWindowWidth)
      valueWindow=infoArea(n:(n+valueWindowHeight-1),m:(m+valueWindowWidth-1));
      valueWindow=valueWindow(:);
      valueWindow=valueWindow./norm(valueWindow);
            
      twoCorrValues(nextValueCorrIndex)=dot(valueWindow,two);
      threeCorrValues(nextValueCorrIndex)=dot(valueWindow,three);
      fourCorrValues(nextValueCorrIndex)=dot(valueWindow,four);
      fiveCorrValues(nextValueCorrIndex)=dot(valueWindow,five);
      sixCorrValues(nextValueCorrIndex)=dot(valueWindow,six);
      sevenCorrValues(nextValueCorrIndex)=dot(valueWindow,seven);
      eightCorrValues(nextValueCorrIndex)=dot(valueWindow,eight);
      nineCorrValues(nextValueCorrIndex)=dot(valueWindow,nine);
      tenCorrValues(nextValueCorrIndex)=dot(valueWindow,ten);
      jackCorrValues(nextValueCorrIndex)=dot(valueWindow,jack);
      queenCorrValues(nextValueCorrIndex)=dot(valueWindow,queen);
      kingCorrValues(nextValueCorrIndex)=dot(valueWindow,king);
      aceCorrValues(nextValueCorrIndex)=dot(valueWindow,ace);
      
      nextValueCorrIndex=nextValueCorrIndex+1;
      
      twoCorrValues(nextValueCorrIndex)=dot(valueWindow,UDtwo);
      threeCorrValues(nextValueCorrIndex)=dot(valueWindow,UDthree);
      fourCorrValues(nextValueCorrIndex)=dot(valueWindow,UDfour);
      fiveCorrValues(nextValueCorrIndex)=dot(valueWindow,UDfive);
      sixCorrValues(nextValueCorrIndex)=dot(valueWindow,UDsix);
      sevenCorrValues(nextValueCorrIndex)=dot(valueWindow,UDseven);
      eightCorrValues(nextValueCorrIndex)=dot(valueWindow,UDeight);
      nineCorrValues(nextValueCorrIndex)=dot(valueWindow,UDnine);
      tenCorrValues(nextValueCorrIndex)=dot(valueWindow,UDten);
      jackCorrValues(nextValueCorrIndex)=dot(valueWindow,UDjack);
      queenCorrValues(nextValueCorrIndex)=dot(valueWindow,UDqueen);
      kingCorrValues(nextValueCorrIndex)=dot(valueWindow,UDking);
      aceCorrValues(nextValueCorrIndex)=dot(valueWindow,UDace);
      
      nextValueCorrIndex=nextValueCorrIndex+1;
   end
end

% collecting the max of each value's correlation vector:
maxValueCorrelations(1)=max(twoCorrValues);
maxValueCorrelations(2)=max(threeCorrValues);
maxValueCorrelations(3)=max(fourCorrValues);
maxValueCorrelations(4)=max(fiveCorrValues);
maxValueCorrelations(5)=max(sixCorrValues);
maxValueCorrelations(6)=max(sevenCorrValues);
maxValueCorrelations(7)=max(eightCorrValues);
maxValueCorrelations(8)=max(nineCorrValues);
maxValueCorrelations(9)=max(tenCorrValues);
maxValueCorrelations(10)=max(jackCorrValues);
maxValueCorrelations(11)=max(queenCorrValues);
maxValueCorrelations(12)=max(kingCorrValues);
maxValueCorrelations(13)=max(aceCorrValues);



% finding the index of the max of maxValueCorrelations and using it to
% select the value:
[maxValueCorrValue,maxValueCorrIndex]=max(maxValueCorrelations);

valueIndex=maxValueCorrIndex(1);

suitValueIndices=[valueIndex,suitIndex];


