Fixed issue 1134

git-svn-id: https://tesseract-ocr.googlecode.com/svn/trunk@1082 d0cd1f9f-072b-0410-8dd7-cf729c803f20
This commit is contained in:
theraysmith@gmail.com 2014-04-25 01:07:26 +00:00
parent 84e0f6470f
commit 42bfdc21d8
4 changed files with 63 additions and 13 deletions

View File

@ -28,6 +28,49 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "host.h"
// TODO(rays) Put the rest of the helpers in the namespace.
namespace tesseract {
// A simple linear congruential random number generator, using Knuth's
// constants from:
// http://en.wikipedia.org/wiki/Linear_congruential_generator.
class TRand {
public:
TRand() : seed_(1) {}
// Sets the seed to the given value.
void set_seed(uinT64 seed) {
seed_ = seed;
}
// Returns an integer in the range 0 to MAX_INT32.
inT32 IntRand() {
Iterate();
return seed_ >> 33;
}
// Returns a floating point value in the range [-range, range].
double SignedRand(double range) {
return range * 2.0 * IntRand() / MAX_INT32 - range;
}
// Returns a floating point value in the range [0, range].
double UnsignedRand(double range) {
return range * IntRand() / MAX_INT32;
}
private:
// Steps the generator to the next value.
void Iterate() {
seed_ *= 6364136223846793005;
seed_ += 1442695040888963407;
}
// The current value of the seed.
uinT64 seed_;
};
} // namespace tesseract
// Remove newline (if any) at the end of the string. // Remove newline (if any) at the end of the string.
inline void chomp_string(char *str) { inline void chomp_string(char *str) {
int last_index = strlen(str) - 1; int last_index = strlen(str) - 1;

View File

@ -22,6 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "allheaders.h" // from leptonica #include "allheaders.h" // from leptonica
#include "helpers.h" // For TRand.
namespace tesseract { namespace tesseract {
@ -34,17 +35,13 @@ const int kSaltnPepper = 5;
// Min sum of width + height on which to operate the ramp. // Min sum of width + height on which to operate the ramp.
const int kMinRampSize = 1000; const int kMinRampSize = 1000;
static unsigned int random_seed = 0x18273645;
#ifndef rand_r // _MSC_VER, ANDROID
#define rand_r(random_seed) rand()
#endif // _MSC_VER
// Degrade the pix as if by a print/copy/scan cycle with exposure > 0 // Degrade the pix as if by a print/copy/scan cycle with exposure > 0
// corresponding to darkening on the copier and <0 lighter and 0 not copied. // corresponding to darkening on the copier and <0 lighter and 0 not copied.
// Exposures in [-2,2] are most useful, with -3 and 3 being extreme. // Exposures in [-2,2] are most useful, with -3 and 3 being extreme.
// If rotation is NULL, rotation is skipped. If *rotation is non-zero, the pix // If rotation is NULL, rotation is skipped. If *rotation is non-zero, the pix
// is rotated by *rotation else it is randomly rotated and *rotation is // is rotated by *rotation else it is randomly rotated and *rotation is
// modified. // modified.
//
// HOW IT WORKS: // HOW IT WORKS:
// Most of the process is really dictated by the fact that the minimum // Most of the process is really dictated by the fact that the minimum
// available convolution is 3X3, which is too big really to simulate a // available convolution is 3X3, which is too big really to simulate a
@ -65,7 +62,8 @@ static unsigned int random_seed = 0x18273645;
// the edges. // the edges.
// Finally a greyscale ramp provides a continuum of effects between exposure // Finally a greyscale ramp provides a continuum of effects between exposure
// levels. // levels.
Pix* DegradeImage(Pix* input, int exposure, float* rotation) { Pix* DegradeImage(Pix* input, int exposure, TRand* randomizer,
float* rotation) {
Pix* pix = pixConvertTo8(input, false); Pix* pix = pixConvertTo8(input, false);
pixDestroy(&input); pixDestroy(&input);
input = pix; input = pix;
@ -85,12 +83,11 @@ Pix* DegradeImage(Pix* input, int exposure, float* rotation) {
pixDestroy(&input); pixDestroy(&input);
// A small random rotation helps to make the edges jaggy in a realistic way. // A small random rotation helps to make the edges jaggy in a realistic way.
if (rotation != NULL) { if (rotation != NULL) {
float radians_clockwise; float radians_clockwise = 0.0f;
if (*rotation) { if (*rotation) {
radians_clockwise = *rotation; radians_clockwise = *rotation;
} else { } else if (randomizer != NULL) {
radians_clockwise = (2.0*rand_r(&random_seed)/RAND_MAX - 1.0) * radians_clockwise = randomizer->SignedRand(kRotationRange);
kRotationRange;
} }
input = pixRotate(pix, radians_clockwise, input = pixRotate(pix, radians_clockwise,
@ -131,7 +128,8 @@ Pix* DegradeImage(Pix* input, int exposure, float* rotation) {
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) { for (int x = 0; x < width; ++x) {
int pixel = GET_DATA_BYTE(data, x); int pixel = GET_DATA_BYTE(data, x);
pixel += rand_r(&random_seed) % (kSaltnPepper*2 + 1) - kSaltnPepper; if (randomizer != NULL)
pixel += randomizer->IntRand() % (kSaltnPepper*2 + 1) - kSaltnPepper;
if (height + width > kMinRampSize) if (height + width > kMinRampSize)
pixel -= (2*x + y) * 32 / (height + width); pixel -= (2*x + y) * 32 / (height + width);
pixel += erosion_offset; pixel += erosion_offset;

View File

@ -24,12 +24,15 @@ struct Pix;
namespace tesseract { namespace tesseract {
class TRand;
// Degrade the pix as if by a print/copy/scan cycle with exposure > 0 // Degrade the pix as if by a print/copy/scan cycle with exposure > 0
// corresponding to darkening on the copier and <0 lighter and 0 not copied. // corresponding to darkening on the copier and <0 lighter and 0 not copied.
// If rotation is not NULL, the clockwise rotation in radians is saved there. // If rotation is not NULL, the clockwise rotation in radians is saved there.
// The input pix must be 8 bit grey. (Binary with values 0 and 255 is OK.) // The input pix must be 8 bit grey. (Binary with values 0 and 255 is OK.)
// The input image is destroyed and a different image returned. // The input image is destroyed and a different image returned.
struct Pix* DegradeImage(struct Pix* input, int exposure, float* rotation); struct Pix* DegradeImage(struct Pix* input, int exposure, TRand* randomizer,
float* rotation);
} // namespace tesseract } // namespace tesseract

View File

@ -43,6 +43,7 @@
#include "degradeimage.h" #include "degradeimage.h"
#include "errcode.h" #include "errcode.h"
#include "fileio.h" #include "fileio.h"
#include "helpers.h"
#include "normstrngs.h" #include "normstrngs.h"
#include "stringrenderer.h" #include "stringrenderer.h"
#include "tlog.h" #include "tlog.h"
@ -55,6 +56,9 @@ using std::map;
using std::pair; using std::pair;
#endif #endif
// A number with which to initialize the random number generator.
const int kRandomSeed = 0x18273645;
// The text input file. // The text input file.
STRING_PARAM_FLAG(text, "", "File name of text input to process"); STRING_PARAM_FLAG(text, "", "File name of text input to process");
@ -534,6 +538,8 @@ int main(int argc, char** argv) {
vector<float> page_rotation; vector<float> page_rotation;
const char* to_render_utf8 = src_utf8.c_str(); const char* to_render_utf8 = src_utf8.c_str();
tesseract::TRand randomizer;
randomizer.set_seed(kRandomSeed);
// We use a two pass mechanism to rotate images in both direction. // We use a two pass mechanism to rotate images in both direction.
// The first pass(0) will rotate the images in random directions and // The first pass(0) will rotate the images in random directions and
// the second pass(1) will mirror those rotations. // the second pass(1) will mirror those rotations.
@ -560,7 +566,7 @@ int main(int argc, char** argv) {
rotation = -1 * page_rotation[page_num]; rotation = -1 * page_rotation[page_num];
} }
if (FLAGS_degrade_image) { if (FLAGS_degrade_image) {
pix = DegradeImage(pix, FLAGS_exposure, &rotation); pix = DegradeImage(pix, FLAGS_exposure, &randomizer, &rotation);
} }
render.RotatePageBoxes(rotation); render.RotatePageBoxes(rotation);