%  This function is the decoding algorithm.  The function only has one
%  input:
%  image - encoded image that was encoded with encode.m
%  In the end, the function will output a binary vector of bits that were 
%  decoded from this image!

function [decoded] = decode(image);

sample = imread(image);

samplesize = size(sample);
rows = samplesize(1);
cols = samplesize(2);

sample0= sample(1:round(rows/2), 1:round(cols/2));
sample1= sample(1:round(rows/2), round(cols/2)+1:cols);
sample2= sample(round(rows/2)+1:rows, 1:round(cols/2));
sample3= sample(round(rows/2)+1:rows, round(cols/2)+1:cols);


rawsampdct0 = dct2(sample0);
rawsampdct1 = dct2(sample1);
rawsampdct2 = dct2(sample2);
rawsampdct3 = dct2(sample3);

blkrows = 1; %# of rows in each block (where one block represents one bit) 
blkcols = 16; %# or columns in each block
sideblkcols = 24;
blkcount = 12; %# of blocks to encode on each axis
blkspace = 2; %double spaced

horzshift = 50; %column at which the set of blocks on the horizontal axis starts
vertshift = 50; %row at which the set of blocks on the vertical axis starts

filter = ones(1,10);
offset = length(filter)/2;
discard = 2;  %number of high and low values to discard when taking mean of left and right
thold = 0.45;  %threshold for 1 or 0

lows = zeros(1,96);
highs = 10*ones(1,96);

%smooth with filter:

sampdct0 = zeros(size(rawsampdct0));
sampdct1 = zeros(size(rawsampdct1));
sampdct2 = zeros(size(rawsampdct2));
sampdct3 = zeros(size(rawsampdct3));

for i = 1:blkspace*blkcount+1,
   
   temp = conv(abs(rawsampdct0(i,:)),filter);
   sampdct0(i,:) = temp(offset:length(temp)-offset);
   
   temp = conv(abs(transpose(rawsampdct0(:,i))),filter);
   temp2 = temp(offset:length(temp)-offset);
   sampdct0(:,i) = transpose(temp2);
   
   temp = conv(abs(rawsampdct1(i,:)),filter);
   sampdct1(i,:) = temp(offset:length(temp)-offset);
   temp = conv(abs(transpose(rawsampdct1(:,i))),filter);
   temp2 = temp(offset:length(temp)-offset);
   sampdct1(:,i) = transpose(temp2);
   
   temp = conv(abs(rawsampdct2(i,:)),filter);
   sampdct2(i,:) = temp(offset:length(temp)-offset);
   temp = conv(abs(transpose(rawsampdct2(:,i))),filter);
   temp2 = temp(offset:length(temp)-offset);
   sampdct2(:,i) = transpose(temp2);
   
   temp = conv(abs(rawsampdct3(i,:)),filter);
   sampdct3(i,:) = temp(offset:length(temp)-offset);
   temp = conv(abs(transpose(rawsampdct3(:,i))),filter);
   temp2 = temp(offset:length(temp)-offset);
   sampdct3(:,i) = transpose(temp2);
   
end



