Skip to content

Commit a1c22fb

Browse files
committed
Fixed issue #557
1 parent b453f74 commit a1c22fb

23 files changed

+131
-423
lines changed

api/tesseractmain.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ int main(int argc, char** argv) {
403403

404404
#if !defined(DEBUG)
405405
// Disable debugging and informational messages from Leptonica.
406-
setMsgSeverity(L_SEVERITY_WARNING);
406+
setMsgSeverity(L_SEVERITY_ERROR);
407407
#endif
408408

409409
#if defined(HAVE_TIFFIO_H) && defined(_WIN32)

ccmain/osdetect.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ void remove_nontext_regions(tesseract::Tesseract *tess, BLOCK_LIST *blocks,
176176
tesseract::LineFinder::FindAndRemoveLines(resolution, false, pix,
177177
&vertical_x, &vertical_y,
178178
NULL, &v_lines, &h_lines);
179-
Pix* im_pix = tesseract::ImageFind::FindImages(pix);
179+
Pix* im_pix = tesseract::ImageFind::FindImages(pix, nullptr);
180180
if (im_pix != NULL) {
181181
pixSubtract(pix, pix, im_pix);
182182
pixDestroy(&im_pix);

ccmain/pagesegmain.cpp

+13-39
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "blobbox.h"
3838
#include "blread.h"
3939
#include "colfind.h"
40+
#include "debugpixa.h"
4041
#include "equationdetect.h"
4142
#include "imagefind.h"
4243
#include "linefind.h"
@@ -176,28 +177,6 @@ int Tesseract::SegmentPage(const STRING* input_file, BLOCK_LIST* blocks,
176177
return auto_page_seg_ret_val;
177178
}
178179

179-
// Helper writes a grey image to a file for use by scrollviewer.
180-
// Normally for speed we don't display the image in the layout debug windows.
181-
// If textord_debug_images is true, we draw the image as a background to some
182-
// of the debug windows. printable determines whether these
183-
// images are optimized for printing instead of screen display.
184-
static void WriteDebugBackgroundImage(bool printable, Pix* pix_binary) {
185-
Pix* grey_pix = pixCreate(pixGetWidth(pix_binary),
186-
pixGetHeight(pix_binary), 8);
187-
// Printable images are light grey on white, but for screen display
188-
// they are black on dark grey so the other colors show up well.
189-
if (printable) {
190-
pixSetAll(grey_pix);
191-
pixSetMasked(grey_pix, pix_binary, 192);
192-
} else {
193-
pixSetAllArbitrary(grey_pix, 64);
194-
pixSetMasked(grey_pix, pix_binary, 0);
195-
}
196-
AlignedBlob::IncrementDebugPix();
197-
pixWrite(AlignedBlob::textord_debug_pix().string(), grey_pix, IFF_PNG);
198-
pixDestroy(&grey_pix);
199-
}
200-
201180
/**
202181
* Auto page segmentation. Divide the page image into blocks of uniform
203182
* text linespacing and images.
@@ -226,9 +205,6 @@ int Tesseract::AutoPageSeg(PageSegMode pageseg_mode, BLOCK_LIST* blocks,
226205
TO_BLOCK_LIST* to_blocks,
227206
BLOBNBOX_LIST* diacritic_blobs, Tesseract* osd_tess,
228207
OSResults* osr) {
229-
if (textord_debug_images) {
230-
WriteDebugBackgroundImage(textord_debug_printable, pix_binary_);
231-
}
232208
Pix* photomask_pix = NULL;
233209
Pix* musicmask_pix = NULL;
234210
// The blocks made by the ColumnFinder. Moved to blocks before return.
@@ -250,9 +226,10 @@ int Tesseract::AutoPageSeg(PageSegMode pageseg_mode, BLOCK_LIST* blocks,
250226
if (equ_detect_) {
251227
finder->SetEquationDetect(equ_detect_);
252228
}
253-
result = finder->FindBlocks(
254-
pageseg_mode, scaled_color_, scaled_factor_, to_block, photomask_pix,
255-
pix_thresholds_, pix_grey_, &found_blocks, diacritic_blobs, to_blocks);
229+
result = finder->FindBlocks(pageseg_mode, scaled_color_, scaled_factor_,
230+
to_block, photomask_pix, pix_thresholds_,
231+
pix_grey_, &pixa_debug_, &found_blocks,
232+
diacritic_blobs, to_blocks);
256233
if (result >= 0)
257234
finder->GetDeskewVectors(&deskew_, &reskew_);
258235
delete finder;
@@ -265,11 +242,6 @@ int Tesseract::AutoPageSeg(PageSegMode pageseg_mode, BLOCK_LIST* blocks,
265242
BLOCK_IT block_it(blocks);
266243
// Move the found blocks to the input/output blocks.
267244
block_it.add_list_after(&found_blocks);
268-
269-
if (textord_debug_images) {
270-
// The debug image is no longer needed so delete it.
271-
unlink(AlignedBlob::textord_debug_pix().string());
272-
}
273245
return result;
274246
}
275247

@@ -311,19 +283,21 @@ ColumnFinder* Tesseract::SetupPageSegAndDetectOrientation(
311283

312284
ASSERT_HOST(pix_binary_ != NULL);
313285
if (tessedit_dump_pageseg_images) {
314-
pixWrite("tessinput.png", pix_binary_, IFF_PNG);
286+
pixa_debug_.AddPix(pix_binary_, "PageSegInput");
315287
}
316288
// Leptonica is used to find the rule/separator lines in the input.
317289
LineFinder::FindAndRemoveLines(source_resolution_,
318290
textord_tabfind_show_vlines, pix_binary_,
319291
&vertical_x, &vertical_y, music_mask_pix,
320292
&v_lines, &h_lines);
321-
if (tessedit_dump_pageseg_images)
322-
pixWrite("tessnolines.png", pix_binary_, IFF_PNG);
293+
if (tessedit_dump_pageseg_images) {
294+
pixa_debug_.AddPix(pix_binary_, "NoLines");
295+
}
323296
// Leptonica is used to find a mask of the photo regions in the input.
324-
*photo_mask_pix = ImageFind::FindImages(pix_binary_);
325-
if (tessedit_dump_pageseg_images)
326-
pixWrite("tessnoimages.png", pix_binary_, IFF_PNG);
297+
*photo_mask_pix = ImageFind::FindImages(pix_binary_, &pixa_debug_);
298+
if (tessedit_dump_pageseg_images) {
299+
pixa_debug_.AddPix(pix_binary_, "NoImages");
300+
}
327301
if (!PSM_COL_FIND_ENABLED(pageseg_mode)) v_lines.clear();
328302

329303
// The rest of the algorithm uses the usual connected components.

ccstruct/Makefile.am

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ endif
1212
include_HEADERS = publictypes.h
1313
noinst_HEADERS = \
1414
blamer.h blckerr.h blobbox.h blobs.h blread.h boxread.h boxword.h ccstruct.h coutln.h crakedge.h \
15-
detlinefit.h dppoint.h fontinfo.h genblob.h hpdsizes.h \
15+
debugpixa.h detlinefit.h dppoint.h fontinfo.h genblob.h hpdsizes.h \
1616
imagedata.h \
1717
ipoints.h \
1818
linlsq.h matrix.h mod128.h normalis.h \

ccstruct/debugpixa.h

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#ifndef TESSERACT_CCSTRUCT_DEBUGPIXA_H_
2+
#define TESSERACT_CCSTRUCT_DEBUGPIXA_H_
3+
4+
#include "allheaders.h"
5+
6+
namespace tesseract {
7+
8+
// Class to hold a Pixa collection of debug images with captions and save them
9+
// to a PDF file.
10+
class DebugPixa {
11+
public:
12+
// TODO(rays) add another constructor with size control.
13+
DebugPixa() {
14+
pixa_ = pixaCreate(0);
15+
fonts_ = bmfCreate(nullptr, 14);
16+
}
17+
// If the filename_ has been set and there are any debug images, they are
18+
// written to the set filename_.
19+
~DebugPixa() {
20+
pixaDestroy(&pixa_);
21+
bmfDestroy(&fonts_);
22+
}
23+
24+
// Adds the given pix to the set of pages in the PDF file, with the given
25+
// caption added to the top.
26+
void AddPix(const Pix* pix, const char* caption) {
27+
int depth = pixGetDepth(const_cast<Pix*>(pix));
28+
int color = depth < 8 ? 1 : (depth > 8 ? 0x00ff0000 : 0x80);
29+
Pix* pix_debug = pixAddSingleTextblock(
30+
const_cast<Pix*>(pix), fonts_, caption, color, L_ADD_BELOW, nullptr);
31+
pixaAddPix(pixa_, pix_debug, L_INSERT);
32+
}
33+
34+
// Sets the destination filename and enables images to be written to a PDF
35+
// on destruction.
36+
void WritePDF(const char* filename) {
37+
if (pixaGetCount(pixa_) > 0) {
38+
pixaConvertToPdf(pixa_, 300, 1.0f, 0, 0, "AllDebugImages", filename);
39+
pixaClear(pixa_);
40+
}
41+
}
42+
43+
private:
44+
// The collection of images to put in the PDF.
45+
Pixa* pixa_;
46+
// The fonts used to draw text captions.
47+
L_Bmf* fonts_;
48+
};
49+
50+
} // namespace tesseract
51+
52+
#endif // TESSERACT_CCSTRUCT_DEBUGPIXA_H_

classify/trainingsampleset.cpp

-81
Original file line numberDiff line numberDiff line change
@@ -487,81 +487,6 @@ void TrainingSampleSet::IndexFeatures(const IntFeatureSpace& feature_space) {
487487
samples_[s]->IndexFeatures(feature_space);
488488
}
489489

490-
// Delete outlier samples with few features that are shared with others.
491-
// IndexFeatures must have been called already.
492-
void TrainingSampleSet::DeleteOutliers(const IntFeatureSpace& feature_space,
493-
bool debug) {
494-
if (font_class_array_ == NULL)
495-
OrganizeByFontAndClass();
496-
Pixa* pixa = NULL;
497-
if (debug)
498-
pixa = pixaCreate(0);
499-
GenericVector<int> feature_counts;
500-
int fs_size = feature_space.Size();
501-
int font_size = font_id_map_.CompactSize();
502-
for (int font_index = 0; font_index < font_size; ++font_index) {
503-
for (int c = 0; c < unicharset_size_; ++c) {
504-
// Create a histogram of the features used by all samples of this
505-
// font/class combination.
506-
feature_counts.init_to_size(fs_size, 0);
507-
FontClassInfo& fcinfo = (*font_class_array_)(font_index, c);
508-
int sample_count = fcinfo.samples.size();
509-
if (sample_count < kMinOutlierSamples)
510-
continue;
511-
for (int i = 0; i < sample_count; ++i) {
512-
int s = fcinfo.samples[i];
513-
const GenericVector<int>& features = samples_[s]->indexed_features();
514-
for (int f = 0; f < features.size(); ++f) {
515-
++feature_counts[features[f]];
516-
}
517-
}
518-
for (int i = 0; i < sample_count; ++i) {
519-
int s = fcinfo.samples[i];
520-
const TrainingSample& sample = *samples_[s];
521-
const GenericVector<int>& features = sample.indexed_features();
522-
// A feature that has a histogram count of 1 is only used by this
523-
// sample, making it 'bad'. All others are 'good'.
524-
int good_features = 0;
525-
int bad_features = 0;
526-
for (int f = 0; f < features.size(); ++f) {
527-
if (feature_counts[features[f]] > 1)
528-
++good_features;
529-
else
530-
++bad_features;
531-
}
532-
// If more than 1/3 features are bad, then this is an outlier.
533-
if (bad_features * 2 > good_features) {
534-
tprintf("Deleting outlier sample of %s, %d good, %d bad\n",
535-
SampleToString(sample).string(),
536-
good_features, bad_features);
537-
if (debug) {
538-
pixaAddPix(pixa, sample.RenderToPix(&unicharset_), L_INSERT);
539-
// Add the previous sample as well, so it is easier to see in
540-
// the output what is wrong with this sample.
541-
int t;
542-
if (i == 0)
543-
t = fcinfo.samples[1];
544-
else
545-
t = fcinfo.samples[i - 1];
546-
const TrainingSample &csample = *samples_[t];
547-
pixaAddPix(pixa, csample.RenderToPix(&unicharset_), L_INSERT);
548-
}
549-
// Mark the sample for deletion.
550-
KillSample(samples_[s]);
551-
}
552-
}
553-
}
554-
}
555-
// Truly delete all bad samples and renumber everything.
556-
DeleteDeadSamples();
557-
if (pixa != NULL) {
558-
Pix* pix = pixaDisplayTiledInRows(pixa, 1, 2600, 1.0, 0, 10, 10);
559-
pixaDestroy(&pixa);
560-
pixWrite("outliers.png", pix, IFF_PNG);
561-
pixDestroy(&pix);
562-
}
563-
}
564-
565490
// Marks the given sample index for deletion.
566491
// Deletion is actually completed by DeleteDeadSamples.
567492
void TrainingSampleSet::KillSample(TrainingSample* sample) {
@@ -745,12 +670,6 @@ void TrainingSampleSet::ComputeCanonicalSamples(const IntFeatureMap& map,
745670
if (debug) {
746671
tprintf("Global worst dist = %g, between sample %d and %d\n",
747672
global_worst_dist, worst_s1, worst_s2);
748-
Pix* pix1 = DebugSample(unicharset_, samples_[worst_s1]);
749-
Pix* pix2 = DebugSample(unicharset_, samples_[worst_s2]);
750-
pixOr(pix1, pix1, pix2);
751-
pixWrite("worstpair.png", pix1, IFF_PNG);
752-
pixDestroy(&pix1);
753-
pixDestroy(&pix2);
754673
}
755674
}
756675

classify/trainingsampleset.h

-4
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,6 @@ class TrainingSampleSet {
171171
// Generates indexed features for all samples with the supplied feature_space.
172172
void IndexFeatures(const IntFeatureSpace& feature_space);
173173

174-
// Delete outlier samples with few features that are shared with others.
175-
// IndexFeatures must have been called already.
176-
void DeleteOutliers(const IntFeatureSpace& feature_space, bool debug);
177-
178174
// Marks the given sample for deletion.
179175
// Deletion is actually completed by DeleteDeadSamples.
180176
void KillSample(TrainingSample* sample);

textord/alignedblob.cpp

-20
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ INT_VAR(textord_testregion_left, -1, "Left edge of debug reporting rectangle");
3030
INT_VAR(textord_testregion_top, -1, "Top edge of debug reporting rectangle");
3131
INT_VAR(textord_testregion_right, MAX_INT32, "Right edge of debug rectangle");
3232
INT_VAR(textord_testregion_bottom, MAX_INT32, "Bottom edge of debug rectangle");
33-
BOOL_VAR(textord_debug_images, false, "Use greyed image background for debug");
3433
BOOL_VAR(textord_debug_printable, false, "Make debug windows printable");
3534

3635
namespace tesseract {
@@ -64,25 +63,6 @@ const double kMinTabGradient = 4.0;
6463
// If the angle is small, the angle in degrees is roughly 60/kMaxSkewFactor.
6564
const int kMaxSkewFactor = 15;
6665

67-
// Constant part of textord_debug_pix_.
68-
const char* kTextordDebugPix = "psdebug_pix";
69-
70-
// Name of image file to use if textord_debug_images is true.
71-
STRING AlignedBlob::textord_debug_pix_ = kTextordDebugPix;
72-
// Index to image file to use if textord_debug_images is true.
73-
int AlignedBlob::debug_pix_index_ = 0;
74-
75-
// Increment the serial number counter and set the string to use
76-
// for a filename if textord_debug_images is true.
77-
void AlignedBlob::IncrementDebugPix() {
78-
++debug_pix_index_;
79-
textord_debug_pix_ = kTextordDebugPix;
80-
char numbuf[32];
81-
snprintf(numbuf, sizeof(numbuf), "%d", debug_pix_index_);
82-
textord_debug_pix_ += numbuf;
83-
textord_debug_pix_ += ".pix";
84-
}
85-
8666
// Constructor to set the parameters for finding aligned and ragged tabs.
8767
// Vertical_x and vertical_y are the current estimates of the true vertical
8868
// direction (up) in the image. Height is the height of the starter blob.

textord/alignedblob.h

-18
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
extern INT_VAR_H(textord_debug_bugs, 0,
3030
"Turn on output related to bugs in tab finding");
3131
extern INT_VAR_H(textord_debug_tabfind, 2, "Debug tab finding");
32-
extern BOOL_VAR_H(textord_debug_images, false,
33-
"Use greyed image background for debug");
3432
extern BOOL_VAR_H(textord_debug_printable, false,
3533
"Make debug windows printable");
3634

@@ -102,17 +100,6 @@ class AlignedBlob : public BlobGrid {
102100
BLOBNBOX* bbox,
103101
int* vertical_x, int* vertical_y);
104102

105-
// Increment the serial number counter and set the string to use
106-
// for a filename if textord_debug_images is true.
107-
static void IncrementDebugPix();
108-
109-
// Return the string to use for a filename if textord_debug_images is true.
110-
// Use IncrementDebugPix first to set the filename, and each time is
111-
// to be incremented.
112-
static const STRING& textord_debug_pix() {
113-
return textord_debug_pix_;
114-
}
115-
116103
private:
117104
// Find a set of blobs that are aligned in the given vertical
118105
// direction with the given blob. Returns a list of aligned
@@ -132,11 +119,6 @@ class AlignedBlob : public BlobGrid {
132119
BLOBNBOX* FindAlignedBlob(const AlignedBlobParams& p,
133120
bool top_to_bottom, BLOBNBOX* bbox,
134121
int x_start, int* end_y);
135-
136-
// Name of image file to use if textord_debug_images is true.
137-
static STRING textord_debug_pix_;
138-
// Index to image file to use if textord_debug_images is true.
139-
static int debug_pix_index_;
140122
};
141123

142124
} // namespace tesseract.

0 commit comments

Comments
 (0)