Skip to content

Commit

Permalink
Replace callback by direct function calls in TessBaseAPI::GetComponen…
Browse files Browse the repository at this point in the history
…tImages

The new code avoids dynamic memory allocation, uses faster function calls
and allows removing more code from tesscallback.h.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
  • Loading branch information
stweil committed Jun 22, 2019
1 parent 3159f42 commit cb2957b
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 215 deletions.
34 changes: 20 additions & 14 deletions src/api/baseapi.cpp
Expand Up @@ -707,24 +707,23 @@ Boxa* TessBaseAPI::GetComponentImages(PageIteratorLevel level,
int component_count = 0;
int left, top, right, bottom;

TessResultCallback<bool>* get_bbox = nullptr;
if (raw_image) {
// Get bounding box in original raw image with padding.
get_bbox = NewPermanentTessCallback(page_it, &PageIterator::BoundingBox,
level, raw_padding,
&left, &top, &right, &bottom);
do {
if (page_it->BoundingBox(level, raw_padding,
&left, &top, &right, &bottom) &&
(!text_only || PTIsTextType(page_it->BlockType())))
++component_count;
} while (page_it->Next(level));
} else {
// Get bounding box from binarized imaged. Note that this could be
// differently scaled from the original image.
get_bbox = NewPermanentTessCallback(page_it,
&PageIterator::BoundingBoxInternal,
level, &left, &top, &right, &bottom);
do {
if (page_it->BoundingBoxInternal(level, &left, &top, &right, &bottom) &&
(!text_only || PTIsTextType(page_it->BlockType())))
++component_count;
} while (page_it->Next(level));
}
do {
if (get_bbox->Run() &&
(!text_only || PTIsTextType(page_it->BlockType())))
++component_count;
} while (page_it->Next(level));

Boxa* boxa = boxaCreate(component_count);
if (pixa != nullptr)
Expand All @@ -739,7 +738,15 @@ Boxa* TessBaseAPI::GetComponentImages(PageIteratorLevel level,
int component_index = 0;
page_it->Begin();
do {
if (get_bbox->Run() &&
bool got_bounding_box;
if (raw_image) {
got_bounding_box =
page_it->BoundingBox(level, raw_padding, &left, &top, &right, &bottom);
} else {
got_bounding_box =
page_it->BoundingBoxInternal(level, &left, &top, &right, &bottom);
}
if (got_bounding_box &&
(!text_only || PTIsTextType(page_it->BlockType()))) {
Box* lbox = boxCreate(left, top, right - left, bottom - top);
boxaAddBox(boxa, lbox, L_INSERT);
Expand Down Expand Up @@ -770,7 +777,6 @@ Boxa* TessBaseAPI::GetComponentImages(PageIteratorLevel level,
}
} while (page_it->Next(level));
delete page_it;
delete get_bbox;
return boxa;
}

Expand Down
201 changes: 0 additions & 201 deletions src/ccutil/tesscallback.h
Expand Up @@ -169,207 +169,6 @@ struct Identity {
using type = T;
};

template <bool del, class R, class T, class P1, class P2, class P3, class P4,
class P5>
class _ConstTessMemberResultCallback_5_0 : public TessResultCallback<R> {
public:
using base = TessResultCallback<R>;
using MemberSignature = R (T::*)(P1, P2, P3, P4, P5) const;

private:
const T* object_;
MemberSignature member_;
typename remove_reference<P1>::type p1_;
typename remove_reference<P2>::type p2_;
typename remove_reference<P3>::type p3_;
typename remove_reference<P4>::type p4_;
typename remove_reference<P5>::type p5_;

public:
inline _ConstTessMemberResultCallback_5_0(const T* object,
MemberSignature member, P1 p1,
P2 p2, P3 p3, P4 p4, P5 p5)
: object_(object),
member_(member),
p1_(p1),
p2_(p2),
p3_(p3),
p4_(p4),
p5_(p5) {}

R Run() override {
if (!del) {
R result = (object_->*member_)(p1_, p2_, p3_, p4_, p5_);
return result;
}
R result = (object_->*member_)(p1_, p2_, p3_, p4_, p5_);
// zero out the pointer to ensure segfault if used again
member_ = nullptr;
delete this;
return result;
}
};

template <bool del, class T, class P1, class P2, class P3, class P4, class P5>
class _ConstTessMemberResultCallback_5_0<del, void, T, P1, P2, P3, P4, P5>
: public TessClosure {
public:
using base = TessClosure;
using MemberSignature = void (T::*)(P1, P2, P3, P4, P5) const;

private:
const T* object_;
MemberSignature member_;
typename remove_reference<P1>::type p1_;
typename remove_reference<P2>::type p2_;
typename remove_reference<P3>::type p3_;
typename remove_reference<P4>::type p4_;
typename remove_reference<P5>::type p5_;

public:
inline _ConstTessMemberResultCallback_5_0(const T* object,
MemberSignature member, P1 p1,
P2 p2, P3 p3, P4 p4, P5 p5)
: object_(object),
member_(member),
p1_(p1),
p2_(p2),
p3_(p3),
p4_(p4),
p5_(p5) {}

void Run() override {
if (!del) {
(object_->*member_)(p1_, p2_, p3_, p4_, p5_);
} else {
(object_->*member_)(p1_, p2_, p3_, p4_, p5_);
// zero out the pointer to ensure segfault if used again
member_ = nullptr;
delete this;
}
}
};

#ifndef SWIG
template <class T1, class T2, class R, class P1, class P2, class P3, class P4,
class P5>
inline typename _ConstTessMemberResultCallback_5_0<false, R, T1, P1, P2, P3, P4,
P5>::base*
NewPermanentTessCallback(const T1* obj,
R (T2::*member)(P1, P2, P3, P4, P5) const,
typename Identity<P1>::type p1,
typename Identity<P2>::type p2,
typename Identity<P3>::type p3,
typename Identity<P4>::type p4,
typename Identity<P5>::type p5) {
return new _ConstTessMemberResultCallback_5_0<false, R, T1, P1, P2, P3, P4,
P5>(obj, member, p1, p2, p3, p4,
p5);
}
#endif

template <bool del, class R, class T, class P1, class P2, class P3, class P4,
class P5, class P6>
class _ConstTessMemberResultCallback_6_0 : public TessResultCallback<R> {
public:
using base = TessResultCallback<R>;
using MemberSignature = R (T::*)(P1, P2, P3, P4, P5, P6) const;

private:
const T* object_;
MemberSignature member_;
typename remove_reference<P1>::type p1_;
typename remove_reference<P2>::type p2_;
typename remove_reference<P3>::type p3_;
typename remove_reference<P4>::type p4_;
typename remove_reference<P5>::type p5_;
typename remove_reference<P6>::type p6_;

public:
inline _ConstTessMemberResultCallback_6_0(const T* object,
MemberSignature member, P1 p1,
P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
: object_(object),
member_(member),
p1_(p1),
p2_(p2),
p3_(p3),
p4_(p4),
p5_(p5),
p6_(p6) {}

R Run() override {
if (!del) {
R result = (object_->*member_)(p1_, p2_, p3_, p4_, p5_, p6_);
return result;
}
R result = (object_->*member_)(p1_, p2_, p3_, p4_, p5_, p6_);
// zero out the pointer to ensure segfault if used again
member_ = nullptr;
delete this;
return result;
}
};

template <bool del, class T, class P1, class P2, class P3, class P4, class P5,
class P6>
class _ConstTessMemberResultCallback_6_0<del, void, T, P1, P2, P3, P4, P5, P6>
: public TessClosure {
public:
using base = TessClosure;
using MemberSignature = void (T::*)(P1, P2, P3, P4, P5, P6) const;

private:
const T* object_;
MemberSignature member_;
typename remove_reference<P1>::type p1_;
typename remove_reference<P2>::type p2_;
typename remove_reference<P3>::type p3_;
typename remove_reference<P4>::type p4_;
typename remove_reference<P5>::type p5_;
typename remove_reference<P6>::type p6_;

public:
inline _ConstTessMemberResultCallback_6_0(const T* object,
MemberSignature member, P1 p1,
P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
: object_(object),
member_(member),
p1_(p1),
p2_(p2),
p3_(p3),
p4_(p4),
p5_(p5),
p6_(p6) {}

void Run() override {
if (!del) {
(object_->*member_)(p1_, p2_, p3_, p4_, p5_, p6_);
} else {
(object_->*member_)(p1_, p2_, p3_, p4_, p5_, p6_);
// zero out the pointer to ensure segfault if used again
member_ = nullptr;
delete this;
}
}
};

#ifndef SWIG
template <class T1, class T2, class R, class P1, class P2, class P3, class P4,
class P5, class P6>
inline typename _ConstTessMemberResultCallback_6_0<false, R, T1, P1, P2, P3, P4,
P5, P6>::base*
NewPermanentTessCallback(
const T1* obj, R (T2::*member)(P1, P2, P3, P4, P5, P6) const,
typename Identity<P1>::type p1, typename Identity<P2>::type p2,
typename Identity<P3>::type p3, typename Identity<P4>::type p4,
typename Identity<P5>::type p5, typename Identity<P6>::type p6) {
return new _ConstTessMemberResultCallback_6_0<false, R, T1, P1, P2, P3, P4,
P5, P6>(obj, member, p1, p2, p3,
p4, p5, p6);
}
#endif

template <class A1>
class TessCallback1 {
public:
Expand Down

0 comments on commit cb2957b

Please sign in to comment.