function [base_coeff,top_coeff,pruned_img,bottoms_img,tops_img,base_evidence,top_evidence] = ...
      basetoplocal3(bin_img,deg,rects,U,tol)
% BASETOPLOCAL3 Robust text baseline regression and character height estimation
%
%   [COEFF,DIST,PRUNED_IMG,BOTTOMS_IMG,TOPS_IMG,DISTANCES] =
%   BASETOPLOCAL3(BIN_IMG, DEG, RECTS,U,TOL) returns a vector, COEFF,
%   of length DEG containing the coefficients, [c b] or [c b a], of
%   the baseline of the binarized text contained in BIN_IMG. In the
%   case when DEG=2, the baseline coefficients, COEFF, are from the
%   quadratic model y = ax^2 + bx + c. When DEG=1, the coefficients
%   COEFF are from a linear model y=b*x+c. The coefficient's
%   coordinates are with respect to the image coordinate system. DIST
%   measures the typical (median) distance between the bottom and top
%   of a character along a normal of the curve. Note this is not
%   synonymous with font height. RECTS is an Nx4 matrix whose rows
%   contain [x y w h] word bounding box coordinates. U is an optional
%   scalar uniform outlier negative log probability. TOL is a
%   2x(DEG+1) matrix containing the tolerance (variance) for normal
%   deviation from the coefficients of the prior guide curve, which is
%   typically a robust fit to the pruned binary image for the base
%   guide (first row of tol), and the resulting base guide for the top
%   guide (second row of tol).
%
%   Overview:
%
%   1. initregress() - The algorithm first runs a regression on all points
%   with value 1 from the original binarized image.
%
%   2. pruneregress() - Next the algorithm prunes the image by taking only
%   the connected components that intersect the curve from the first
%   regression. It reruns a regression on the pruned binary image.
%
%   3. normalextremalocal() - This finds the extremal "bottom" and
%   corresponding "top" points of the text along the local normal,
%   calculating character heights.
%
%   4. baseregress() - Runs a robust regression using the pruned regression
%   as its priors.  It regresses over the bottom points.
%
%   BASETOPLOCAL3 uses the method described in Section 5 of the following article:
%
%     J. Weinman, Z. Butler, D. Knoll, and J. Feild, Toward Integrated Scene Text
%     Reading. IEEE TPAMI 36(2):375--387, 2014.doi:10.1109/TPAMI.2013.126
%
%
%   See also INITREGRESS, PARABOLICREGRESS, PRUNEREGRESS, REGRESS,
%   BASEREGRESS.
%

% Copyright (c) 2012
% Jerod Weinman
% jerod@acm.org

% $Id: basetoplocal3.m 594 2014-10-24 12:04:55Z weinman $
 
% Jerod Weinman, Zach Butler, Dugan Knoll, Alexander Turner, Yirong Jing
% jerod@acm.org
% Copyright 2011, 2012, 2013, 2014
 
%    This file is part of PIONEER WordNorm.
%
%    PIONEER WordNorm is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    PIONEER WordNorm is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with PIONEER WordNorm.  If not, see <http://www.gnu.org/licenses/>.



  base_evidence = -Inf;
  top_evidence = -Inf;
  
  % Perform an initial regression using all points in the image
  init_coeff = initregress(bin_img,deg,rects);

  if ~anyv(bin_img) % No points in binary image
    pruned_img = bin_img;
    bottoms_img = bin_img;
    tops_img = bin_img;
    base_coeff = init_coeff;
    top_coeff = init_coeff;
    top_coeff(1) = top_coeff(1) - mean(rects(:,4));
    return;
  end;
  
  % Prune the points and perform a regression on what remains
  [base_coeff,pruned_img] = pruneregress(bin_img,init_coeff);

  % Extend coefficients for compatibility
  if deg==1
    base_coeff(3) = 0;
  end
  
  % Use the curve to project the normal along the outline of the bottom points
  [bottoms_img,tops_img] = normalextremalocal(pruned_img,base_coeff);

  
  if sumv(bottoms_img)==0 % Geometric projections failed.
    base_coeff = init_coeff;
    
    % Extend coefficients for compatibility
    if deg==1
      base_coeff(3) = 0;
    end

    % Use original, rather than pruned image
    [bottoms_img, tops_img] = normalextremalocal(bin_img,base_coeff);
  
    if sumv(bottoms_img)==0 % Geometric projections still failed.
        % Do regression on rectangle points
        base_coeff = initregress(bottoms_img,deg,rects);
        tops_img = bottoms_img;
        top_coeff = base_coeff;
        top_coeff(1) = top_coeff(1) - mean(rects(:,4));
        return
    end;
  end;
  
  % Translate the curve vertically to match these bottom points
  base_coeff(1) = adjustoffset(bottoms_img,base_coeff);

  % Un-extend coefficients
  base_coeff = base_coeff(1:deg+1);
  
  % Run a robust regression on the bottom points using the prior curve 
  [base_coeff,base_evidence] = baseregress(bottoms_img,base_coeff,rects, ...
                                           tol(1,:), U);
  
  % Run a regression on the top points
  distances = getdistances(base_coeff,tops_img);
  [top_coeff,top_evidence] = topregress(tops_img, base_coeff, distances, ...
                                        rects, tol(2,:), U);  
end % if
