tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/ccstruct/coutln.h
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:                                                coutln.c      (Formerly:  coutline.c)
00003  * Description: Code for the C_OUTLINE class.
00004  * Author:                                      Ray Smith
00005  * Created:                                     Mon Oct 07 16:01:57 BST 1991
00006  *
00007  * (C) Copyright 1991, 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 #ifndef           COUTLN_H
00021 #define           COUTLN_H
00022 
00023 #include          "crakedge.h"
00024 #include          "mod128.h"
00025 #include          "bits16.h"
00026 #include          "rect.h"
00027 #include          "blckerr.h"
00028 #include          "scrollview.h"
00029 
00030 class DENORM;
00031 
00032 #define INTERSECTING    MAX_INT16//no winding number
00033 
00034                                  //mask to get step
00035 #define STEP_MASK       3
00036 
00037 enum C_OUTLINE_FLAGS
00038 {
00039   COUT_INVERSE                   //White on black blob
00040 };
00041 
00042 // Simple struct to hold the 3 values needed to compute a more precise edge
00043 // position and direction. The offset_numerator is the difference between the
00044 // grey threshold and the mean pixel value. pixel_diff is the difference between
00045 // the pixels in the edge. Consider the following row of pixels: p1 p2 p3 p4 p5
00046 // Say the image was thresholded  at threshold t, making p1, p2, p3 black
00047 // and p4, p5 white (p1, p2, p3 < t, and p4, p5 >= t), but suppose that
00048 // max(p[i+1] - p[i]) is p3 - p2. Then the extrapolated position of the edge,
00049 // based on the maximum gradient, is at the crack between p2 and p3 plus the
00050 // offset (t - (p2+p3)/2)/(p3 - p2). We store the pixel difference p3-p2
00051 // denominator in pixel_diff and the offset numerator, relative to the original
00052 // binary edge (t - (p2+p3)/2) - (p3 -p2) in offset_numerator.
00053 // The sign of offset_numerator and pixel_diff are manipulated to ensure
00054 // that the pixel_diff, which will be used as a weight, is always positive.
00055 // The direction stores the quantized feature direction for the given step
00056 // computed from the edge gradient. (Using binary_angle_plus_pi.)
00057 // If the pixel_diff is zero, it means that the direction of the gradient
00058 // is in conflict with the step direction, so this step is to be ignored.
00059 struct EdgeOffset {
00060   inT8 offset_numerator;
00061   uinT8 pixel_diff;
00062   uinT8 direction;
00063 };
00064 
00065 class DLLSYM C_OUTLINE;          //forward declaration
00066 struct Pix;
00067 
00068 ELISTIZEH (C_OUTLINE)
00069 class DLLSYM C_OUTLINE:public ELIST_LINK {
00070  public:
00071   C_OUTLINE() {  //empty constructor
00072       steps = NULL;
00073       offsets = NULL;
00074     }
00075     C_OUTLINE(                     //constructor
00076               CRACKEDGE *startpt,  //from edge detector
00077               ICOORD bot_left,     //bounding box //length of loop
00078               ICOORD top_right,
00079               inT16 length);
00080     C_OUTLINE(ICOORD startpt,    //start of loop
00081               DIR128 *new_steps,  //steps in loop
00082               inT16 length);     //length of loop
00083                                  //outline to copy
00084     C_OUTLINE(C_OUTLINE *srcline, FCOORD rotation);  //and rotate
00085 
00086     // Build a fake outline, given just a bounding box and append to the list.
00087     static void FakeOutline(const TBOX& box, C_OUTLINE_LIST* outlines);
00088 
00089     ~C_OUTLINE () {              //destructor
00090       if (steps != NULL)
00091         free_mem(steps);
00092       steps = NULL;
00093       delete [] offsets;
00094     }
00095 
00096     BOOL8 flag(                               //test flag
00097                C_OUTLINE_FLAGS mask) const {  //flag to test
00098       return flags.bit (mask);
00099     }
00100     void set_flag(                       //set flag value
00101                   C_OUTLINE_FLAGS mask,  //flag to test
00102                   BOOL8 value) {         //value to set
00103       flags.set_bit (mask, value);
00104     }
00105 
00106     C_OUTLINE_LIST *child() {  //get child list
00107       return &children;
00108     }
00109 
00110                                  //access function
00111     const TBOX &bounding_box() const {
00112       return box;
00113     }
00114     void set_step(                    //set a step
00115                   inT16 stepindex,    //index of step
00116                   inT8 stepdir) {     //chain code
00117       int shift = stepindex%4 * 2;
00118       uinT8 mask = 3 << shift;
00119       steps[stepindex/4] = ((stepdir << shift) & mask) |
00120                            (steps[stepindex/4] & ~mask);
00121       //squeeze 4 into byte
00122     }
00123     void set_step(                    //set a step
00124                   inT16 stepindex,    //index of step
00125                   DIR128 stepdir) {   //direction
00126                                  //clean it
00127       inT8 chaindir = stepdir.get_dir() >> (DIRBITS - 2);
00128                                  //difference
00129       set_step(stepindex, chaindir);
00130       //squeeze 4 into byte
00131     }
00132 
00133     inT32 pathlength() const {  //get path length
00134       return stepcount;
00135     }
00136     // Return step at a given index as a DIR128.
00137     DIR128 step_dir(int index) const {
00138       return DIR128((inT16)(((steps[index/4] >> (index%4 * 2)) & STEP_MASK) <<
00139                       (DIRBITS - 2)));
00140     }
00141     // Return the step vector for the given outline position.
00142     ICOORD step(int index) const { // index of step
00143       return step_coords[chain_code(index)];
00144     }
00145                                  // get start position
00146     const ICOORD &start_pos() const {
00147       return start;
00148     }
00149     // Returns the position at the given index on the outline.
00150     // NOT to be used lightly, as it has to iterate the outline to find out.
00151     ICOORD position_at_index(int index) const {
00152       ICOORD pos = start;
00153       for (int i = 0; i < index; ++i)
00154         pos += step(i);
00155       return pos;
00156     }
00157     // Returns the sub-pixel accurate position given the integer position pos
00158     // at the given index on the outline. pos may be a return value of
00159     // position_at_index, or computed by repeatedly adding step to the
00160     // start_pos() in the usual way.
00161     FCOORD sub_pixel_pos_at_index(const ICOORD& pos, int index) const {
00162       const ICOORD& step_to_next(step(index));
00163       FCOORD f_pos(pos.x() + step_to_next.x() / 2.0f,
00164                    pos.y() + step_to_next.y() / 2.0f);
00165       if (offsets != NULL && offsets[index].pixel_diff > 0) {
00166         float offset = offsets[index].offset_numerator;
00167         offset /= offsets[index].pixel_diff;
00168         if (step_to_next.x() != 0)
00169           f_pos.set_y(f_pos.y() + offset);
00170         else
00171           f_pos.set_x(f_pos.x() + offset);
00172       }
00173       return f_pos;
00174     }
00175     // Returns the step direction for the given index or -1 if there is none.
00176     int direction_at_index(int index) const {
00177       if (offsets != NULL && offsets[index].pixel_diff > 0)
00178         return offsets[index].direction;
00179       return -1;
00180     }
00181     // Returns the edge strength for the given index.
00182     // If there are no recorded edge strengths, returns 1 (assuming the image
00183     // is binary). Returns 0 if the gradient direction conflicts with the
00184     // step direction, indicating that this position could be skipped.
00185     int edge_strength_at_index(int index) const {
00186       if (offsets != NULL)
00187         return offsets[index].pixel_diff;
00188       return 1;
00189     }
00190     // Return the step as a chain code (0-3) related to the standard feature
00191     // direction of binary_angle_plus_pi by:
00192     // chain_code * 64 = feature direction.
00193     int chain_code(int index) const {  // index of step
00194       return (steps[index / 4] >> (index % 4 * 2)) & STEP_MASK;
00195     }
00196 
00197     inT32 area() const;  // Returns area of self and 1st level children.
00198     inT32 perimeter() const;  // Total perimeter of self and 1st level children.
00199     inT32 outer_area() const;  // Returns area of self only.
00200     inT32 count_transitions(                   //count maxima
00201                             inT32 threshold);  //size threshold
00202 
00203     BOOL8 operator< (            //containment test
00204       const C_OUTLINE & other) const;
00205     BOOL8 operator> (            //containment test
00206       C_OUTLINE & other) const
00207     {
00208       return other < *this;      //use the < to do it
00209     }
00210     inT16 winding_number(                       //get winding number
00211                          ICOORD testpt) const;  //around this point
00212                                  //get direction
00213     inT16 turn_direction() const;
00214     void reverse();  //reverse direction
00215 
00216     void move(                    // reposition outline
00217               const ICOORD vec);  // by vector
00218 
00219     // Returns true if *this and its children are legally nested.
00220     // The outer area of a child should have the opposite sign to the
00221     // parent. If not, it means we have discarded an outline in between
00222     // (probably due to excessive length).
00223     bool IsLegallyNested() const;
00224 
00225     // If this outline is smaller than the given min_size, delete this and
00226     // remove from its list, via *it, after checking that *it points to this.
00227     // Otherwise, if any children of this are too small, delete them.
00228     // On entry, *it must be an iterator pointing to this. If this gets deleted
00229     // then this is extracted from *it, so an iteration can continue.
00230     void RemoveSmallRecursive(int min_size, C_OUTLINE_IT* it);
00231 
00232     // Adds sub-pixel resolution EdgeOffsets for the outline if the supplied
00233     // pix is 8-bit. Does nothing otherwise.
00234     void ComputeEdgeOffsets(int threshold, Pix* pix);
00235     // Adds sub-pixel resolution EdgeOffsets for the outline using only
00236     // a binary image source.
00237     void ComputeBinaryOffsets();
00238 
00239     // Renders the outline to the given pix, with left and top being
00240     // the coords of the upper-left corner of the pix.
00241     void render(int left, int top, Pix* pix) const;
00242 
00243     // Renders just the outline to the given pix (no fill), with left and top
00244     // being the coords of the upper-left corner of the pix.
00245     void render_outline(int left, int top, Pix* pix) const;
00246 
00247     #ifndef GRAPHICS_DISABLED
00248     void plot(                       //draw one
00249               ScrollView* window,         //window to draw in
00250               ScrollView::Color colour) const;  //colour to draw it
00251     // Draws the outline in the given colour, normalized using the given denorm,
00252     // making use of sub-pixel accurate information if available.
00253     void plot_normed(const DENORM& denorm, ScrollView::Color colour,
00254                      ScrollView* window) const;
00255     #endif  // GRAPHICS_DISABLED
00256 
00257     C_OUTLINE& operator=(const C_OUTLINE& source);
00258 
00259     static C_OUTLINE* deep_copy(const C_OUTLINE* src) {
00260       C_OUTLINE* outline = new C_OUTLINE;
00261       *outline = *src;
00262       return outline;
00263     }
00264 
00265     static ICOORD chain_step(int chaindir);
00266 
00267     // The maximum length of any outline. The stepcount is stored as 16 bits,
00268     // but it is probably not a good idea to increase this constant by much
00269     // and switch to 32 bits, as it plays an important role in keeping huge
00270     // outlines invisible, which prevents bad speed behavior.
00271     static const int kMaxOutlineLength = 16000;
00272 
00273   private:
00274     // Helper for ComputeBinaryOffsets. Increments pos, dir_counts, pos_totals
00275     // by the step, increment, and vertical step ? x : y position * increment
00276     // at step s Mod stepcount respectively. Used to add or subtract the
00277     // direction and position to/from accumulators of a small neighbourhood.
00278     void increment_step(int s, int increment, ICOORD* pos, int* dir_counts,
00279                         int* pos_totals) const;
00280     int step_mem() const { return (stepcount+3) / 4; }
00281 
00282     TBOX box;                    // bounding box
00283     ICOORD start;                // start coord
00284     inT16 stepcount;             // no of steps
00285     BITS16 flags;                // flags about outline
00286     uinT8 *steps;                // step array
00287     EdgeOffset* offsets;         // Higher precision edge.
00288     C_OUTLINE_LIST children;     // child elements
00289     static ICOORD step_coords[4];
00290 };
00291 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines