tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/ccstruct/quadlsq.cpp
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        quadlsq.cpp  (Formerly qlsq.c)
00003  * Description: Code for least squares approximation of quadratics.
00004  * Author:              Ray Smith
00005  * Created:             Wed Oct  6 15:14:23 BST 1993
00006  *
00007  * (C) Copyright 1993, Hewlett-Packard Ltd.
00008  ** Licensed under the Apache License, Version 2.0 (the "License");
00009  ** you may not use this file except in compliance with the License.
00010  ** You may obtain a copy of the License at
00011  ** http://www.apache.org/licenses/LICENSE-2.0
00012  ** Unless required by applicable law or agreed to in writing, software
00013  ** distributed under the License is distributed on an "AS IS" BASIS,
00014  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  ** See the License for the specific language governing permissions and
00016  ** limitations under the License.
00017  *
00018  **********************************************************************/
00019 
00020 #include <stdio.h>
00021 #include <math.h>
00022 #include "quadlsq.h"
00023 #include "tprintf.h"
00024 
00025 // Minimum variance in least squares before backing off to a lower degree.
00026 const double kMinVariance = 1.0 / 1024;
00027 
00028 /**********************************************************************
00029  * QLSQ::clear
00030  *
00031  * Function to initialize a QLSQ.
00032  **********************************************************************/
00033 
00034 void QLSQ::clear() {  // initialize
00035   a = 0.0;
00036   b = 0.0;
00037   c = 0.0;
00038   n = 0;                           // No elements.
00039   sigx = 0.0;                      // Zero accumulators.
00040   sigy = 0.0;
00041   sigxx = 0.0;
00042   sigxy = 0.0;
00043   sigyy = 0.0;
00044   sigxxx = 0.0;
00045   sigxxy = 0.0;
00046   sigxxxx = 0.0;
00047 }
00048 
00049 
00050 /**********************************************************************
00051  * QLSQ::add
00052  *
00053  * Add an element to the accumulator.
00054  **********************************************************************/
00055 
00056 void QLSQ::add(double x, double y) {
00057   n++;                           // Count elements.
00058   sigx += x;                     // Update accumulators.
00059   sigy += y;
00060   sigxx += x * x;
00061   sigxy += x * y;
00062   sigyy += y * y;
00063   sigxxx += static_cast<long double>(x) * x * x;
00064   sigxxy += static_cast<long double>(x) * x * y;
00065   sigxxxx += static_cast<long double>(x) * x * x * x;
00066 }
00067 
00068 
00069 /**********************************************************************
00070  * QLSQ::remove
00071  *
00072  * Delete an element from the accumulator.
00073  **********************************************************************/
00074 
00075 void QLSQ::remove(double x, double y) {
00076   if (n <= 0) {
00077     tprintf("Can't remove an element from an empty QLSQ accumulator!\n");
00078     return;
00079   }
00080   n--;                           // Count elements.
00081   sigx -= x;                     // Update accumulators.
00082   sigy -= y;
00083   sigxx -= x * x;
00084   sigxy -= x * y;
00085   sigyy -= y * y;
00086   sigxxx -= static_cast<long double>(x) * x * x;
00087   sigxxy -= static_cast<long double>(x) * x * y;
00088   sigxxxx -= static_cast<long double>(x) * x * x * x;
00089 }
00090 
00091 
00092 /**********************************************************************
00093  * QLSQ::fit
00094  *
00095  * Fit the given degree of polynomial and store the result.
00096  * This creates a quadratic of the form axx + bx + c, but limited to
00097  * the given degree.
00098  **********************************************************************/
00099 
00100 void QLSQ::fit(int degree) {
00101   long double x_variance = static_cast<long double>(sigxx) * n -
00102       static_cast<long double>(sigx) * sigx;
00103 
00104   // Note: for computational efficiency, we do not normalize the variance,
00105   // covariance and cube variance here as they are in the same order in both
00106   // nominators and denominators. However, we need be careful in value range
00107   // check.
00108   if (x_variance < kMinVariance * n * n || degree < 1 || n < 2) {
00109     // We cannot calculate b reliably so forget a and b, and just work on c.
00110     a = b = 0.0;
00111     if (n >= 1 && degree >= 0) {
00112       c = sigy / n;
00113     } else {
00114       c = 0.0;
00115     }
00116     return;
00117   }
00118   long double top96 = 0.0;       // Accurate top.
00119   long double bottom96 = 0.0;    // Accurate bottom.
00120   long double cubevar = sigxxx * n - static_cast<long double>(sigxx) * sigx;
00121   long double covariance = static_cast<long double>(sigxy) * n -
00122       static_cast<long double>(sigx) * sigy;
00123 
00124   if (n >= 4 && degree >= 2) {
00125     top96 = cubevar * covariance;
00126     top96 += x_variance * (static_cast<long double>(sigxx) * sigy - sigxxy * n);
00127 
00128     bottom96 = cubevar * cubevar;
00129     bottom96 -= x_variance *
00130         (sigxxxx * n - static_cast<long double>(sigxx) * sigxx);
00131   }
00132   if (bottom96 >= kMinVariance * n * n * n * n) {
00133     // Denominators looking good
00134     a = top96 / bottom96;
00135     top96 = covariance - cubevar * a;
00136     b = top96 / x_variance;
00137   } else {
00138     // Forget a, and concentrate on b.
00139     a = 0.0;
00140     b = covariance / x_variance;
00141   }
00142   c = (sigy - a * sigxx - b * sigx) / n;
00143 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines