function [contours, width, height] = bitstream2contour(bitstream)
% -------------------------------------------------------------------------
% MSc Project - MSc in Communications and Signal Processing
% Department of Electrical and Electronic Engineering
% Imperial College London, 2011
%
% Supervisor  : Dr Pier Luigi Dragotti
% Contributor : Andriy Gelman
% Author      : Jon Onativia Bravo
%
% File        : bitstream2contour.m
% -------------------------------------------------------------------------
% 
%
% [label_contours, width, height] = bitstream2contour(bitstream)
%
% INPUT:
%  - 
%
% OUTPUT:
%  - 
%

% Dictionary 
dict = cell(8,2);
dict{1,1} = 0;      dict{1,2} = [0];
dict{2,1} = 45;     dict{2,2} = [1 0];
dict{3,1} = -45;    dict{3,2} = [1 1 0];
dict{4,1} = 90;     dict{4,2} = [1 1 1 0];
dict{5,1} = -90;    dict{5,2} = [1 1 1 1 0];
dict{6,1}= 135;     dict{6,2} = [1 1 1 1 1 0];
dict{7,1} = -135;   dict{7,2} = [1 1 1 1 1 1 0];
dict{8,1} = 180;    dict{8,2} = [1 1 1 1 1 1 1];

b_idx = 1;

% Read size of the images
field_bits = 12;
width      = bin2dec(bitstream(b_idx:b_idx+field_bits-1), false);
b_idx      = b_idx + field_bits;
height     = bin2dec(bitstream(b_idx:b_idx+field_bits-1), false);
b_idx      = b_idx + field_bits;

% Obtain the number of layers
field_bits = 6;
num_layers = bin2dec(bitstream(b_idx:b_idx+field_bits-1), false);
b_idx      = b_idx + field_bits;

contours = cell(num_layers, 1);

for layer = 1 : num_layers
    
    % Obtain the number of segments for each layer
    field_bits  = 6;
    num_of_segs = bin2dec(bitstream(b_idx:b_idx+field_bits-1), false);
    b_idx       = b_idx + field_bits;
    
    verts = [];
    for ith_seg = 1 : num_of_segs
        [seg, b_idx] = decode_bitstream(bitstream, b_idx, dict);
        verts        = [verts, seg];
    end
    
    % Insert the segments into the output contours cell
    contours{layer} = verts;
end

end


function [seg, b_idx] = decode_bitstream(bitstream, b_idx, dict)     

% Obtain the length of the segment
field_bits  = 12;
seg_len     = bin2dec(bitstream(b_idx:b_idx+field_bits-1), false);
b_idx       = b_idx + field_bits;

% Allocate segment
seg = zeros(2, seg_len+1);
seg(2,1) = seg_len;

% Obtain the first vertex
field_bits  = 12;
seg(1,2)    = bin2dec(bitstream(b_idx:b_idx+field_bits-1), false);
b_idx       = b_idx + field_bits;
field_bits  = 12;
seg(2,2)    = bin2dec(bitstream(b_idx:b_idx+field_bits-1), false);
b_idx       = b_idx + field_bits;

% Decode the angles using the dictionary
num_words  = size(dict, 1);
prev_angle = 0;
for ith_vert = 2 : seg_len
    b_start = b_idx;
    
    for ith_word = 1 : num_words
        word  = dict{ith_word,2};
        b_end = b_idx + length(word) - 1;
        sub_stream = bitstream(b_start:b_end);
        if all(sub_stream == word)
            dif_angle = dict{ith_word,1};
            break;
        end
    end
    
    b_idx = b_end + 1;
    
    % Compute current angle and store it for next iteration
    angle      = prev_angle + dif_angle;
    prev_angle = angle;
    
    % Obtain x and y variations
    angle = angle / 180 * pi;
    direct = round(exp(1i * angle));
    dir_x  = real(direct);
    dir_y  = imag(direct);
    
    % Obtain next vertex
    seg(:,ith_vert+1) = seg(:,ith_vert) + [dir_x; dir_y];
end

end