tesseract
3.03
|
00001 /********************************************************************** 00002 * File: normalis.cpp (Formerly denorm.c) 00003 * Description: Code for the DENORM class. 00004 * Author: Ray Smith 00005 * Created: Thu Apr 23 09:22:43 BST 1992 00006 * 00007 * (C) Copyright 1992, 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 "normalis.h" 00021 00022 #include <stdlib.h> 00023 00024 #include "allheaders.h" 00025 #include "blobs.h" 00026 #include "helpers.h" 00027 #include "matrix.h" 00028 #include "ocrblock.h" 00029 #include "unicharset.h" 00030 #include "werd.h" 00031 00032 // Tolerance in pixels used for baseline and xheight on non-upper/lower scripts. 00033 const int kSloppyTolerance = 4; 00034 // Final tolerance in pixels added to the computed xheight range. 00035 const float kFinalPixelTolerance = 0.125f; 00036 00037 DENORM::DENORM() { 00038 Init(); 00039 } 00040 00041 DENORM::DENORM(const DENORM &src) { 00042 rotation_ = NULL; 00043 *this = src; 00044 } 00045 00046 00047 DENORM & DENORM::operator=(const DENORM & src) { 00048 Clear(); 00049 inverse_ = src.inverse_; 00050 predecessor_ = src.predecessor_; 00051 pix_ = src.pix_; 00052 block_ = src.block_; 00053 if (src.rotation_ == NULL) 00054 rotation_ = NULL; 00055 else 00056 rotation_ = new FCOORD(*src.rotation_); 00057 x_origin_ = src.x_origin_; 00058 y_origin_ = src.y_origin_; 00059 x_scale_ = src.x_scale_; 00060 y_scale_ = src.y_scale_; 00061 final_xshift_ = src.final_xshift_; 00062 final_yshift_ = src.final_yshift_; 00063 return *this; 00064 } 00065 00066 DENORM::~DENORM() { 00067 Clear(); 00068 } 00069 00070 // Initializes the denorm for a transformation. For details see the large 00071 // comment in normalis.h. 00072 // Arguments: 00073 // block: if not NULL, then this is the first transformation, and 00074 // block->re_rotation() needs to be used after the Denorm 00075 // transformation to get back to the image coords. 00076 // rotation: if not NULL, apply this rotation after translation to the 00077 // origin and scaling. (Usually a classify rotation.) 00078 // predecessor: if not NULL, then predecessor has been applied to the 00079 // input space and needs to be undone to complete the inverse. 00080 // The above pointers are not owned by this DENORM and are assumed to live 00081 // longer than this denorm, except rotation, which is deep copied on input. 00082 // 00083 // x_origin: The x origin which will be mapped to final_xshift in the result. 00084 // y_origin: The y origin which will be mapped to final_yshift in the result. 00085 // Added to result of row->baseline(x) if not NULL. 00086 // 00087 // x_scale: scale factor for the x-coordinate. 00088 // y_scale: scale factor for the y-coordinate. Ignored if segs is given. 00089 // Note that these scale factors apply to the same x and y system as the 00090 // x-origin and y-origin apply, ie after any block rotation, but before 00091 // the rotation argument is applied. 00092 // 00093 // final_xshift: The x component of the final translation. 00094 // final_yshift: The y component of the final translation. 00095 void DENORM::SetupNormalization(const BLOCK* block, 00096 const FCOORD* rotation, 00097 const DENORM* predecessor, 00098 float x_origin, float y_origin, 00099 float x_scale, float y_scale, 00100 float final_xshift, float final_yshift) { 00101 Clear(); 00102 block_ = block; 00103 if (rotation == NULL) 00104 rotation_ = NULL; 00105 else 00106 rotation_ = new FCOORD(*rotation); 00107 predecessor_ = predecessor; 00108 x_origin_ = x_origin; 00109 y_origin_ = y_origin; 00110 x_scale_ = x_scale; 00111 y_scale_ = y_scale; 00112 final_xshift_ = final_xshift; 00113 final_yshift_ = final_yshift; 00114 } 00115 00116 // Helper for SetupNonLinear computes an image of shortest run-lengths from 00117 // the x/y edges provided. 00118 // Based on "A nonlinear normalization method for handprinted Kanji character 00119 // recognition -- line density equalization" by Hiromitsu Yamada et al. 00120 // Eg below is an O in a 1-pixel margin-ed bounding box and the corresponding 00121 // ______________ input x_coords and y_coords. 00122 // | _________ | <empty> 00123 // | | _ | | 1, 6 00124 // | | | | | | 1, 3, 4, 6 00125 // | | | | | | 1, 3, 4, 6 00126 // | | | | | | 1, 3, 4, 6 00127 // | | |_| | | 1, 3, 4, 6 00128 // | |_________| | 1, 6 00129 // |_____________| <empty> 00130 // E 1 1 1 1 1 E 00131 // m 7 7 2 7 7 m 00132 // p 6 p 00133 // t 7 t 00134 // y y 00135 // The output image contains the min of the x and y run-length (distance 00136 // between edges) at each coordinate in the image thus: 00137 // ______________ 00138 // |7 1_1_1_1_1 7| 00139 // |1|5 5 1 5 5|1| 00140 // |1|2 2|1|2 2|1| 00141 // |1|2 2|1|2 2|1| 00142 // |1|2 2|1|2 2|1| 00143 // |1|2 2|1|2 2|1| 00144 // |1|5_5_1_5_5|1| 00145 // |7_1_1_1_1_1_7| 00146 // Note that the input coords are all integer, so all partial pixels are dealt 00147 // with elsewhere. Although it is nice for outlines to be properly connected 00148 // and continuous, there is no requirement that they be as such, so they could 00149 // have been derived from a flaky source, such as greyscale. 00150 // This function works only within the provided box, and it is assumed that the 00151 // input x_coords and y_coords have already been translated to have the bottom- 00152 // left of box as the origin. Although an output, the minruns should have been 00153 // pre-initialized to be the same size as box. Each element will contain the 00154 // minimum of x and y run-length as shown above. 00155 static void ComputeRunlengthImage( 00156 const TBOX& box, 00157 const GenericVector<GenericVector<int> >& x_coords, 00158 const GenericVector<GenericVector<int> >& y_coords, 00159 GENERIC_2D_ARRAY<int>* minruns) { 00160 int width = box.width(); 00161 int height = box.height(); 00162 ASSERT_HOST(minruns->dim1() == width); 00163 ASSERT_HOST(minruns->dim2() == height); 00164 // Set a 2-d image array to the run lengths at each pixel. 00165 for (int ix = 0; ix < width; ++ix) { 00166 int y = 0; 00167 for (int i = 0; i < y_coords[ix].size(); ++i) { 00168 int y_edge = ClipToRange(y_coords[ix][i], 0, height); 00169 int gap = y_edge - y; 00170 // Every pixel between the last and current edge get set to the gap. 00171 while (y < y_edge) { 00172 (*minruns)(ix, y) = gap; 00173 ++y; 00174 } 00175 } 00176 // Pretend there is a bounding box of edges all around the image. 00177 int gap = height - y; 00178 while (y < height) { 00179 (*minruns)(ix, y) = gap; 00180 ++y; 00181 } 00182 } 00183 // Now set the image pixels the the MIN of the x and y runlengths. 00184 for (int iy = 0; iy < height; ++iy) { 00185 int x = 0; 00186 for (int i = 0; i < x_coords[iy].size(); ++i) { 00187 int x_edge = ClipToRange(x_coords[iy][i], 0, width); 00188 int gap = x_edge - x; 00189 while (x < x_edge) { 00190 if (gap < (*minruns)(x, iy)) 00191 (*minruns)(x, iy) = gap; 00192 ++x; 00193 } 00194 } 00195 int gap = width - x; 00196 while (x < width) { 00197 if (gap < (*minruns)(x, iy)) 00198 (*minruns)(x, iy) = gap; 00199 ++x; 00200 } 00201 } 00202 } 00203 // Converts the run-length image (see above to the edge density profiles used 00204 // for scaling, thus: 00205 // ______________ 00206 // |7 1_1_1_1_1 7| = 5.28 00207 // |1|5 5 1 5 5|1| = 3.8 00208 // |1|2 2|1|2 2|1| = 5 00209 // |1|2 2|1|2 2|1| = 5 00210 // |1|2 2|1|2 2|1| = 5 00211 // |1|2 2|1|2 2|1| = 5 00212 // |1|5_5_1_5_5|1| = 3.8 00213 // |7_1_1_1_1_1_7| = 5.28 00214 // 6 4 4 8 4 4 6 00215 // . . . . . . . 00216 // 2 4 4 0 4 4 2 00217 // 8 8 00218 // Each profile is the sum of the reciprocals of the pixels in the image in 00219 // the appropriate row or column, and these are then normalized to sum to 1. 00220 // On output hx, hy contain an extra element, which will eventually be used 00221 // to guarantee that the top/right edge of the box (and anything beyond) always 00222 // gets mapped to the maximum target coordinate. 00223 static void ComputeEdgeDensityProfiles(const TBOX& box, 00224 const GENERIC_2D_ARRAY<int>& minruns, 00225 GenericVector<float>* hx, 00226 GenericVector<float>* hy) { 00227 int width = box.width(); 00228 int height = box.height(); 00229 hx->init_to_size(width + 1, 0.0); 00230 hy->init_to_size(height + 1, 0.0); 00231 double total = 0.0; 00232 for (int iy = 0; iy < height; ++iy) { 00233 for (int ix = 0; ix < width; ++ix) { 00234 int run = minruns(ix, iy); 00235 if (run == 0) run = 1; 00236 float density = 1.0f / run; 00237 (*hx)[ix] += density; 00238 (*hy)[iy] += density; 00239 } 00240 total += (*hy)[iy]; 00241 } 00242 // Normalize each profile to sum to 1. 00243 if (total > 0.0) { 00244 for (int ix = 0; ix < width; ++ix) { 00245 (*hx)[ix] /= total; 00246 } 00247 for (int iy = 0; iy < height; ++iy) { 00248 (*hy)[iy] /= total; 00249 } 00250 } 00251 // There is an extra element in each array, so initialize to 1. 00252 (*hx)[width] = 1.0f; 00253 (*hy)[height] = 1.0f; 00254 } 00255 00256 // Sets up the DENORM to execute a non-linear transformation based on 00257 // preserving an even distribution of stroke edges. The transformation 00258 // operates only within the given box. 00259 // x_coords is a collection of the x-coords of vertical edges for each 00260 // y-coord starting at box.bottom(). 00261 // y_coords is a collection of the y-coords of horizontal edges for each 00262 // x-coord starting at box.left(). 00263 // Eg x_coords[0] is a collection of the x-coords of edges at y=bottom. 00264 // Eg x_coords[1] is a collection of the x-coords of edges at y=bottom + 1. 00265 // The second-level vectors must all be sorted in ascending order. 00266 // See comments on the helper functions above for more details. 00267 void DENORM::SetupNonLinear( 00268 const DENORM* predecessor, const TBOX& box, float target_width, 00269 float target_height, float final_xshift, float final_yshift, 00270 const GenericVector<GenericVector<int> >& x_coords, 00271 const GenericVector<GenericVector<int> >& y_coords) { 00272 Clear(); 00273 predecessor_ = predecessor; 00274 // x_map_ and y_map_ store a mapping from input x and y coordinate to output 00275 // x and y coordinate, based on scaling to the supplied target_width and 00276 // target_height. 00277 x_map_ = new GenericVector<float>; 00278 y_map_ = new GenericVector<float>; 00279 // Set a 2-d image array to the run lengths at each pixel. 00280 int width = box.width(); 00281 int height = box.height(); 00282 GENERIC_2D_ARRAY<int> minruns(width, height, 0); 00283 ComputeRunlengthImage(box, x_coords, y_coords, &minruns); 00284 // Edge density is the sum of the inverses of the run lengths. Compute 00285 // edge density projection profiles. 00286 ComputeEdgeDensityProfiles(box, minruns, x_map_, y_map_); 00287 // Convert the edge density profiles to the coordinates by multiplying by 00288 // the desired size and accumulating. 00289 (*x_map_)[width] = target_width; 00290 for (int x = width - 1; x >= 0; --x) { 00291 (*x_map_)[x] = (*x_map_)[x + 1] - (*x_map_)[x] * target_width; 00292 } 00293 (*y_map_)[height] = target_height; 00294 for (int y = height - 1; y >= 0; --y) { 00295 (*y_map_)[y] = (*y_map_)[y + 1] - (*y_map_)[y] * target_height; 00296 } 00297 x_origin_ = box.left(); 00298 y_origin_ = box.bottom(); 00299 final_xshift_ = final_xshift; 00300 final_yshift_ = final_yshift; 00301 } 00302 00303 // Transforms the given coords one step forward to normalized space, without 00304 // using any block rotation or predecessor. 00305 void DENORM::LocalNormTransform(const TPOINT& pt, TPOINT* transformed) const { 00306 FCOORD src_pt(pt.x, pt.y); 00307 FCOORD float_result; 00308 LocalNormTransform(src_pt, &float_result); 00309 transformed->x = IntCastRounded(float_result.x()); 00310 transformed->y = IntCastRounded(float_result.y()); 00311 } 00312 void DENORM::LocalNormTransform(const FCOORD& pt, FCOORD* transformed) const { 00313 FCOORD translated(pt.x() - x_origin_, pt.y() - y_origin_); 00314 if (x_map_ != NULL && y_map_ != NULL) { 00315 int x = ClipToRange(IntCastRounded(translated.x()), 0, x_map_->size()-1); 00316 translated.set_x((*x_map_)[x]); 00317 int y = ClipToRange(IntCastRounded(translated.y()), 0, y_map_->size()-1); 00318 translated.set_y((*y_map_)[y]); 00319 } else { 00320 translated.set_x(translated.x() * x_scale_); 00321 translated.set_y(translated.y() * y_scale_); 00322 if (rotation_ != NULL) 00323 translated.rotate(*rotation_); 00324 } 00325 transformed->set_x(translated.x() + final_xshift_); 00326 transformed->set_y(translated.y() + final_yshift_); 00327 } 00328 00329 // Transforms the given coords forward to normalized space using the 00330 // full transformation sequence defined by the block rotation, the 00331 // predecessors, deepest first, and finally this. If first_norm is not NULL, 00332 // then the first and deepest transformation used is first_norm, ending 00333 // with this, and the block rotation will not be applied. 00334 void DENORM::NormTransform(const DENORM* first_norm, const TPOINT& pt, 00335 TPOINT* transformed) const { 00336 FCOORD src_pt(pt.x, pt.y); 00337 FCOORD float_result; 00338 NormTransform(first_norm, src_pt, &float_result); 00339 transformed->x = IntCastRounded(float_result.x()); 00340 transformed->y = IntCastRounded(float_result.y()); 00341 } 00342 void DENORM::NormTransform(const DENORM* first_norm, const FCOORD& pt, 00343 FCOORD* transformed) const { 00344 FCOORD src_pt(pt); 00345 if (first_norm != this) { 00346 if (predecessor_ != NULL) { 00347 predecessor_->NormTransform(first_norm, pt, &src_pt); 00348 } else if (block_ != NULL) { 00349 FCOORD fwd_rotation(block_->re_rotation().x(), 00350 -block_->re_rotation().y()); 00351 src_pt.rotate(fwd_rotation); 00352 } 00353 } 00354 LocalNormTransform(src_pt, transformed); 00355 } 00356 00357 // Transforms the given coords one step back to source space, without 00358 // using to any block rotation or predecessor. 00359 void DENORM::LocalDenormTransform(const TPOINT& pt, TPOINT* original) const { 00360 FCOORD src_pt(pt.x, pt.y); 00361 FCOORD float_result; 00362 LocalDenormTransform(src_pt, &float_result); 00363 original->x = IntCastRounded(float_result.x()); 00364 original->y = IntCastRounded(float_result.y()); 00365 } 00366 void DENORM::LocalDenormTransform(const FCOORD& pt, FCOORD* original) const { 00367 FCOORD rotated(pt.x() - final_xshift_, pt.y() - final_yshift_); 00368 if (x_map_ != NULL && y_map_ != NULL) { 00369 int x = x_map_->binary_search(rotated.x()); 00370 original->set_x(x + x_origin_); 00371 int y = y_map_->binary_search(rotated.y()); 00372 original->set_y(y + y_origin_); 00373 } else { 00374 if (rotation_ != NULL) { 00375 FCOORD inverse_rotation(rotation_->x(), -rotation_->y()); 00376 rotated.rotate(inverse_rotation); 00377 } 00378 original->set_x(rotated.x() / x_scale_ + x_origin_); 00379 float y_scale = y_scale_; 00380 original->set_y(rotated.y() / y_scale + y_origin_); 00381 } 00382 } 00383 00384 // Transforms the given coords all the way back to source image space using 00385 // the full transformation sequence defined by this and its predecesors 00386 // recursively, shallowest first, and finally any block re_rotation. 00387 // If last_denorm is not NULL, then the last transformation used will 00388 // be last_denorm, and the block re_rotation will never be executed. 00389 void DENORM::DenormTransform(const DENORM* last_denorm, const TPOINT& pt, 00390 TPOINT* original) const { 00391 FCOORD src_pt(pt.x, pt.y); 00392 FCOORD float_result; 00393 DenormTransform(last_denorm, src_pt, &float_result); 00394 original->x = IntCastRounded(float_result.x()); 00395 original->y = IntCastRounded(float_result.y()); 00396 } 00397 void DENORM::DenormTransform(const DENORM* last_denorm, const FCOORD& pt, 00398 FCOORD* original) const { 00399 LocalDenormTransform(pt, original); 00400 if (last_denorm != this) { 00401 if (predecessor_ != NULL) { 00402 predecessor_->DenormTransform(last_denorm, *original, original); 00403 } else if (block_ != NULL) { 00404 original->rotate(block_->re_rotation()); 00405 } 00406 } 00407 } 00408 00409 // Normalize a blob using blob transformations. Less accurate, but 00410 // more accurately copies the old way. 00411 void DENORM::LocalNormBlob(TBLOB* blob) const { 00412 TBOX blob_box = blob->bounding_box(); 00413 ICOORD translation(-IntCastRounded(x_origin_), -IntCastRounded(y_origin_)); 00414 blob->Move(translation); 00415 if (y_scale_ != 1.0f) 00416 blob->Scale(y_scale_); 00417 if (rotation_ != NULL) 00418 blob->Rotate(*rotation_); 00419 translation.set_x(IntCastRounded(final_xshift_)); 00420 translation.set_y(IntCastRounded(final_yshift_)); 00421 blob->Move(translation); 00422 } 00423 00424 // Fills in the x-height range accepted by the given unichar_id, given its 00425 // bounding box in the usual baseline-normalized coordinates, with some 00426 // initial crude x-height estimate (such as word size) and this denoting the 00427 // transformation that was used. 00428 void DENORM::XHeightRange(int unichar_id, const UNICHARSET& unicharset, 00429 const TBOX& bbox, 00430 float* min_xht, float* max_xht, float* yshift) const { 00431 // Default return -- accept anything. 00432 *yshift = 0.0f; 00433 *min_xht = 0.0f; 00434 *max_xht = MAX_FLOAT32; 00435 00436 if (!unicharset.top_bottom_useful()) 00437 return; 00438 00439 // Clip the top and bottom to the limit of normalized feature space. 00440 int top = ClipToRange<int>(bbox.top(), 0, kBlnCellHeight - 1); 00441 int bottom = ClipToRange<int>(bbox.bottom(), 0, kBlnCellHeight - 1); 00442 // A tolerance of yscale corresponds to 1 pixel in the image. 00443 double tolerance = y_scale(); 00444 // If the script doesn't have upper and lower-case characters, widen the 00445 // tolerance to allow sloppy baseline/x-height estimates. 00446 if (!unicharset.script_has_upper_lower()) 00447 tolerance = y_scale() * kSloppyTolerance; 00448 00449 int min_bottom, max_bottom, min_top, max_top; 00450 unicharset.get_top_bottom(unichar_id, &min_bottom, &max_bottom, 00451 &min_top, &max_top); 00452 00453 // Calculate the scale factor we'll use to get to image y-pixels 00454 double midx = (bbox.left() + bbox.right()) / 2; 00455 double ydiff = (bbox.top() - bbox.bottom()) + 2; 00456 FCOORD mid_bot(midx, bbox.bottom()), tmid_bot; 00457 FCOORD mid_high(midx, bbox.bottom() + ydiff), tmid_high; 00458 DenormTransform(NULL, mid_bot, &tmid_bot); 00459 DenormTransform(NULL, mid_high, &tmid_high); 00460 00461 // bln_y_measure * yscale = image_y_measure 00462 double yscale = tmid_high.pt_to_pt_dist(tmid_bot) / ydiff; 00463 00464 // Calculate y-shift 00465 int bln_yshift = 0, bottom_shift = 0, top_shift = 0; 00466 if (bottom < min_bottom - tolerance) { 00467 bottom_shift = bottom - min_bottom; 00468 } else if (bottom > max_bottom + tolerance) { 00469 bottom_shift = bottom - max_bottom; 00470 } 00471 if (top < min_top - tolerance) { 00472 top_shift = top - min_top; 00473 } else if (top > max_top + tolerance) { 00474 top_shift = top - max_top; 00475 } 00476 if ((top_shift >= 0 && bottom_shift > 0) || 00477 (top_shift < 0 && bottom_shift < 0)) { 00478 bln_yshift = (top_shift + bottom_shift) / 2; 00479 } 00480 *yshift = bln_yshift * yscale; 00481 00482 // To help very high cap/xheight ratio fonts accept the correct x-height, 00483 // and to allow the large caps in small caps to accept the xheight of the 00484 // small caps, add kBlnBaselineOffset to chars with a maximum max, and have 00485 // a top already at a significantly high position. 00486 if (max_top == kBlnCellHeight - 1 && 00487 top > kBlnCellHeight - kBlnBaselineOffset / 2) 00488 max_top += kBlnBaselineOffset; 00489 top -= bln_yshift; 00490 int height = top - kBlnBaselineOffset - bottom_shift; 00491 double min_height = min_top - kBlnBaselineOffset - tolerance; 00492 double max_height = max_top - kBlnBaselineOffset + tolerance; 00493 00494 // We shouldn't try calculations if the characters are very short (for example 00495 // for punctuation). 00496 if (min_height > kBlnXHeight / 8 && height > 0) { 00497 float result = height * kBlnXHeight * yscale / min_height; 00498 *max_xht = result + kFinalPixelTolerance; 00499 result = height * kBlnXHeight * yscale / max_height; 00500 *min_xht = result - kFinalPixelTolerance; 00501 } 00502 } 00503 00504 // Prints the content of the DENORM for debug purposes. 00505 void DENORM::Print() const { 00506 if (pix_ != NULL) { 00507 tprintf("Pix dimensions %d x %d x %d\n", 00508 pixGetWidth(pix_), pixGetHeight(pix_), pixGetDepth(pix_)); 00509 } 00510 if (inverse_) 00511 tprintf("Inverse\n"); 00512 if (block_ && block_->re_rotation().x() != 1.0f) { 00513 tprintf("Block rotation %g, %g\n", 00514 block_->re_rotation().x(), block_->re_rotation().y()); 00515 } 00516 tprintf("Input Origin = (%g, %g)\n", x_origin_, y_origin_); 00517 if (x_map_ != NULL && y_map_ != NULL) { 00518 tprintf("x map:\n"); 00519 for (int x = 0; x < x_map_->size(); ++x) { 00520 tprintf("%g ", (*x_map_)[x]); 00521 } 00522 tprintf("\ny map:\n"); 00523 for (int y = 0; y < y_map_->size(); ++y) { 00524 tprintf("%g ", (*y_map_)[y]); 00525 } 00526 tprintf("\n"); 00527 } else { 00528 tprintf("Scale = (%g, %g)\n", x_scale_, y_scale_); 00529 if (rotation_ != NULL) 00530 tprintf("Rotation = (%g, %g)\n", rotation_->x(), rotation_->y()); 00531 } 00532 tprintf("Final Origin = (%g, %g)\n", final_xshift_, final_xshift_); 00533 if (predecessor_ != NULL) { 00534 tprintf("Predecessor:\n"); 00535 predecessor_->Print(); 00536 } 00537 } 00538 00539 00540 // ============== Private Code ====================== 00541 00542 // Free allocated memory and clear pointers. 00543 void DENORM::Clear() { 00544 if (x_map_ != NULL) { 00545 delete x_map_; 00546 x_map_ = NULL; 00547 } 00548 if (y_map_ != NULL) { 00549 delete y_map_; 00550 y_map_ = NULL; 00551 } 00552 if (rotation_ != NULL) { 00553 delete rotation_; 00554 rotation_ = NULL; 00555 } 00556 } 00557 00558 // Setup default values. 00559 void DENORM::Init() { 00560 inverse_ = false; 00561 pix_ = NULL; 00562 block_ = NULL; 00563 rotation_ = NULL; 00564 predecessor_ = NULL; 00565 x_map_ = NULL; 00566 y_map_ = NULL; 00567 x_origin_ = 0.0f; 00568 y_origin_ = 0.0f; 00569 x_scale_ = 1.0f; 00570 y_scale_ = 1.0f; 00571 final_xshift_ = 0.0f; 00572 final_yshift_ = static_cast<float>(kBlnBaselineOffset); 00573 }