mirror of
https://github.com/tesseract-ocr/tesseract.git
synced 2025-06-07 09:52:40 +08:00
Fixed issue 1134
git-svn-id: https://tesseract-ocr.googlecode.com/svn/trunk@1082 d0cd1f9f-072b-0410-8dd7-cf729c803f20
This commit is contained in:
parent
84e0f6470f
commit
42bfdc21d8
@ -28,6 +28,49 @@
|
||||
#include <stdio.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.
|
||||
inline void chomp_string(char *str) {
|
||||
int last_index = strlen(str) - 1;
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "allheaders.h" // from leptonica
|
||||
#include "helpers.h" // For TRand.
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
@ -34,17 +35,13 @@ const int kSaltnPepper = 5;
|
||||
// Min sum of width + height on which to operate the ramp.
|
||||
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
|
||||
// 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.
|
||||
// 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
|
||||
// modified.
|
||||
//
|
||||
// HOW IT WORKS:
|
||||
// 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
|
||||
@ -65,7 +62,8 @@ static unsigned int random_seed = 0x18273645;
|
||||
// the edges.
|
||||
// Finally a greyscale ramp provides a continuum of effects between exposure
|
||||
// levels.
|
||||
Pix* DegradeImage(Pix* input, int exposure, float* rotation) {
|
||||
Pix* DegradeImage(Pix* input, int exposure, TRand* randomizer,
|
||||
float* rotation) {
|
||||
Pix* pix = pixConvertTo8(input, false);
|
||||
pixDestroy(&input);
|
||||
input = pix;
|
||||
@ -85,12 +83,11 @@ Pix* DegradeImage(Pix* input, int exposure, float* rotation) {
|
||||
pixDestroy(&input);
|
||||
// A small random rotation helps to make the edges jaggy in a realistic way.
|
||||
if (rotation != NULL) {
|
||||
float radians_clockwise;
|
||||
float radians_clockwise = 0.0f;
|
||||
if (*rotation) {
|
||||
radians_clockwise = *rotation;
|
||||
} else {
|
||||
radians_clockwise = (2.0*rand_r(&random_seed)/RAND_MAX - 1.0) *
|
||||
kRotationRange;
|
||||
} else if (randomizer != NULL) {
|
||||
radians_clockwise = randomizer->SignedRand(kRotationRange);
|
||||
}
|
||||
|
||||
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 x = 0; x < width; ++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)
|
||||
pixel -= (2*x + y) * 32 / (height + width);
|
||||
pixel += erosion_offset;
|
||||
|
@ -24,12 +24,15 @@ struct Pix;
|
||||
|
||||
namespace tesseract {
|
||||
|
||||
class TRand;
|
||||
|
||||
// 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.
|
||||
// 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 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
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "degradeimage.h"
|
||||
#include "errcode.h"
|
||||
#include "fileio.h"
|
||||
#include "helpers.h"
|
||||
#include "normstrngs.h"
|
||||
#include "stringrenderer.h"
|
||||
#include "tlog.h"
|
||||
@ -55,6 +56,9 @@ using std::map;
|
||||
using std::pair;
|
||||
#endif
|
||||
|
||||
// A number with which to initialize the random number generator.
|
||||
const int kRandomSeed = 0x18273645;
|
||||
|
||||
// The text input file.
|
||||
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;
|
||||
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.
|
||||
// The first pass(0) will rotate the images in random directions and
|
||||
// the second pass(1) will mirror those rotations.
|
||||
@ -560,7 +566,7 @@ int main(int argc, char** argv) {
|
||||
rotation = -1 * page_rotation[page_num];
|
||||
}
|
||||
if (FLAGS_degrade_image) {
|
||||
pix = DegradeImage(pix, FLAGS_exposure, &rotation);
|
||||
pix = DegradeImage(pix, FLAGS_exposure, &randomizer, &rotation);
|
||||
}
|
||||
render.RotatePageBoxes(rotation);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user