for i = 1:blkcount,
   row = i*blkspace;
   col = horzshift;
   
   avg = sort(abs(sampdct0(row,col+blkcols/4:col+blkcols-1-blkcols/4)));
   avg0h = mean(avg(1:length(avg)-discard));
   left = sort(abs(sampdct0(row,col-sideblkcols:col-1)));
   avg0lefth = mean(left(1+discard:length(left)));
   right = sort(abs(sampdct0(row,col+blkcols:col+blkcols+sideblkcols-1)));
   avg0righth = mean(right(1+discard:length(right)));
   
   avg = sort(abs(sampdct1(row,col+blkcols/4:col+blkcols-1-blkcols/4)));
   avg1h = mean(avg(1:length(avg)-discard));
   left = sort(abs(sampdct1(row,col-sideblkcols:col-1)));
   avg1lefth = mean(left(1+discard:length(left)));
   right = sort(abs(sampdct1(row,col+blkcols:col+blkcols+sideblkcols-1)));
   avg1righth = mean(right(1+discard:length(right)));
   
   
   avg = sort(abs(sampdct2(row,col+blkcols/4:col+blkcols-1-blkcols/4)));
   avg2h = mean(avg(1:length(avg)-discard));
   left = sort(abs(sampdct2(row,col-sideblkcols:col-1)));
   avg2lefth = mean(left(1+discard:length(left)));
   right = sort(abs(sampdct2(row,col+blkcols:col+blkcols+sideblkcols-1)));
   avg2righth = mean(right(1+discard:length(right)));
   
   avg = sort(abs(sampdct3(row,col+blkcols/4:col+blkcols-1-blkcols/4)));
   avg3h = mean(avg(1:length(avg)-discard));
   left = sort(abs(sampdct3(row,col-sideblkcols:col-1)));
   avg3lefth = mean(left(1+discard:length(left))); 
   right = sort(abs(sampdct3(row,col+blkcols:col+blkcols+sideblkcols-1)));
   avg3righth = mean(right(1+discard:length(right)));
   
   
   if(avg0h/mean([avg0lefth avg0righth]) <= thold),
      decoded(i) = 1;
   else,
      decoded(i) = 0;
   end
   
   if(avg1h/mean([avg1lefth avg1righth]) <= thold),
      decoded(i+2*blkcount) = 1;
   else,
      decoded(i+2*blkcount) = 0;
   end
   
   if(avg2h/mean([avg2lefth avg2righth]) <= thold),
      decoded(i+4*blkcount) = 1;
   else,
      decoded(i+4*blkcount) = 0;
   end
   
   if(avg3h/mean([avg3lefth avg3righth]) <= thold),
      decoded(i+6*blkcount) = 1;
   else,
      decoded(i+6*blkcount) = 0;
   end
   
   
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  threshold test %%%%%%%%%%%%%%%%%%%%%%%%%
   if(code(i) == 1),
      lows(i) = (avg0h/mean([avg0lefth avg0righth]));
   else,
      highs(i) = (avg0h/mean([avg0lefth avg0righth]));
   end
   if(code(i+2*blkcount) == 1),
      lows(i+2*blkcount) = (avg1h/mean([avg1lefth avg1righth]));
   else,
      highs(i+2*blkcount) = (avg1h/mean([avg1lefth avg1righth]));
   end
   if(code(i+4*blkcount) == 1),
      lows(i+4*blkcount) = (avg2h/mean([avg2lefth avg2righth]));
   else,
      highs(i+4*blkcount) = (avg2h/mean([avg2lefth avg2righth]));
   end
   if(code(i+6*blkcount) == 1),
      lows(i+6*blkcount) = (avg3h/mean([avg3lefth avg3righth]));
   else,
      highs(i+6*blkcount) = (avg3h/mean([avg3lefth avg3righth]));
   end
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   
   
   row = vertshift;
   col = i*blkspace+1;
   
   avg = sort(abs(sampdct0(row+blkcols/4:row+blkcols-1-blkcols/4,col)));
   avg0v = mean(avg(1:length(avg)-discard));
   left = sort(abs(sampdct0(row-sideblkcols:row-1,col)));
   avg0leftv = mean(left(1+discard:length(left)));
   right = sort(abs(sampdct0(row+blkcols:row+blkcols+sideblkcols-1,col)));
   avg0rightv = mean(right(1+discard:length(right)));
   
   avg = sort(abs(sampdct1(row+blkcols/4:row+blkcols-1-blkcols/4,col)));
   avg1v = mean(avg(1:length(avg)-discard));
   left = sort(abs(sampdct1(row-sideblkcols:row-1,col)));
   avg1leftv = mean(left(1+discard:length(left)));
   right = sort(abs(sampdct1(row+blkcols:row+blkcols+sideblkcols-1,col)));
   avg1rightv = mean(right(1+discard:length(right)));
   
   avg = sort(abs(sampdct2(row+blkcols/4:row+blkcols-1-blkcols/4,col)));
   avg2v = mean(avg(1:length(avg)-discard));
   left = sort(abs(sampdct2(row-sideblkcols:row-1,col)));
   avg2leftv = mean(left(1+discard:length(left)));
   right = sort(abs(sampdct2(row+blkcols:row+blkcols+sideblkcols-1,col)));
   avg2rightv = mean(right(1+discard:length(right)));
   
   avg = sort(abs(sampdct3(row+blkcols/4:row+blkcols-1-blkcols/4,col)));
   avg3v = mean(avg(1:length(avg)-discard));
   left = sort(abs(sampdct3(row-sideblkcols:row-1,col)));
   avg3leftv = mean(left(1+discard:length(left)));
   right = sort(abs(sampdct3(row+blkcols:row+blkcols+sideblkcols-1,col)));
   avg3rightv = mean(right(1+discard:length(right)));
   
   
   if(avg0v/mean([avg0leftv avg0rightv]) <= thold),
      decoded(i+blkcount) = 1;
   else,
      decoded(i+blkcount) = 0;
   end
   
   if(avg1v/mean([avg1leftv avg1rightv]) <= thold),
      decoded(i+3*blkcount) = 1;
   else,
      decoded(i+3*blkcount) = 0;
   end
   
   if(avg2v/mean([avg2leftv avg2rightv]) <= thold),
      decoded(i+5*blkcount) = 1;
   else,
      decoded(i+5*blkcount) = 0;
   end
   
   if(avg3v/mean([avg3leftv avg3rightv]) <= thold),
      decoded(i+7*blkcount) = 1;
   else,
      decoded(i+7*blkcount) = 0;
   end
   
   
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  threshold test %%%%%%%%%%%%%%%%%%%%%%%%%
   if(code(i+blkcount) == 1),
      lows(i+blkcount) = (avg0v/mean([avg0leftv avg0rightv]));
   else,
      highs(i+blkcount) = (avg0v/mean([avg0leftv avg0rightv]));
   end
   if(code(i+3*blkcount) == 1),
      lows(i+3*blkcount) = (avg1v/mean([avg1leftv avg1rightv]));
   else,
      highs(i+3*blkcount) = (avg1v/mean([avg1leftv avg1rightv]));
   end
   if(code(i+5*blkcount) == 1),
      lows(i+5*blkcount) = (avg2v/mean([avg2leftv avg2rightv]));
   else,
      highs(i+5*blkcount) = (avg2v/mean([avg2leftv avg2rightv]));
   end
   if(code(i+7*blkcount) == 1),
      lows(i+7*blkcount) = (avg3v/mean([avg3leftv avg3rightv]));
   else,
      highs(i+7*blkcount) = (avg3v/mean([avg3leftv avg3rightv]));
   end
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   
   
end


highbound = min(highs)
lowbound = max(lows)

toolow = 0;
toohigh = 0;
belowthold = 0;
abovethold = 0;

for i=1:96,
   if(highs(i)<lowbound),
      toolow = toolow+1;
   end
   if(lows(i)>highbound),
      toohigh = toohigh+1;
   end
   if(highs(i)<thold),
      belowthold = belowthold+1;
   end
   if(lows(i)>thold),
      abovethold = abovethold+1;
   end
   
end

toolow
toohigh
belowthold
abovethold



%mesh(log(abs(sampdct0(1:100,1:100)))), view(2);
%figure;
%mesh(log(abs(sampdct1(1:100,1:100)))), view(2);
%figure;
%mesh(log(abs(sampdct2(1:100,1:100)))), view(2);
%figure;
%mesh(log(abs(sampdct3(1:100,1:100)))), view(2);

