% PIONEER / VIDI Word Normalization
% Jerod Weinman jerod@acm.org
% 24 October 2014

% Key API procedures are TEXTFITGUIDES and NORMRECT as well as WORDCAT

% Load a text image built-in to Matlab
X=imread('text.png');

% Warp it a tad by rotating 30 degrees
Y = imrotate(im2double(X),30,'bicubic');
imgSize = size(Y);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Grouping-based normalization

% Define rectangles for two words "ridge that" to demonstrate the
% [non-]effects of grouping, descenders, and ascenders
rects = [108 84 47 34 ; ...
         153 61 38 31];

% For Nx4 rectangles matrix, wordcat finds groups of them on the
% same line
groups = wordcat(rects);

for g=1:length(groups) % For each group 
   
    % Create full-sized image to store only binarized word rectangles
    binImg = false(imgSize(1:2));

    for w=groups{g}
        rect = rects(w,:); % One-based rectangle location [L T W H]
    
        % Find rectangle borders
        top    = max(1,       rect(2));
        left   = max(1,       rect(1));
        bottom = min(imgSize(1), rect(2) + rect(4)-1);
        right  = min(imgSize(2), rect(1) + rect(3)-1);
    
        % Insert binarized word
        binImg(top:bottom, left:right) = binImg(top:bottom, left:right) | ...
            Y(top:bottom,left:right)>0.5;
        
    end    

    % Fit guides to each group of words
    guides = textfitguides( binImg, rects(groups{g},:), struct(), ...
                            struct() ); % Use default options
   
    % Show visualization of points
    figure;
    imshow(double(cat(3,guides.bottomsImg,guides.topsImg,guides.prunedImg)));
    title('Group Fit');
    hold on;
    
    % Add fit curves to visualization
    xx=min(rects(groups{g},1)):(max(sum(rects(groups{g},[1 3]),2))-1);
    yb=guides.bottom(3).*xx.^2 + guides.bottom(2).*xx + guides.bottom(1);
    yt=guides.top(3).*xx.^2 + guides.top(2).*xx + guides.top(1);    
    plot(xx,yb,'r');
    plot(xx,yt,'c');

    % Normalize word images (make believe that Y is a color image by
    % expanding it to three channels)
    img = Y(:,:,[1 1 1]);
    binImg = Y>0.5;

    for w=groups{g}
        [normRectImg, normBinImg,normPts] = normrect( img, binImg, guides, rects(w,:), ...
                                              struct(), struct() );
        
        figure; 
        imshow(normRectImg);
        title('Group Fit Normalized Word');
        normBounds = normPts.bounds; % [L R B H]
        rectangle('Position', [normBounds(1) normBounds(3)-normBounds(4) ...
                            normBounds(2)-normBounds(1) normBounds(4)], ...
                  'EdgeColor','r');
    end
        
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Normalization of individual words (less robust)

for w=1:size(rects,1) % For each word
   
    % Create full-sized image to store only word rectangle
    binImg = false(imgSize(1:2));
    rect = rects(w,:); % One-based rectangle location [L T W H]
    
    % Find rectangle borders
    top    = max(1,       rect(2));
    left   = max(1,       rect(1));
    bottom = min(imgSize(1), rect(2) + rect(4)-1);
    right  = min(imgSize(2), rect(1) + rect(3)-1);
    
    % Insert binarized word
    binImg(top:bottom, left:right) = binImg(top:bottom, left:right) | ...
        Y(top:bottom,left:right)>0.5;
    
    % Fit guides to each word
    guides = textfitguides( binImg, rect, struct(), struct() ); % Use defaults
   
    % Show visualization of points
    figure;
    imshow(double(cat(3,guides.bottomsImg,guides.topsImg,guides.prunedImg)));
    title('Individual Word Fit');
    hold on;
    
    % Add fit curves to visualization
    xx=min(rect(1)):(max(sum(rect([1 3]),2))-1);
    yb=guides.bottom(3).*xx.^2 + guides.bottom(2).*xx + guides.bottom(1);
    yt=guides.top(3).*xx.^2 + guides.top(2).*xx + guides.top(1);    
    plot(xx,yb,'r');
    plot(xx,yt,'c');

    % Normalize word images (make believe that Y is a color image by
    % expanding it to three channels)
    img = Y(:,:,[1 1 1]);
    binImg = Y>0.5;

    [normRectImg, normBinImg,normPts] = normrect( img, binImg, guides, rect, ...
                                                  struct(), struct() );
        
    figure; 
    imshow(normRectImg);
    title('Individual Fit Normalized Word');
    normBounds = normPts.bounds; % [L R B H]
    rectangle('Position', [normBounds(1) normBounds(3)-normBounds(4) ...
                        normBounds(2)-normBounds(1) normBounds(4)], ...
              'EdgeColor','r');
end
        
