mirror of
https://github.com/tesseract-ocr/tesseract.git
synced 2025-06-12 05:13:14 +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 <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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user