Merge pull request #309 from littletomatodonkey/cpp_infer
add cpp inference
This commit is contained in:
commit
e30f368a27
|
@ -1,5 +1,6 @@
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
.ipynb_checkpoints/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
project(ocr_system CXX C)
|
||||||
|
option(WITH_MKL "Compile demo with MKL/OpenBlas support, default use MKL." ON)
|
||||||
|
option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." OFF)
|
||||||
|
option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." ON)
|
||||||
|
option(USE_TENSORRT "Compile demo with TensorRT." OFF)
|
||||||
|
|
||||||
|
|
||||||
|
macro(safe_set_static_flag)
|
||||||
|
foreach(flag_var
|
||||||
|
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||||
|
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||||
|
if(${flag_var} MATCHES "/MD")
|
||||||
|
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||||
|
endif(${flag_var} MATCHES "/MD")
|
||||||
|
endforeach(flag_var)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -fpermissive")
|
||||||
|
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||||
|
message("flags" ${CMAKE_CXX_FLAGS})
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||||
|
|
||||||
|
if(NOT DEFINED PADDLE_LIB)
|
||||||
|
message(FATAL_ERROR "please set PADDLE_LIB with -DPADDLE_LIB=/path/paddle/lib")
|
||||||
|
endif()
|
||||||
|
if(NOT DEFINED DEMO_NAME)
|
||||||
|
message(FATAL_ERROR "please set DEMO_NAME with -DDEMO_NAME=demo_name")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
set(OPENCV_DIR ${OPENCV_DIR})
|
||||||
|
find_package(OpenCV REQUIRED PATHS ${OPENCV_DIR}/share/OpenCV NO_DEFAULT_PATH)
|
||||||
|
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
include_directories("${PADDLE_LIB}/paddle/include")
|
||||||
|
include_directories("${PADDLE_LIB}/third_party/install/protobuf/include")
|
||||||
|
include_directories("${PADDLE_LIB}/third_party/install/glog/include")
|
||||||
|
include_directories("${PADDLE_LIB}/third_party/install/gflags/include")
|
||||||
|
include_directories("${PADDLE_LIB}/third_party/install/xxhash/include")
|
||||||
|
include_directories("${PADDLE_LIB}/third_party/install/zlib/include")
|
||||||
|
include_directories("${PADDLE_LIB}/third_party/boost")
|
||||||
|
include_directories("${PADDLE_LIB}/third_party/eigen3")
|
||||||
|
|
||||||
|
include_directories("${CMAKE_SOURCE_DIR}/")
|
||||||
|
|
||||||
|
if (USE_TENSORRT AND WITH_GPU)
|
||||||
|
include_directories("${TENSORRT_ROOT}/include")
|
||||||
|
link_directories("${TENSORRT_ROOT}/lib")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
link_directories("${PADDLE_LIB}/third_party/install/zlib/lib")
|
||||||
|
|
||||||
|
link_directories("${PADDLE_LIB}/third_party/install/protobuf/lib")
|
||||||
|
link_directories("${PADDLE_LIB}/third_party/install/glog/lib")
|
||||||
|
link_directories("${PADDLE_LIB}/third_party/install/gflags/lib")
|
||||||
|
link_directories("${PADDLE_LIB}/third_party/install/xxhash/lib")
|
||||||
|
link_directories("${PADDLE_LIB}/paddle/lib")
|
||||||
|
|
||||||
|
|
||||||
|
AUX_SOURCE_DIRECTORY(./src SRCS)
|
||||||
|
add_executable(${DEMO_NAME} ${SRCS})
|
||||||
|
|
||||||
|
if(WITH_MKL)
|
||||||
|
include_directories("${PADDLE_LIB}/third_party/install/mklml/include")
|
||||||
|
set(MATH_LIB ${PADDLE_LIB}/third_party/install/mklml/lib/libmklml_intel${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||||
|
${PADDLE_LIB}/third_party/install/mklml/lib/libiomp5${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||||
|
set(MKLDNN_PATH "${PADDLE_LIB}/third_party/install/mkldnn")
|
||||||
|
if(EXISTS ${MKLDNN_PATH})
|
||||||
|
include_directories("${MKLDNN_PATH}/include")
|
||||||
|
set(MKLDNN_LIB ${MKLDNN_PATH}/lib/libmkldnn.so.0)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(MATH_LIB ${PADDLE_LIB}/third_party/install/openblas/lib/libopenblas${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Note: libpaddle_inference_api.so/a must put before libpaddle_fluid.so/a
|
||||||
|
if(WITH_STATIC_LIB)
|
||||||
|
set(DEPS
|
||||||
|
${PADDLE_LIB}/paddle/lib/libpaddle_fluid${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||||
|
else()
|
||||||
|
set(DEPS
|
||||||
|
${PADDLE_LIB}/paddle/lib/libpaddle_fluid${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(EXTERNAL_LIB "-lrt -ldl -lpthread -lm")
|
||||||
|
|
||||||
|
set(DEPS ${DEPS}
|
||||||
|
${MATH_LIB} ${MKLDNN_LIB}
|
||||||
|
glog gflags protobuf z xxhash
|
||||||
|
${EXTERNAL_LIB} ${OpenCV_LIBS})
|
||||||
|
|
||||||
|
if(WITH_GPU)
|
||||||
|
if (USE_TENSORRT)
|
||||||
|
set(DEPS ${DEPS}
|
||||||
|
${TENSORRT_ROOT}/lib/libnvinfer${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||||
|
set(DEPS ${DEPS}
|
||||||
|
${TENSORRT_ROOT}/lib/libnvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||||
|
endif()
|
||||||
|
set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||||
|
set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX} )
|
||||||
|
set(DEPS ${DEPS} ${CUDA_LIB}/libcublas${CMAKE_SHARED_LIBRARY_SUFFIX} )
|
||||||
|
set(DEPS ${DEPS} ${CUDNN_LIB}/libcudnn${CMAKE_SHARED_LIBRARY_SUFFIX} )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(${DEMO_NAME} ${DEPS})
|
|
@ -0,0 +1,423 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* *
|
||||||
|
* Author : Angus Johnson *
|
||||||
|
* Version : 6.4.2 *
|
||||||
|
* Date : 27 February 2017 *
|
||||||
|
* Website : http://www.angusj.com *
|
||||||
|
* Copyright : Angus Johnson 2010-2017 *
|
||||||
|
* *
|
||||||
|
* License: *
|
||||||
|
* Use, modification & distribution is subject to Boost Software License Ver 1. *
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt *
|
||||||
|
* *
|
||||||
|
* Attributions: *
|
||||||
|
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
|
||||||
|
* "A generic solution to polygon clipping" *
|
||||||
|
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
|
||||||
|
* http://portal.acm.org/citation.cfm?id=129906 *
|
||||||
|
* *
|
||||||
|
* Computer graphics and geometric modeling: implementation and algorithms *
|
||||||
|
* By Max K. Agoston *
|
||||||
|
* Springer; 1 edition (January 4, 2005) *
|
||||||
|
* http://books.google.com/books?q=vatti+clipping+agoston *
|
||||||
|
* *
|
||||||
|
* See also: *
|
||||||
|
* "Polygon Offsetting by Computing Winding Numbers" *
|
||||||
|
* Paper no. DETC2005-85513 pp. 565-575 *
|
||||||
|
* ASME 2005 International Design Engineering Technical Conferences *
|
||||||
|
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
|
||||||
|
* September 24-28, 2005 , Long Beach, California, USA *
|
||||||
|
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
|
||||||
|
* *
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef clipper_hpp
|
||||||
|
#define clipper_hpp
|
||||||
|
|
||||||
|
#define CLIPPER_VERSION "6.4.2"
|
||||||
|
|
||||||
|
// use_int32: When enabled 32bit ints are used instead of 64bit ints. This
|
||||||
|
// improve performance but coordinate values are limited to the range +/- 46340
|
||||||
|
//#define use_int32
|
||||||
|
|
||||||
|
// use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
|
||||||
|
//#define use_xyz
|
||||||
|
|
||||||
|
// use_lines: Enables line clipping. Adds a very minor cost to performance.
|
||||||
|
#define use_lines
|
||||||
|
|
||||||
|
// use_deprecated: Enables temporary support for the obsolete functions
|
||||||
|
//#define use_deprecated
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
#include <list>
|
||||||
|
#include <ostream>
|
||||||
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ClipperLib {
|
||||||
|
|
||||||
|
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
|
||||||
|
enum PolyType { ptSubject, ptClip };
|
||||||
|
// By far the most widely used winding rules for polygon filling are
|
||||||
|
// EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
|
||||||
|
// Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
|
||||||
|
// see http://glprogramming.com/red/chapter11.html
|
||||||
|
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
|
||||||
|
|
||||||
|
#ifdef use_int32
|
||||||
|
typedef int cInt;
|
||||||
|
static cInt const loRange = 0x7FFF;
|
||||||
|
static cInt const hiRange = 0x7FFF;
|
||||||
|
#else
|
||||||
|
typedef signed long long cInt;
|
||||||
|
static cInt const loRange = 0x3FFFFFFF;
|
||||||
|
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
|
||||||
|
typedef signed long long long64; // used by Int128 class
|
||||||
|
typedef unsigned long long ulong64;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct IntPoint {
|
||||||
|
cInt X;
|
||||||
|
cInt Y;
|
||||||
|
#ifdef use_xyz
|
||||||
|
cInt Z;
|
||||||
|
IntPoint(cInt x = 0, cInt y = 0, cInt z = 0) : X(x), Y(y), Z(z){};
|
||||||
|
#else
|
||||||
|
IntPoint(cInt x = 0, cInt y = 0) : X(x), Y(y){};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
friend inline bool operator==(const IntPoint &a, const IntPoint &b) {
|
||||||
|
return a.X == b.X && a.Y == b.Y;
|
||||||
|
}
|
||||||
|
friend inline bool operator!=(const IntPoint &a, const IntPoint &b) {
|
||||||
|
return a.X != b.X || a.Y != b.Y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef std::vector<IntPoint> Path;
|
||||||
|
typedef std::vector<Path> Paths;
|
||||||
|
|
||||||
|
inline Path &operator<<(Path &poly, const IntPoint &p) {
|
||||||
|
poly.push_back(p);
|
||||||
|
return poly;
|
||||||
|
}
|
||||||
|
inline Paths &operator<<(Paths &polys, const Path &p) {
|
||||||
|
polys.push_back(p);
|
||||||
|
return polys;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &s, const IntPoint &p);
|
||||||
|
std::ostream &operator<<(std::ostream &s, const Path &p);
|
||||||
|
std::ostream &operator<<(std::ostream &s, const Paths &p);
|
||||||
|
|
||||||
|
struct DoublePoint {
|
||||||
|
double X;
|
||||||
|
double Y;
|
||||||
|
DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
|
||||||
|
DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef use_xyz
|
||||||
|
typedef void (*ZFillCallback)(IntPoint &e1bot, IntPoint &e1top, IntPoint &e2bot,
|
||||||
|
IntPoint &e2top, IntPoint &pt);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum InitOptions {
|
||||||
|
ioReverseSolution = 1,
|
||||||
|
ioStrictlySimple = 2,
|
||||||
|
ioPreserveCollinear = 4
|
||||||
|
};
|
||||||
|
enum JoinType { jtSquare, jtRound, jtMiter };
|
||||||
|
enum EndType {
|
||||||
|
etClosedPolygon,
|
||||||
|
etClosedLine,
|
||||||
|
etOpenButt,
|
||||||
|
etOpenSquare,
|
||||||
|
etOpenRound
|
||||||
|
};
|
||||||
|
|
||||||
|
class PolyNode;
|
||||||
|
typedef std::vector<PolyNode *> PolyNodes;
|
||||||
|
|
||||||
|
class PolyNode {
|
||||||
|
public:
|
||||||
|
PolyNode();
|
||||||
|
virtual ~PolyNode(){};
|
||||||
|
Path Contour;
|
||||||
|
PolyNodes Childs;
|
||||||
|
PolyNode *Parent;
|
||||||
|
PolyNode *GetNext() const;
|
||||||
|
bool IsHole() const;
|
||||||
|
bool IsOpen() const;
|
||||||
|
int ChildCount() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// PolyNode& operator =(PolyNode& other);
|
||||||
|
unsigned Index; // node index in Parent.Childs
|
||||||
|
bool m_IsOpen;
|
||||||
|
JoinType m_jointype;
|
||||||
|
EndType m_endtype;
|
||||||
|
PolyNode *GetNextSiblingUp() const;
|
||||||
|
void AddChild(PolyNode &child);
|
||||||
|
friend class Clipper; // to access Index
|
||||||
|
friend class ClipperOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PolyTree : public PolyNode {
|
||||||
|
public:
|
||||||
|
~PolyTree() { Clear(); };
|
||||||
|
PolyNode *GetFirst() const;
|
||||||
|
void Clear();
|
||||||
|
int Total() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// PolyTree& operator =(PolyTree& other);
|
||||||
|
PolyNodes AllNodes;
|
||||||
|
friend class Clipper; // to access AllNodes
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Orientation(const Path &poly);
|
||||||
|
double Area(const Path &poly);
|
||||||
|
int PointInPolygon(const IntPoint &pt, const Path &path);
|
||||||
|
|
||||||
|
void SimplifyPolygon(const Path &in_poly, Paths &out_polys,
|
||||||
|
PolyFillType fillType = pftEvenOdd);
|
||||||
|
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys,
|
||||||
|
PolyFillType fillType = pftEvenOdd);
|
||||||
|
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
|
||||||
|
|
||||||
|
void CleanPolygon(const Path &in_poly, Path &out_poly, double distance = 1.415);
|
||||||
|
void CleanPolygon(Path &poly, double distance = 1.415);
|
||||||
|
void CleanPolygons(const Paths &in_polys, Paths &out_polys,
|
||||||
|
double distance = 1.415);
|
||||||
|
void CleanPolygons(Paths &polys, double distance = 1.415);
|
||||||
|
|
||||||
|
void MinkowskiSum(const Path &pattern, const Path &path, Paths &solution,
|
||||||
|
bool pathIsClosed);
|
||||||
|
void MinkowskiSum(const Path &pattern, const Paths &paths, Paths &solution,
|
||||||
|
bool pathIsClosed);
|
||||||
|
void MinkowskiDiff(const Path &poly1, const Path &poly2, Paths &solution);
|
||||||
|
|
||||||
|
void PolyTreeToPaths(const PolyTree &polytree, Paths &paths);
|
||||||
|
void ClosedPathsFromPolyTree(const PolyTree &polytree, Paths &paths);
|
||||||
|
void OpenPathsFromPolyTree(PolyTree &polytree, Paths &paths);
|
||||||
|
|
||||||
|
void ReversePath(Path &p);
|
||||||
|
void ReversePaths(Paths &p);
|
||||||
|
|
||||||
|
struct IntRect {
|
||||||
|
cInt left;
|
||||||
|
cInt top;
|
||||||
|
cInt right;
|
||||||
|
cInt bottom;
|
||||||
|
};
|
||||||
|
|
||||||
|
// enums that are used internally ...
|
||||||
|
enum EdgeSide { esLeft = 1, esRight = 2 };
|
||||||
|
|
||||||
|
// forward declarations (for stuff used internally) ...
|
||||||
|
struct TEdge;
|
||||||
|
struct IntersectNode;
|
||||||
|
struct LocalMinimum;
|
||||||
|
struct OutPt;
|
||||||
|
struct OutRec;
|
||||||
|
struct Join;
|
||||||
|
|
||||||
|
typedef std::vector<OutRec *> PolyOutList;
|
||||||
|
typedef std::vector<TEdge *> EdgeList;
|
||||||
|
typedef std::vector<Join *> JoinList;
|
||||||
|
typedef std::vector<IntersectNode *> IntersectList;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ClipperBase is the ancestor to the Clipper class. It should not be
|
||||||
|
// instantiated directly. This class simply abstracts the conversion of sets of
|
||||||
|
// polygon coordinates into edge objects that are stored in a LocalMinima list.
|
||||||
|
class ClipperBase {
|
||||||
|
public:
|
||||||
|
ClipperBase();
|
||||||
|
virtual ~ClipperBase();
|
||||||
|
virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
|
||||||
|
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
|
||||||
|
virtual void Clear();
|
||||||
|
IntRect GetBounds();
|
||||||
|
bool PreserveCollinear() { return m_PreserveCollinear; };
|
||||||
|
void PreserveCollinear(bool value) { m_PreserveCollinear = value; };
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void DisposeLocalMinimaList();
|
||||||
|
TEdge *AddBoundsToLML(TEdge *e, bool IsClosed);
|
||||||
|
virtual void Reset();
|
||||||
|
TEdge *ProcessBound(TEdge *E, bool IsClockwise);
|
||||||
|
void InsertScanbeam(const cInt Y);
|
||||||
|
bool PopScanbeam(cInt &Y);
|
||||||
|
bool LocalMinimaPending();
|
||||||
|
bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin);
|
||||||
|
OutRec *CreateOutRec();
|
||||||
|
void DisposeAllOutRecs();
|
||||||
|
void DisposeOutRec(PolyOutList::size_type index);
|
||||||
|
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
|
||||||
|
void DeleteFromAEL(TEdge *e);
|
||||||
|
void UpdateEdgeIntoAEL(TEdge *&e);
|
||||||
|
|
||||||
|
typedef std::vector<LocalMinimum> MinimaList;
|
||||||
|
MinimaList::iterator m_CurrentLM;
|
||||||
|
MinimaList m_MinimaList;
|
||||||
|
|
||||||
|
bool m_UseFullRange;
|
||||||
|
EdgeList m_edges;
|
||||||
|
bool m_PreserveCollinear;
|
||||||
|
bool m_HasOpenPaths;
|
||||||
|
PolyOutList m_PolyOuts;
|
||||||
|
TEdge *m_ActiveEdges;
|
||||||
|
|
||||||
|
typedef std::priority_queue<cInt> ScanbeamList;
|
||||||
|
ScanbeamList m_Scanbeam;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class Clipper : public virtual ClipperBase {
|
||||||
|
public:
|
||||||
|
Clipper(int initOptions = 0);
|
||||||
|
bool Execute(ClipType clipType, Paths &solution,
|
||||||
|
PolyFillType fillType = pftEvenOdd);
|
||||||
|
bool Execute(ClipType clipType, Paths &solution, PolyFillType subjFillType,
|
||||||
|
PolyFillType clipFillType);
|
||||||
|
bool Execute(ClipType clipType, PolyTree &polytree,
|
||||||
|
PolyFillType fillType = pftEvenOdd);
|
||||||
|
bool Execute(ClipType clipType, PolyTree &polytree, PolyFillType subjFillType,
|
||||||
|
PolyFillType clipFillType);
|
||||||
|
bool ReverseSolution() { return m_ReverseOutput; };
|
||||||
|
void ReverseSolution(bool value) { m_ReverseOutput = value; };
|
||||||
|
bool StrictlySimple() { return m_StrictSimple; };
|
||||||
|
void StrictlySimple(bool value) { m_StrictSimple = value; };
|
||||||
|
// set the callback function for z value filling on intersections (otherwise Z
|
||||||
|
// is 0)
|
||||||
|
#ifdef use_xyz
|
||||||
|
void ZFillFunction(ZFillCallback zFillFunc);
|
||||||
|
#endif
|
||||||
|
protected:
|
||||||
|
virtual bool ExecuteInternal();
|
||||||
|
|
||||||
|
private:
|
||||||
|
JoinList m_Joins;
|
||||||
|
JoinList m_GhostJoins;
|
||||||
|
IntersectList m_IntersectList;
|
||||||
|
ClipType m_ClipType;
|
||||||
|
typedef std::list<cInt> MaximaList;
|
||||||
|
MaximaList m_Maxima;
|
||||||
|
TEdge *m_SortedEdges;
|
||||||
|
bool m_ExecuteLocked;
|
||||||
|
PolyFillType m_ClipFillType;
|
||||||
|
PolyFillType m_SubjFillType;
|
||||||
|
bool m_ReverseOutput;
|
||||||
|
bool m_UsingPolyTree;
|
||||||
|
bool m_StrictSimple;
|
||||||
|
#ifdef use_xyz
|
||||||
|
ZFillCallback m_ZFill; // custom callback
|
||||||
|
#endif
|
||||||
|
void SetWindingCount(TEdge &edge);
|
||||||
|
bool IsEvenOddFillType(const TEdge &edge) const;
|
||||||
|
bool IsEvenOddAltFillType(const TEdge &edge) const;
|
||||||
|
void InsertLocalMinimaIntoAEL(const cInt botY);
|
||||||
|
void InsertEdgeIntoAEL(TEdge *edge, TEdge *startEdge);
|
||||||
|
void AddEdgeToSEL(TEdge *edge);
|
||||||
|
bool PopEdgeFromSEL(TEdge *&edge);
|
||||||
|
void CopyAELToSEL();
|
||||||
|
void DeleteFromSEL(TEdge *e);
|
||||||
|
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
|
||||||
|
bool IsContributing(const TEdge &edge) const;
|
||||||
|
bool IsTopHorz(const cInt XPos);
|
||||||
|
void DoMaxima(TEdge *e);
|
||||||
|
void ProcessHorizontals();
|
||||||
|
void ProcessHorizontal(TEdge *horzEdge);
|
||||||
|
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||||
|
OutPt *AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||||
|
OutRec *GetOutRec(int idx);
|
||||||
|
void AppendPolygon(TEdge *e1, TEdge *e2);
|
||||||
|
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
|
||||||
|
OutPt *AddOutPt(TEdge *e, const IntPoint &pt);
|
||||||
|
OutPt *GetLastOutPt(TEdge *e);
|
||||||
|
bool ProcessIntersections(const cInt topY);
|
||||||
|
void BuildIntersectList(const cInt topY);
|
||||||
|
void ProcessIntersectList();
|
||||||
|
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
|
||||||
|
void BuildResult(Paths &polys);
|
||||||
|
void BuildResult2(PolyTree &polytree);
|
||||||
|
void SetHoleState(TEdge *e, OutRec *outrec);
|
||||||
|
void DisposeIntersectNodes();
|
||||||
|
bool FixupIntersectionOrder();
|
||||||
|
void FixupOutPolygon(OutRec &outrec);
|
||||||
|
void FixupOutPolyline(OutRec &outrec);
|
||||||
|
bool IsHole(TEdge *e);
|
||||||
|
bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
|
||||||
|
void FixHoleLinkage(OutRec &outrec);
|
||||||
|
void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt);
|
||||||
|
void ClearJoins();
|
||||||
|
void ClearGhostJoins();
|
||||||
|
void AddGhostJoin(OutPt *op, const IntPoint offPt);
|
||||||
|
bool JoinPoints(Join *j, OutRec *outRec1, OutRec *outRec2);
|
||||||
|
void JoinCommonEdges();
|
||||||
|
void DoSimplePolygons();
|
||||||
|
void FixupFirstLefts1(OutRec *OldOutRec, OutRec *NewOutRec);
|
||||||
|
void FixupFirstLefts2(OutRec *InnerOutRec, OutRec *OuterOutRec);
|
||||||
|
void FixupFirstLefts3(OutRec *OldOutRec, OutRec *NewOutRec);
|
||||||
|
#ifdef use_xyz
|
||||||
|
void SetZ(IntPoint &pt, TEdge &e1, TEdge &e2);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ClipperOffset {
|
||||||
|
public:
|
||||||
|
ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
|
||||||
|
~ClipperOffset();
|
||||||
|
void AddPath(const Path &path, JoinType joinType, EndType endType);
|
||||||
|
void AddPaths(const Paths &paths, JoinType joinType, EndType endType);
|
||||||
|
void Execute(Paths &solution, double delta);
|
||||||
|
void Execute(PolyTree &solution, double delta);
|
||||||
|
void Clear();
|
||||||
|
double MiterLimit;
|
||||||
|
double ArcTolerance;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Paths m_destPolys;
|
||||||
|
Path m_srcPoly;
|
||||||
|
Path m_destPoly;
|
||||||
|
std::vector<DoublePoint> m_normals;
|
||||||
|
double m_delta, m_sinA, m_sin, m_cos;
|
||||||
|
double m_miterLim, m_StepsPerRad;
|
||||||
|
IntPoint m_lowest;
|
||||||
|
PolyNode m_polyNodes;
|
||||||
|
|
||||||
|
void FixOrientations();
|
||||||
|
void DoOffset(double delta);
|
||||||
|
void OffsetPoint(int j, int &k, JoinType jointype);
|
||||||
|
void DoSquare(int j, int k);
|
||||||
|
void DoMiter(int j, int k, double r);
|
||||||
|
void DoRound(int j, int k);
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class clipperException : public std::exception {
|
||||||
|
public:
|
||||||
|
clipperException(const char *description) : m_descr(description) {}
|
||||||
|
virtual ~clipperException() throw() {}
|
||||||
|
virtual const char *what() const throw() { return m_descr.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_descr;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
} // ClipperLib namespace
|
||||||
|
|
||||||
|
#endif // clipper_hpp
|
|
@ -0,0 +1,95 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "include/utility.h"
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
public:
|
||||||
|
explicit Config(const std::string &config_file) {
|
||||||
|
config_map_ = LoadConfig(config_file);
|
||||||
|
|
||||||
|
this->use_gpu = bool(stoi(config_map_["use_gpu"]));
|
||||||
|
|
||||||
|
this->gpu_id = stoi(config_map_["gpu_id"]);
|
||||||
|
|
||||||
|
this->gpu_mem = stoi(config_map_["gpu_mem"]);
|
||||||
|
|
||||||
|
this->cpu_math_library_num_threads =
|
||||||
|
stoi(config_map_["cpu_math_library_num_threads"]);
|
||||||
|
|
||||||
|
this->max_side_len = stoi(config_map_["max_side_len"]);
|
||||||
|
|
||||||
|
this->det_db_thresh = stod(config_map_["det_db_thresh"]);
|
||||||
|
|
||||||
|
this->det_db_box_thresh = stod(config_map_["det_db_box_thresh"]);
|
||||||
|
|
||||||
|
this->det_db_box_thresh = stod(config_map_["det_db_box_thresh"]);
|
||||||
|
|
||||||
|
this->det_model_dir.assign(config_map_["det_model_dir"]);
|
||||||
|
|
||||||
|
this->rec_model_dir.assign(config_map_["rec_model_dir"]);
|
||||||
|
|
||||||
|
this->char_list_file.assign(config_map_["char_list_file"]);
|
||||||
|
|
||||||
|
this->visualize = bool(stoi(config_map_["visualize"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool use_gpu = false;
|
||||||
|
|
||||||
|
int gpu_id = 0;
|
||||||
|
|
||||||
|
int gpu_mem = 4000;
|
||||||
|
|
||||||
|
int cpu_math_library_num_threads = 1;
|
||||||
|
|
||||||
|
int max_side_len = 960;
|
||||||
|
|
||||||
|
double det_db_thresh = 0.3;
|
||||||
|
|
||||||
|
double det_db_box_thresh = 0.5;
|
||||||
|
|
||||||
|
double det_db_unclip_ratio = 2.0;
|
||||||
|
|
||||||
|
std::string det_model_dir;
|
||||||
|
|
||||||
|
std::string rec_model_dir;
|
||||||
|
|
||||||
|
std::string char_list_file;
|
||||||
|
|
||||||
|
bool visualize = true;
|
||||||
|
|
||||||
|
void PrintConfigInfo();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Load configuration
|
||||||
|
std::map<std::string, std::string> LoadConfig(const std::string &config_file);
|
||||||
|
|
||||||
|
std::vector<std::string> split(const std::string &str,
|
||||||
|
const std::string &delim);
|
||||||
|
|
||||||
|
std::map<std::string, std::string> config_map_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,97 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "opencv2/core.hpp"
|
||||||
|
#include "opencv2/imgcodecs.hpp"
|
||||||
|
#include "opencv2/imgproc.hpp"
|
||||||
|
#include "paddle_api.h"
|
||||||
|
#include "paddle_inference_api.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include <include/postprocess_op.h>
|
||||||
|
#include <include/preprocess_op.h>
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
class DBDetector {
|
||||||
|
public:
|
||||||
|
explicit DBDetector(const std::string &model_dir, const bool &use_gpu,
|
||||||
|
const int &gpu_id, const int &gpu_mem,
|
||||||
|
const int &cpu_math_library_num_threads,
|
||||||
|
const int &max_side_len, const double &det_db_thresh,
|
||||||
|
const double &det_db_box_thresh,
|
||||||
|
const double &det_db_unclip_ratio,
|
||||||
|
const bool &visualize) {
|
||||||
|
this->use_gpu_ = use_gpu;
|
||||||
|
this->gpu_id_ = gpu_id;
|
||||||
|
this->gpu_mem_ = gpu_mem;
|
||||||
|
this->cpu_math_library_num_threads_ = cpu_math_library_num_threads;
|
||||||
|
|
||||||
|
this->max_side_len_ = max_side_len;
|
||||||
|
|
||||||
|
this->det_db_thresh_ = det_db_thresh;
|
||||||
|
this->det_db_box_thresh_ = det_db_box_thresh;
|
||||||
|
this->det_db_unclip_ratio_ = det_db_unclip_ratio;
|
||||||
|
|
||||||
|
this->visualize_ = visualize;
|
||||||
|
|
||||||
|
LoadModel(model_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Paddle inference model
|
||||||
|
void LoadModel(const std::string &model_dir);
|
||||||
|
|
||||||
|
// Run predictor
|
||||||
|
void Run(cv::Mat &img, std::vector<std::vector<std::vector<int>>> &boxes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<PaddlePredictor> predictor_;
|
||||||
|
|
||||||
|
bool use_gpu_ = false;
|
||||||
|
int gpu_id_ = 0;
|
||||||
|
int gpu_mem_ = 4000;
|
||||||
|
int cpu_math_library_num_threads_ = 4;
|
||||||
|
|
||||||
|
int max_side_len_ = 960;
|
||||||
|
|
||||||
|
double det_db_thresh_ = 0.3;
|
||||||
|
double det_db_box_thresh_ = 0.5;
|
||||||
|
double det_db_unclip_ratio_ = 2.0;
|
||||||
|
|
||||||
|
bool visualize_ = true;
|
||||||
|
|
||||||
|
std::vector<float> mean_ = {0.485f, 0.456f, 0.406f};
|
||||||
|
std::vector<float> scale_ = {1 / 0.229f, 1 / 0.224f, 1 / 0.225f};
|
||||||
|
bool is_scale_ = true;
|
||||||
|
|
||||||
|
// pre-process
|
||||||
|
ResizeImgType0 resize_op_;
|
||||||
|
Normalize normalize_op_;
|
||||||
|
Permute permute_op_;
|
||||||
|
|
||||||
|
// post-process
|
||||||
|
PostProcessor post_processor_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "opencv2/core.hpp"
|
||||||
|
#include "opencv2/imgcodecs.hpp"
|
||||||
|
#include "opencv2/imgproc.hpp"
|
||||||
|
#include "paddle_api.h"
|
||||||
|
#include "paddle_inference_api.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include <include/postprocess_op.h>
|
||||||
|
#include <include/preprocess_op.h>
|
||||||
|
#include <include/utility.h>
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
class CRNNRecognizer {
|
||||||
|
public:
|
||||||
|
explicit CRNNRecognizer(const std::string &model_dir, const bool &use_gpu,
|
||||||
|
const int &gpu_id, const int &gpu_mem,
|
||||||
|
const int &cpu_math_library_num_threads,
|
||||||
|
const string &label_path) {
|
||||||
|
this->use_gpu_ = use_gpu;
|
||||||
|
this->gpu_id_ = gpu_id;
|
||||||
|
this->gpu_mem_ = gpu_mem;
|
||||||
|
this->cpu_math_library_num_threads_ = cpu_math_library_num_threads;
|
||||||
|
|
||||||
|
this->label_list_ = Utility::ReadDict(label_path);
|
||||||
|
|
||||||
|
LoadModel(model_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Paddle inference model
|
||||||
|
void LoadModel(const std::string &model_dir);
|
||||||
|
|
||||||
|
void Run(std::vector<std::vector<std::vector<int>>> boxes, cv::Mat &img);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<PaddlePredictor> predictor_;
|
||||||
|
|
||||||
|
bool use_gpu_ = false;
|
||||||
|
int gpu_id_ = 0;
|
||||||
|
int gpu_mem_ = 4000;
|
||||||
|
int cpu_math_library_num_threads_ = 4;
|
||||||
|
|
||||||
|
std::vector<std::string> label_list_;
|
||||||
|
|
||||||
|
std::vector<float> mean_ = {0.5f, 0.5f, 0.5f};
|
||||||
|
std::vector<float> scale_ = {1 / 0.5f, 1 / 0.5f, 1 / 0.5f};
|
||||||
|
bool is_scale_ = true;
|
||||||
|
|
||||||
|
// pre-process
|
||||||
|
CrnnResizeImg resize_op_;
|
||||||
|
Normalize normalize_op_;
|
||||||
|
Permute permute_op_;
|
||||||
|
|
||||||
|
// post-process
|
||||||
|
PostProcessor post_processor_;
|
||||||
|
|
||||||
|
cv::Mat GetRotateCropImage(const cv::Mat &srcimage,
|
||||||
|
std::vector<std::vector<int>> box);
|
||||||
|
|
||||||
|
}; // class CrnnRecognizer
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "opencv2/core.hpp"
|
||||||
|
#include "opencv2/imgcodecs.hpp"
|
||||||
|
#include "opencv2/imgproc.hpp"
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include "include/clipper.h"
|
||||||
|
#include "include/utility.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
class PostProcessor {
|
||||||
|
public:
|
||||||
|
void GetContourArea(const std::vector<std::vector<float>> &box,
|
||||||
|
float unclip_ratio, float &distance);
|
||||||
|
|
||||||
|
cv::RotatedRect UnClip(std::vector<std::vector<float>> box,
|
||||||
|
const float &unclip_ratio);
|
||||||
|
|
||||||
|
float **Mat2Vec(cv::Mat mat);
|
||||||
|
|
||||||
|
std::vector<std::vector<int>>
|
||||||
|
OrderPointsClockwise(std::vector<std::vector<int>> pts);
|
||||||
|
|
||||||
|
std::vector<std::vector<float>> GetMiniBoxes(cv::RotatedRect box,
|
||||||
|
float &ssid);
|
||||||
|
|
||||||
|
float BoxScoreFast(std::vector<std::vector<float>> box_array, cv::Mat pred);
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<int>>>
|
||||||
|
BoxesFromBitmap(const cv::Mat pred, const cv::Mat bitmap,
|
||||||
|
const float &box_thresh, const float &det_db_unclip_ratio);
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<int>>>
|
||||||
|
FilterTagDetRes(std::vector<std::vector<std::vector<int>>> boxes,
|
||||||
|
float ratio_h, float ratio_w, cv::Mat srcimg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool XsortInt(std::vector<int> a, std::vector<int> b);
|
||||||
|
|
||||||
|
static bool XsortFp32(std::vector<float> a, std::vector<float> b);
|
||||||
|
|
||||||
|
std::vector<std::vector<float>> Mat2Vector(cv::Mat mat);
|
||||||
|
|
||||||
|
inline int _max(int a, int b) { return a >= b ? a : b; }
|
||||||
|
|
||||||
|
inline int _min(int a, int b) { return a >= b ? b : a; }
|
||||||
|
|
||||||
|
template <class T> inline T clamp(T x, T min, T max) {
|
||||||
|
if (x > max)
|
||||||
|
return max;
|
||||||
|
if (x < min)
|
||||||
|
return min;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float clampf(float x, float min, float max) {
|
||||||
|
if (x > max)
|
||||||
|
return max;
|
||||||
|
if (x < min)
|
||||||
|
return min;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "opencv2/core.hpp"
|
||||||
|
#include "opencv2/imgcodecs.hpp"
|
||||||
|
#include "opencv2/imgproc.hpp"
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace paddle;
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
class Normalize {
|
||||||
|
public:
|
||||||
|
virtual void Run(cv::Mat *im, const std::vector<float> &mean,
|
||||||
|
const std::vector<float> &scale, const bool is_scale = true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// RGB -> CHW
|
||||||
|
class Permute {
|
||||||
|
public:
|
||||||
|
virtual void Run(const cv::Mat *im, float *data);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ResizeImgType0 {
|
||||||
|
public:
|
||||||
|
virtual void Run(const cv::Mat &img, cv::Mat &resize_img, int max_size_len,
|
||||||
|
float &ratio_h, float &ratio_w);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CrnnResizeImg {
|
||||||
|
public:
|
||||||
|
virtual void Run(const cv::Mat &img, cv::Mat &resize_img, float wh_ratio,
|
||||||
|
const std::vector<int> &rec_image_shape = {3, 32, 320});
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include "opencv2/core.hpp"
|
||||||
|
#include "opencv2/imgcodecs.hpp"
|
||||||
|
#include "opencv2/imgproc.hpp"
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
class Utility {
|
||||||
|
public:
|
||||||
|
static std::vector<std::string> ReadDict(const std::string &path);
|
||||||
|
|
||||||
|
static void
|
||||||
|
VisualizeBboxes(const cv::Mat &srcimg,
|
||||||
|
const std::vector<std::vector<std::vector<int>>> &boxes);
|
||||||
|
|
||||||
|
template <class ForwardIterator>
|
||||||
|
inline static size_t argmax(ForwardIterator first, ForwardIterator last) {
|
||||||
|
return std::distance(first, std::max_element(first, last));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,197 @@
|
||||||
|
# 服务器端C++预测
|
||||||
|
|
||||||
|
本教程将介绍在服务器端部署PaddleOCR超轻量中文检测、识别模型的详细步骤。
|
||||||
|
|
||||||
|
|
||||||
|
## 1. 准备环境
|
||||||
|
|
||||||
|
### 运行准备
|
||||||
|
- Linux环境,推荐使用docker。
|
||||||
|
|
||||||
|
### 1.1 编译opencv库
|
||||||
|
|
||||||
|
* 首先需要从opencv官网上下载在Linux环境下源码编译的包,以opencv3.4.7为例,下载命令如下。
|
||||||
|
|
||||||
|
```
|
||||||
|
wget https://github.com/opencv/opencv/archive/3.4.7.tar.gz
|
||||||
|
tar -xf 3.4.7.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
最终可以在当前目录下看到`opencv-3.4.7/`的文件夹。
|
||||||
|
|
||||||
|
* 编译opencv,设置opencv源码路径(`root_path`)以及安装路径(`install_path`)。进入opencv源码路径下,按照下面的方式进行编译。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
root_path=your_opencv_root_path
|
||||||
|
install_path=${root_path}/opencv3
|
||||||
|
|
||||||
|
rm -rf build
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
cmake .. \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=${install_path} \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DBUILD_SHARED_LIBS=OFF \
|
||||||
|
-DWITH_IPP=OFF \
|
||||||
|
-DBUILD_IPP_IW=OFF \
|
||||||
|
-DWITH_LAPACK=OFF \
|
||||||
|
-DWITH_EIGEN=OFF \
|
||||||
|
-DCMAKE_INSTALL_LIBDIR=lib64 \
|
||||||
|
-DWITH_ZLIB=ON \
|
||||||
|
-DBUILD_ZLIB=ON \
|
||||||
|
-DWITH_JPEG=ON \
|
||||||
|
-DBUILD_JPEG=ON \
|
||||||
|
-DWITH_PNG=ON \
|
||||||
|
-DBUILD_PNG=ON \
|
||||||
|
-DWITH_TIFF=ON \
|
||||||
|
-DBUILD_TIFF=ON
|
||||||
|
|
||||||
|
make -j
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
其中`root_path`为下载的opencv源码路径,`install_path`为opencv的安装路径,`make install`完成之后,会在该文件夹下生成opencv头文件和库文件,用于后面的OCR代码编译。
|
||||||
|
|
||||||
|
最终在安装路径下的文件结构如下所示。
|
||||||
|
|
||||||
|
```
|
||||||
|
opencv3/
|
||||||
|
|-- bin
|
||||||
|
|-- include
|
||||||
|
|-- lib
|
||||||
|
|-- lib64
|
||||||
|
|-- share
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.2 下载或者编译Paddle预测库
|
||||||
|
|
||||||
|
* 有2种方式获取Paddle预测库,下面进行详细介绍。
|
||||||
|
|
||||||
|
#### 1.2.1 预测库源码编译
|
||||||
|
* 如果希望获取最新预测库特性,可以从Paddle github上克隆最新代码,源码编译预测库。
|
||||||
|
* 可以参考[Paddle预测库官网](https://www.paddlepaddle.org.cn/documentation/docs/zh/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html)的说明,从github上获取Paddle代码,然后进行编译,生成最新的预测库。使用git获取代码方法如下。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/PaddlePaddle/Paddle.git
|
||||||
|
```
|
||||||
|
|
||||||
|
* 进入Paddle目录后,编译方法如下。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
rm -rf build
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
cmake .. \
|
||||||
|
-DWITH_CONTRIB=OFF \
|
||||||
|
-DWITH_MKL=ON \
|
||||||
|
-DWITH_MKLDNN=ON \
|
||||||
|
-DWITH_TESTING=OFF \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DWITH_INFERENCE_API_TEST=OFF \
|
||||||
|
-DON_INFER=ON \
|
||||||
|
-DWITH_PYTHON=ON
|
||||||
|
make -j
|
||||||
|
make inference_lib_dist
|
||||||
|
```
|
||||||
|
|
||||||
|
更多编译参数选项可以参考Paddle C++预测库官网:[https://www.paddlepaddle.org.cn/documentation/docs/zh/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html](https://www.paddlepaddle.org.cn/documentation/docs/zh/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html)。
|
||||||
|
|
||||||
|
|
||||||
|
* 编译完成之后,可以在`build/fluid_inference_install_dir/`文件下看到生成了以下文件及文件夹。
|
||||||
|
|
||||||
|
```
|
||||||
|
build/fluid_inference_install_dir/
|
||||||
|
|-- CMakeCache.txt
|
||||||
|
|-- paddle
|
||||||
|
|-- third_party
|
||||||
|
|-- version.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
其中`paddle`就是之后进行C++预测时所需的Paddle库,`version.txt`中包含当前预测库的版本信息。
|
||||||
|
|
||||||
|
#### 1.2.2 直接下载安装
|
||||||
|
|
||||||
|
* [Paddle预测库官网](https://www.paddlepaddle.org.cn/documentation/docs/zh/advanced_guide/inference_deployment/inference/build_and_install_lib_cn.html)上提供了不同cuda版本的Linux预测库,可以在官网查看并选择合适的预测库版本。
|
||||||
|
|
||||||
|
* 下载之后使用下面的方法解压。
|
||||||
|
|
||||||
|
```
|
||||||
|
tar -xf fluid_inference.tgz
|
||||||
|
```
|
||||||
|
|
||||||
|
最终会在当前的文件夹中生成`fluid_inference/`的子文件夹。
|
||||||
|
|
||||||
|
|
||||||
|
## 2 开始运行
|
||||||
|
|
||||||
|
### 2.1 将模型导出为inference model
|
||||||
|
|
||||||
|
* 可以参考[模型预测章节](../../doc/doc_ch/inference.md),导出inference model,用于模型预测。模型导出之后,假设放在`inference`目录下,则目录结构如下。
|
||||||
|
|
||||||
|
```
|
||||||
|
inference/
|
||||||
|
|-- det_db
|
||||||
|
| |--model
|
||||||
|
| |--params
|
||||||
|
|-- rec_rcnn
|
||||||
|
| |--model
|
||||||
|
| |--params
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 2.2 编译PaddleOCR C++预测demo
|
||||||
|
|
||||||
|
* 编译命令如下,其中Paddle C++预测库、opencv等其他依赖库的地址需要换成自己机器上的实际地址。
|
||||||
|
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sh tools/build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
具体地,`tools/build.sh`中内容如下。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
OPENCV_DIR=your_opencv_dir
|
||||||
|
LIB_DIR=your_paddle_inference_dir
|
||||||
|
CUDA_LIB_DIR=your_cuda_lib_dir
|
||||||
|
CUDNN_LIB_DIR=/your_cudnn_lib_dir
|
||||||
|
|
||||||
|
BUILD_DIR=build
|
||||||
|
rm -rf ${BUILD_DIR}
|
||||||
|
mkdir ${BUILD_DIR}
|
||||||
|
cd ${BUILD_DIR}
|
||||||
|
cmake .. \
|
||||||
|
-DPADDLE_LIB=${LIB_DIR} \
|
||||||
|
-DWITH_MKL=ON \
|
||||||
|
-DDEMO_NAME=ocr_system \
|
||||||
|
-DWITH_GPU=OFF \
|
||||||
|
-DWITH_STATIC_LIB=OFF \
|
||||||
|
-DUSE_TENSORRT=OFF \
|
||||||
|
-DOPENCV_DIR=${OPENCV_DIR} \
|
||||||
|
-DCUDNN_LIB=${CUDNN_LIB_DIR} \
|
||||||
|
-DCUDA_LIB=${CUDA_LIB_DIR} \
|
||||||
|
|
||||||
|
make -j
|
||||||
|
```
|
||||||
|
|
||||||
|
`OPENCV_DIR`为opencv编译安装的地址;`LIB_DIR`为下载(`fluid_inference`文件夹)或者编译生成的Paddle预测库地址(`build/fluid_inference_install_dir`文件夹);`CUDA_LIB_DIR`为cuda库文件地址,在docker中;为`/usr/local/cuda/lib64`;`CUDNN_LIB_DIR`为cudnn库文件地址,在docker中为`/usr/lib/x86_64-linux-gnu/`。
|
||||||
|
|
||||||
|
|
||||||
|
* 编译完成之后,会在`build`文件夹下生成一个名为`ocr_system`的可执行文件。
|
||||||
|
|
||||||
|
|
||||||
|
### 运行demo
|
||||||
|
* 执行以下命令,完成对一幅图像的OCR识别与检测,最终输出
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sh tools/run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
最终屏幕上会输出检测结果如下。
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../imgs/cpp_infer_pred_12.png" width="600">
|
||||||
|
</div>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <include/config.h>
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
std::vector<std::string> Config::split(const std::string &str,
|
||||||
|
const std::string &delim) {
|
||||||
|
std::vector<std::string> res;
|
||||||
|
if ("" == str)
|
||||||
|
return res;
|
||||||
|
char *strs = new char[str.length() + 1];
|
||||||
|
std::strcpy(strs, str.c_str());
|
||||||
|
|
||||||
|
char *d = new char[delim.length() + 1];
|
||||||
|
std::strcpy(d, delim.c_str());
|
||||||
|
|
||||||
|
char *p = std::strtok(strs, d);
|
||||||
|
while (p) {
|
||||||
|
std::string s = p;
|
||||||
|
res.push_back(s);
|
||||||
|
p = std::strtok(NULL, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::string>
|
||||||
|
Config::LoadConfig(const std::string &config_path) {
|
||||||
|
auto config = Utility::ReadDict(config_path);
|
||||||
|
|
||||||
|
std::map<std::string, std::string> dict;
|
||||||
|
for (int i = 0; i < config.size(); i++) {
|
||||||
|
// pass for empty line or comment
|
||||||
|
if (config[i].size() <= 1 or config[i][0] == '#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::vector<std::string> res = split(config[i], " ");
|
||||||
|
dict[res[0]] = res[1];
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::PrintConfigInfo() {
|
||||||
|
std::cout << "=======Paddle OCR inference config======" << std::endl;
|
||||||
|
for (auto iter = config_map_.begin(); iter != config_map_.end(); iter++) {
|
||||||
|
std::cout << iter->first << " : " << iter->second << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << "=======End of Paddle OCR inference config======" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,76 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "opencv2/core.hpp"
|
||||||
|
#include "opencv2/imgcodecs.hpp"
|
||||||
|
#include "opencv2/imgproc.hpp"
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include <include/config.h>
|
||||||
|
#include <include/ocr_det.h>
|
||||||
|
#include <include/ocr_rec.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace cv;
|
||||||
|
using namespace PaddleOCR;
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc < 3) {
|
||||||
|
std::cerr << "[ERROR] usage: " << argv[0]
|
||||||
|
<< " configure_filepath image_path\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Config config(argv[1]);
|
||||||
|
|
||||||
|
config.PrintConfigInfo();
|
||||||
|
|
||||||
|
std::string img_path(argv[2]);
|
||||||
|
|
||||||
|
cv::Mat srcimg = cv::imread(img_path, cv::IMREAD_COLOR);
|
||||||
|
|
||||||
|
DBDetector det(config.det_model_dir, config.use_gpu, config.gpu_id,
|
||||||
|
config.gpu_mem, config.cpu_math_library_num_threads,
|
||||||
|
config.max_side_len, config.det_db_thresh,
|
||||||
|
config.det_db_box_thresh, config.det_db_unclip_ratio,
|
||||||
|
config.visualize);
|
||||||
|
CRNNRecognizer rec(config.rec_model_dir, config.use_gpu, config.gpu_id,
|
||||||
|
config.gpu_mem, config.cpu_math_library_num_threads,
|
||||||
|
config.char_list_file);
|
||||||
|
|
||||||
|
auto start = std::chrono::system_clock::now();
|
||||||
|
std::vector<std::vector<std::vector<int>>> boxes;
|
||||||
|
det.Run(srcimg, boxes);
|
||||||
|
|
||||||
|
rec.Run(boxes, srcimg);
|
||||||
|
|
||||||
|
auto end = std::chrono::system_clock::now();
|
||||||
|
auto duration =
|
||||||
|
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||||
|
std::cout << "花费了"
|
||||||
|
<< double(duration.count()) *
|
||||||
|
std::chrono::microseconds::period::num /
|
||||||
|
std::chrono::microseconds::period::den
|
||||||
|
<< "秒" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <include/ocr_det.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
void DBDetector::LoadModel(const std::string &model_dir) {
|
||||||
|
AnalysisConfig config;
|
||||||
|
config.SetModel(model_dir + "/model", model_dir + "/params");
|
||||||
|
|
||||||
|
if (this->use_gpu_) {
|
||||||
|
config.EnableUseGpu(this->gpu_mem_, this->gpu_id_);
|
||||||
|
} else {
|
||||||
|
config.DisableGpu();
|
||||||
|
// config.EnableMKLDNN(); // not sugesteed to use for now
|
||||||
|
config.SetCpuMathLibraryNumThreads(this->cpu_math_library_num_threads_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// false for zero copy tensor
|
||||||
|
config.SwitchUseFeedFetchOps(false);
|
||||||
|
// true for multiple input
|
||||||
|
config.SwitchSpecifyInputNames(true);
|
||||||
|
|
||||||
|
config.SwitchIrOptim(true);
|
||||||
|
|
||||||
|
config.EnableMemoryOptim();
|
||||||
|
|
||||||
|
this->predictor_ = CreatePaddlePredictor(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBDetector::Run(cv::Mat &img,
|
||||||
|
std::vector<std::vector<std::vector<int>>> &boxes) {
|
||||||
|
float ratio_h{};
|
||||||
|
float ratio_w{};
|
||||||
|
|
||||||
|
cv::Mat srcimg;
|
||||||
|
cv::Mat resize_img;
|
||||||
|
img.copyTo(srcimg);
|
||||||
|
this->resize_op_.Run(img, resize_img, this->max_side_len_, ratio_h, ratio_w);
|
||||||
|
|
||||||
|
this->normalize_op_.Run(&resize_img, this->mean_, this->scale_,
|
||||||
|
this->is_scale_);
|
||||||
|
|
||||||
|
std::vector<float> input(1 * 3 * resize_img.rows * resize_img.cols, 0.0f);
|
||||||
|
this->permute_op_.Run(&resize_img, input.data());
|
||||||
|
|
||||||
|
auto input_names = this->predictor_->GetInputNames();
|
||||||
|
auto input_t = this->predictor_->GetInputTensor(input_names[0]);
|
||||||
|
input_t->Reshape({1, 3, resize_img.rows, resize_img.cols});
|
||||||
|
input_t->copy_from_cpu(input.data());
|
||||||
|
|
||||||
|
this->predictor_->ZeroCopyRun();
|
||||||
|
|
||||||
|
std::vector<float> out_data;
|
||||||
|
auto output_names = this->predictor_->GetOutputNames();
|
||||||
|
auto output_t = this->predictor_->GetOutputTensor(output_names[0]);
|
||||||
|
std::vector<int> output_shape = output_t->shape();
|
||||||
|
int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 1,
|
||||||
|
std::multiplies<int>());
|
||||||
|
|
||||||
|
out_data.resize(out_num);
|
||||||
|
output_t->copy_to_cpu(out_data.data());
|
||||||
|
|
||||||
|
int n2 = output_shape[2];
|
||||||
|
int n3 = output_shape[3];
|
||||||
|
int n = n2 * n3;
|
||||||
|
|
||||||
|
std::vector<float> pred(n, 0.0);
|
||||||
|
std::vector<unsigned char> cbuf(n, ' ');
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
pred[i] = float(out_data[i]);
|
||||||
|
cbuf[i] = (unsigned char)((out_data[i]) * 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat cbuf_map(n2, n3, CV_8UC1, (unsigned char *)cbuf.data());
|
||||||
|
cv::Mat pred_map(n2, n3, CV_32F, (float *)pred.data());
|
||||||
|
|
||||||
|
const double threshold = this->det_db_thresh_ * 255;
|
||||||
|
const double maxvalue = 255;
|
||||||
|
cv::Mat bit_map;
|
||||||
|
cv::threshold(cbuf_map, bit_map, threshold, maxvalue, cv::THRESH_BINARY);
|
||||||
|
|
||||||
|
boxes = post_processor_.BoxesFromBitmap(
|
||||||
|
pred_map, bit_map, this->det_db_box_thresh_, this->det_db_unclip_ratio_);
|
||||||
|
|
||||||
|
boxes = post_processor_.FilterTagDetRes(boxes, ratio_h, ratio_w, srcimg);
|
||||||
|
|
||||||
|
//// visualization
|
||||||
|
if (this->visualize_) {
|
||||||
|
Utility::VisualizeBboxes(srcimg, boxes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,202 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "opencv2/core.hpp"
|
||||||
|
#include "opencv2/imgcodecs.hpp"
|
||||||
|
#include "opencv2/imgproc.hpp"
|
||||||
|
#include "paddle_api.h"
|
||||||
|
#include "paddle_inference_api.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include <include/ocr_rec.h>
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
void CRNNRecognizer::Run(std::vector<std::vector<std::vector<int>>> boxes,
|
||||||
|
cv::Mat &img) {
|
||||||
|
cv::Mat srcimg;
|
||||||
|
img.copyTo(srcimg);
|
||||||
|
cv::Mat crop_img;
|
||||||
|
cv::Mat resize_img;
|
||||||
|
|
||||||
|
std::cout << "The predicted text is :" << std::endl;
|
||||||
|
int index = 0;
|
||||||
|
for (int i = boxes.size() - 1; i >= 0; i--) {
|
||||||
|
crop_img = GetRotateCropImage(srcimg, boxes[i]);
|
||||||
|
|
||||||
|
float wh_ratio = float(crop_img.cols) / float(crop_img.rows);
|
||||||
|
|
||||||
|
this->resize_op_.Run(crop_img, resize_img, wh_ratio);
|
||||||
|
|
||||||
|
this->normalize_op_.Run(&resize_img, this->mean_, this->scale_,
|
||||||
|
this->is_scale_);
|
||||||
|
|
||||||
|
std::vector<float> input(1 * 3 * resize_img.rows * resize_img.cols, 0.0f);
|
||||||
|
|
||||||
|
this->permute_op_.Run(&resize_img, input.data());
|
||||||
|
|
||||||
|
auto input_names = this->predictor_->GetInputNames();
|
||||||
|
auto input_t = this->predictor_->GetInputTensor(input_names[0]);
|
||||||
|
input_t->Reshape({1, 3, resize_img.rows, resize_img.cols});
|
||||||
|
input_t->copy_from_cpu(input.data());
|
||||||
|
|
||||||
|
this->predictor_->ZeroCopyRun();
|
||||||
|
|
||||||
|
std::vector<int64_t> rec_idx;
|
||||||
|
auto output_names = this->predictor_->GetOutputNames();
|
||||||
|
auto output_t = this->predictor_->GetOutputTensor(output_names[0]);
|
||||||
|
auto rec_idx_lod = output_t->lod();
|
||||||
|
auto shape_out = output_t->shape();
|
||||||
|
int out_num = std::accumulate(shape_out.begin(), shape_out.end(), 1,
|
||||||
|
std::multiplies<int>());
|
||||||
|
|
||||||
|
rec_idx.resize(out_num);
|
||||||
|
output_t->copy_to_cpu(rec_idx.data());
|
||||||
|
|
||||||
|
std::vector<int> pred_idx;
|
||||||
|
for (int n = int(rec_idx_lod[0][0]); n < int(rec_idx_lod[0][1]); n++) {
|
||||||
|
pred_idx.push_back(int(rec_idx[n]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pred_idx.size() < 1e-3)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
std::cout << index << "\t";
|
||||||
|
for (int n = 0; n < pred_idx.size(); n++) {
|
||||||
|
std::cout << label_list_[pred_idx[n]];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<float> predict_batch;
|
||||||
|
auto output_t_1 = this->predictor_->GetOutputTensor(output_names[1]);
|
||||||
|
|
||||||
|
auto predict_lod = output_t_1->lod();
|
||||||
|
auto predict_shape = output_t_1->shape();
|
||||||
|
int out_num_1 = std::accumulate(predict_shape.begin(), predict_shape.end(),
|
||||||
|
1, std::multiplies<int>());
|
||||||
|
|
||||||
|
predict_batch.resize(out_num_1);
|
||||||
|
output_t_1->copy_to_cpu(predict_batch.data());
|
||||||
|
|
||||||
|
int argmax_idx;
|
||||||
|
int blank = predict_shape[1];
|
||||||
|
float score = 0.f;
|
||||||
|
int count = 0;
|
||||||
|
float max_value = 0.0f;
|
||||||
|
|
||||||
|
for (int n = predict_lod[0][0]; n < predict_lod[0][1] - 1; n++) {
|
||||||
|
argmax_idx =
|
||||||
|
int(Utility::argmax(&predict_batch[n * predict_shape[1]],
|
||||||
|
&predict_batch[(n + 1) * predict_shape[1]]));
|
||||||
|
max_value =
|
||||||
|
float(*std::max_element(&predict_batch[n * predict_shape[1]],
|
||||||
|
&predict_batch[(n + 1) * predict_shape[1]]));
|
||||||
|
if (blank - 1 - argmax_idx > 1e-5) {
|
||||||
|
score += max_value;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
score /= count;
|
||||||
|
std::cout << "\tscore: " << score << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRNNRecognizer::LoadModel(const std::string &model_dir) {
|
||||||
|
AnalysisConfig config;
|
||||||
|
config.SetModel(model_dir + "/model", model_dir + "/params");
|
||||||
|
|
||||||
|
if (this->use_gpu_) {
|
||||||
|
config.EnableUseGpu(this->gpu_mem_, this->gpu_id_);
|
||||||
|
} else {
|
||||||
|
config.DisableGpu();
|
||||||
|
// config.EnableMKLDNN(); // not sugesteed to use for now
|
||||||
|
config.SetCpuMathLibraryNumThreads(this->cpu_math_library_num_threads_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// false for zero copy tensor
|
||||||
|
config.SwitchUseFeedFetchOps(false);
|
||||||
|
// true for multiple input
|
||||||
|
config.SwitchSpecifyInputNames(true);
|
||||||
|
|
||||||
|
config.SwitchIrOptim(true);
|
||||||
|
|
||||||
|
config.EnableMemoryOptim();
|
||||||
|
|
||||||
|
this->predictor_ = CreatePaddlePredictor(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat CRNNRecognizer::GetRotateCropImage(const cv::Mat &srcimage,
|
||||||
|
std::vector<std::vector<int>> box) {
|
||||||
|
cv::Mat image;
|
||||||
|
srcimage.copyTo(image);
|
||||||
|
std::vector<std::vector<int>> points = box;
|
||||||
|
|
||||||
|
int x_collect[4] = {box[0][0], box[1][0], box[2][0], box[3][0]};
|
||||||
|
int y_collect[4] = {box[0][1], box[1][1], box[2][1], box[3][1]};
|
||||||
|
int left = int(*std::min_element(x_collect, x_collect + 4));
|
||||||
|
int right = int(*std::max_element(x_collect, x_collect + 4));
|
||||||
|
int top = int(*std::min_element(y_collect, y_collect + 4));
|
||||||
|
int bottom = int(*std::max_element(y_collect, y_collect + 4));
|
||||||
|
|
||||||
|
cv::Mat img_crop;
|
||||||
|
image(cv::Rect(left, top, right - left, bottom - top)).copyTo(img_crop);
|
||||||
|
|
||||||
|
for (int i = 0; i < points.size(); i++) {
|
||||||
|
points[i][0] -= left;
|
||||||
|
points[i][1] -= top;
|
||||||
|
}
|
||||||
|
|
||||||
|
int img_crop_width = int(sqrt(pow(points[0][0] - points[1][0], 2) +
|
||||||
|
pow(points[0][1] - points[1][1], 2)));
|
||||||
|
int img_crop_height = int(sqrt(pow(points[0][0] - points[3][0], 2) +
|
||||||
|
pow(points[0][1] - points[3][1], 2)));
|
||||||
|
|
||||||
|
cv::Point2f pts_std[4];
|
||||||
|
pts_std[0] = cv::Point2f(0., 0.);
|
||||||
|
pts_std[1] = cv::Point2f(img_crop_width, 0.);
|
||||||
|
pts_std[2] = cv::Point2f(img_crop_width, img_crop_height);
|
||||||
|
pts_std[3] = cv::Point2f(0.f, img_crop_height);
|
||||||
|
|
||||||
|
cv::Point2f pointsf[4];
|
||||||
|
pointsf[0] = cv::Point2f(points[0][0], points[0][1]);
|
||||||
|
pointsf[1] = cv::Point2f(points[1][0], points[1][1]);
|
||||||
|
pointsf[2] = cv::Point2f(points[2][0], points[2][1]);
|
||||||
|
pointsf[3] = cv::Point2f(points[3][0], points[3][1]);
|
||||||
|
|
||||||
|
cv::Mat M = cv::getPerspectiveTransform(pointsf, pts_std);
|
||||||
|
|
||||||
|
cv::Mat dst_img;
|
||||||
|
cv::warpPerspective(img_crop, dst_img, M,
|
||||||
|
cv::Size(img_crop_width, img_crop_height),
|
||||||
|
cv::BORDER_REPLICATE);
|
||||||
|
|
||||||
|
if (float(dst_img.rows) >= float(dst_img.cols) * 1.5) {
|
||||||
|
cv::Mat srcCopy = cv::Mat(dst_img.rows, dst_img.cols, dst_img.depth());
|
||||||
|
cv::transpose(dst_img, srcCopy);
|
||||||
|
cv::flip(srcCopy, srcCopy, 0);
|
||||||
|
return srcCopy;
|
||||||
|
} else {
|
||||||
|
return dst_img;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,294 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <include/postprocess_op.h>
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
void PostProcessor::GetContourArea(const std::vector<std::vector<float>> &box,
|
||||||
|
float unclip_ratio, float &distance) {
|
||||||
|
int pts_num = 4;
|
||||||
|
float area = 0.0f;
|
||||||
|
float dist = 0.0f;
|
||||||
|
for (int i = 0; i < pts_num; i++) {
|
||||||
|
area += box[i][0] * box[(i + 1) % pts_num][1] -
|
||||||
|
box[i][1] * box[(i + 1) % pts_num][0];
|
||||||
|
dist += sqrtf((box[i][0] - box[(i + 1) % pts_num][0]) *
|
||||||
|
(box[i][0] - box[(i + 1) % pts_num][0]) +
|
||||||
|
(box[i][1] - box[(i + 1) % pts_num][1]) *
|
||||||
|
(box[i][1] - box[(i + 1) % pts_num][1]));
|
||||||
|
}
|
||||||
|
area = fabs(float(area / 2.0));
|
||||||
|
|
||||||
|
distance = area * unclip_ratio / dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::RotatedRect PostProcessor::UnClip(std::vector<std::vector<float>> box,
|
||||||
|
const float &unclip_ratio) {
|
||||||
|
float distance = 1.0;
|
||||||
|
|
||||||
|
GetContourArea(box, unclip_ratio, distance);
|
||||||
|
|
||||||
|
ClipperLib::ClipperOffset offset;
|
||||||
|
ClipperLib::Path p;
|
||||||
|
p << ClipperLib::IntPoint(int(box[0][0]), int(box[0][1]))
|
||||||
|
<< ClipperLib::IntPoint(int(box[1][0]), int(box[1][1]))
|
||||||
|
<< ClipperLib::IntPoint(int(box[2][0]), int(box[2][1]))
|
||||||
|
<< ClipperLib::IntPoint(int(box[3][0]), int(box[3][1]));
|
||||||
|
offset.AddPath(p, ClipperLib::jtRound, ClipperLib::etClosedPolygon);
|
||||||
|
|
||||||
|
ClipperLib::Paths soln;
|
||||||
|
offset.Execute(soln, distance);
|
||||||
|
std::vector<cv::Point2f> points;
|
||||||
|
|
||||||
|
for (int j = 0; j < soln.size(); j++) {
|
||||||
|
for (int i = 0; i < soln[soln.size() - 1].size(); i++) {
|
||||||
|
points.emplace_back(soln[j][i].X, soln[j][i].Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cv::RotatedRect res = cv::minAreaRect(points);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
float **PostProcessor::Mat2Vec(cv::Mat mat) {
|
||||||
|
auto **array = new float *[mat.rows];
|
||||||
|
for (int i = 0; i < mat.rows; ++i)
|
||||||
|
array[i] = new float[mat.cols];
|
||||||
|
for (int i = 0; i < mat.rows; ++i) {
|
||||||
|
for (int j = 0; j < mat.cols; ++j) {
|
||||||
|
array[i][j] = mat.at<float>(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<int>>
|
||||||
|
PostProcessor::OrderPointsClockwise(std::vector<std::vector<int>> pts) {
|
||||||
|
std::vector<std::vector<int>> box = pts;
|
||||||
|
std::sort(box.begin(), box.end(), XsortInt);
|
||||||
|
|
||||||
|
std::vector<std::vector<int>> leftmost = {box[0], box[1]};
|
||||||
|
std::vector<std::vector<int>> rightmost = {box[2], box[3]};
|
||||||
|
|
||||||
|
if (leftmost[0][1] > leftmost[1][1])
|
||||||
|
std::swap(leftmost[0], leftmost[1]);
|
||||||
|
|
||||||
|
if (rightmost[0][1] > rightmost[1][1])
|
||||||
|
std::swap(rightmost[0], rightmost[1]);
|
||||||
|
|
||||||
|
std::vector<std::vector<int>> rect = {leftmost[0], rightmost[0], rightmost[1],
|
||||||
|
leftmost[1]};
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<float>> PostProcessor::Mat2Vector(cv::Mat mat) {
|
||||||
|
std::vector<std::vector<float>> img_vec;
|
||||||
|
std::vector<float> tmp;
|
||||||
|
|
||||||
|
for (int i = 0; i < mat.rows; ++i) {
|
||||||
|
tmp.clear();
|
||||||
|
for (int j = 0; j < mat.cols; ++j) {
|
||||||
|
tmp.push_back(mat.at<float>(i, j));
|
||||||
|
}
|
||||||
|
img_vec.push_back(tmp);
|
||||||
|
}
|
||||||
|
return img_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PostProcessor::XsortFp32(std::vector<float> a, std::vector<float> b) {
|
||||||
|
if (a[0] != b[0])
|
||||||
|
return a[0] < b[0];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PostProcessor::XsortInt(std::vector<int> a, std::vector<int> b) {
|
||||||
|
if (a[0] != b[0])
|
||||||
|
return a[0] < b[0];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<float>> PostProcessor::GetMiniBoxes(cv::RotatedRect box,
|
||||||
|
float &ssid) {
|
||||||
|
ssid = std::max(box.size.width, box.size.height);
|
||||||
|
|
||||||
|
cv::Mat points;
|
||||||
|
cv::boxPoints(box, points);
|
||||||
|
|
||||||
|
auto array = Mat2Vector(points);
|
||||||
|
std::sort(array.begin(), array.end(), XsortFp32);
|
||||||
|
|
||||||
|
std::vector<float> idx1 = array[0], idx2 = array[1], idx3 = array[2],
|
||||||
|
idx4 = array[3];
|
||||||
|
if (array[3][1] <= array[2][1]) {
|
||||||
|
idx2 = array[3];
|
||||||
|
idx3 = array[2];
|
||||||
|
} else {
|
||||||
|
idx2 = array[2];
|
||||||
|
idx3 = array[3];
|
||||||
|
}
|
||||||
|
if (array[1][1] <= array[0][1]) {
|
||||||
|
idx1 = array[1];
|
||||||
|
idx4 = array[0];
|
||||||
|
} else {
|
||||||
|
idx1 = array[0];
|
||||||
|
idx4 = array[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
array[0] = idx1;
|
||||||
|
array[1] = idx2;
|
||||||
|
array[2] = idx3;
|
||||||
|
array[3] = idx4;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
float PostProcessor::BoxScoreFast(std::vector<std::vector<float>> box_array,
|
||||||
|
cv::Mat pred) {
|
||||||
|
auto array = box_array;
|
||||||
|
int width = pred.cols;
|
||||||
|
int height = pred.rows;
|
||||||
|
|
||||||
|
float box_x[4] = {array[0][0], array[1][0], array[2][0], array[3][0]};
|
||||||
|
float box_y[4] = {array[0][1], array[1][1], array[2][1], array[3][1]};
|
||||||
|
|
||||||
|
int xmin = clamp(int(std::floor(*(std::min_element(box_x, box_x + 4)))), 0,
|
||||||
|
width - 1);
|
||||||
|
int xmax = clamp(int(std::ceil(*(std::max_element(box_x, box_x + 4)))), 0,
|
||||||
|
width - 1);
|
||||||
|
int ymin = clamp(int(std::floor(*(std::min_element(box_y, box_y + 4)))), 0,
|
||||||
|
height - 1);
|
||||||
|
int ymax = clamp(int(std::ceil(*(std::max_element(box_y, box_y + 4)))), 0,
|
||||||
|
height - 1);
|
||||||
|
|
||||||
|
cv::Mat mask;
|
||||||
|
mask = cv::Mat::zeros(ymax - ymin + 1, xmax - xmin + 1, CV_8UC1);
|
||||||
|
|
||||||
|
cv::Point root_point[4];
|
||||||
|
root_point[0] = cv::Point(int(array[0][0]) - xmin, int(array[0][1]) - ymin);
|
||||||
|
root_point[1] = cv::Point(int(array[1][0]) - xmin, int(array[1][1]) - ymin);
|
||||||
|
root_point[2] = cv::Point(int(array[2][0]) - xmin, int(array[2][1]) - ymin);
|
||||||
|
root_point[3] = cv::Point(int(array[3][0]) - xmin, int(array[3][1]) - ymin);
|
||||||
|
const cv::Point *ppt[1] = {root_point};
|
||||||
|
int npt[] = {4};
|
||||||
|
cv::fillPoly(mask, ppt, npt, 1, cv::Scalar(1));
|
||||||
|
|
||||||
|
cv::Mat croppedImg;
|
||||||
|
pred(cv::Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1))
|
||||||
|
.copyTo(croppedImg);
|
||||||
|
|
||||||
|
auto score = cv::mean(croppedImg, mask)[0];
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<int>>>
|
||||||
|
PostProcessor::BoxesFromBitmap(const cv::Mat pred, const cv::Mat bitmap,
|
||||||
|
const float &box_thresh,
|
||||||
|
const float &det_db_unclip_ratio) {
|
||||||
|
const int min_size = 3;
|
||||||
|
const int max_candidates = 1000;
|
||||||
|
|
||||||
|
int width = bitmap.cols;
|
||||||
|
int height = bitmap.rows;
|
||||||
|
|
||||||
|
std::vector<std::vector<cv::Point>> contours;
|
||||||
|
std::vector<cv::Vec4i> hierarchy;
|
||||||
|
|
||||||
|
cv::findContours(bitmap, contours, hierarchy, cv::RETR_LIST,
|
||||||
|
cv::CHAIN_APPROX_SIMPLE);
|
||||||
|
|
||||||
|
int num_contours =
|
||||||
|
contours.size() >= max_candidates ? max_candidates : contours.size();
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<int>>> boxes;
|
||||||
|
|
||||||
|
for (int _i = 0; _i < num_contours; _i++) {
|
||||||
|
float ssid;
|
||||||
|
cv::RotatedRect box = cv::minAreaRect(contours[_i]);
|
||||||
|
auto array = GetMiniBoxes(box, ssid);
|
||||||
|
|
||||||
|
auto box_for_unclip = array;
|
||||||
|
// end get_mini_box
|
||||||
|
|
||||||
|
if (ssid < min_size) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float score;
|
||||||
|
score = BoxScoreFast(array, pred);
|
||||||
|
if (score < box_thresh)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// start for unclip
|
||||||
|
cv::RotatedRect points = UnClip(box_for_unclip, det_db_unclip_ratio);
|
||||||
|
// end for unclip
|
||||||
|
|
||||||
|
cv::RotatedRect clipbox = points;
|
||||||
|
auto cliparray = GetMiniBoxes(clipbox, ssid);
|
||||||
|
|
||||||
|
if (ssid < min_size + 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int dest_width = pred.cols;
|
||||||
|
int dest_height = pred.rows;
|
||||||
|
std::vector<std::vector<int>> intcliparray;
|
||||||
|
|
||||||
|
for (int num_pt = 0; num_pt < 4; num_pt++) {
|
||||||
|
std::vector<int> a{int(clampf(roundf(cliparray[num_pt][0] / float(width) *
|
||||||
|
float(dest_width)),
|
||||||
|
0, float(dest_width))),
|
||||||
|
int(clampf(roundf(cliparray[num_pt][1] /
|
||||||
|
float(height) * float(dest_height)),
|
||||||
|
0, float(dest_height)))};
|
||||||
|
intcliparray.push_back(a);
|
||||||
|
}
|
||||||
|
boxes.push_back(intcliparray);
|
||||||
|
|
||||||
|
} // end for
|
||||||
|
return boxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<int>>>
|
||||||
|
PostProcessor::FilterTagDetRes(std::vector<std::vector<std::vector<int>>> boxes,
|
||||||
|
float ratio_h, float ratio_w, cv::Mat srcimg) {
|
||||||
|
int oriimg_h = srcimg.rows;
|
||||||
|
int oriimg_w = srcimg.cols;
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<int>>> root_points;
|
||||||
|
for (int n = 0; n < boxes.size(); n++) {
|
||||||
|
boxes[n] = OrderPointsClockwise(boxes[n]);
|
||||||
|
for (int m = 0; m < boxes[0].size(); m++) {
|
||||||
|
boxes[n][m][0] /= ratio_w;
|
||||||
|
boxes[n][m][1] /= ratio_h;
|
||||||
|
|
||||||
|
boxes[n][m][0] = int(_min(_max(boxes[n][m][0], 0), oriimg_w - 1));
|
||||||
|
boxes[n][m][1] = int(_min(_max(boxes[n][m][1], 0), oriimg_h - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int n = 0; n < boxes.size(); n++) {
|
||||||
|
int rect_width, rect_height;
|
||||||
|
rect_width = int(sqrt(pow(boxes[n][0][0] - boxes[n][1][0], 2) +
|
||||||
|
pow(boxes[n][0][1] - boxes[n][1][1], 2)));
|
||||||
|
rect_height = int(sqrt(pow(boxes[n][0][0] - boxes[n][3][0], 2) +
|
||||||
|
pow(boxes[n][0][1] - boxes[n][3][1], 2)));
|
||||||
|
if (rect_width <= 10 || rect_height <= 10)
|
||||||
|
continue;
|
||||||
|
root_points.push_back(boxes[n]);
|
||||||
|
}
|
||||||
|
return root_points;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,119 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "opencv2/core.hpp"
|
||||||
|
#include "opencv2/imgcodecs.hpp"
|
||||||
|
#include "opencv2/imgproc.hpp"
|
||||||
|
#include "paddle_api.h"
|
||||||
|
#include "paddle_inference_api.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include <include/preprocess_op.h>
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
void Permute::Run(const cv::Mat *im, float *data) {
|
||||||
|
int rh = im->rows;
|
||||||
|
int rw = im->cols;
|
||||||
|
int rc = im->channels();
|
||||||
|
for (int i = 0; i < rc; ++i) {
|
||||||
|
cv::extractChannel(*im, cv::Mat(rh, rw, CV_32FC1, data + i * rh * rw), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Normalize::Run(cv::Mat *im, const std::vector<float> &mean,
|
||||||
|
const std::vector<float> &scale, const bool is_scale) {
|
||||||
|
double e = 1.0;
|
||||||
|
if (is_scale) {
|
||||||
|
e /= 255.0;
|
||||||
|
}
|
||||||
|
(*im).convertTo(*im, CV_32FC3, e);
|
||||||
|
for (int h = 0; h < im->rows; h++) {
|
||||||
|
for (int w = 0; w < im->cols; w++) {
|
||||||
|
im->at<cv::Vec3f>(h, w)[0] =
|
||||||
|
(im->at<cv::Vec3f>(h, w)[0] - mean[0]) * scale[0];
|
||||||
|
im->at<cv::Vec3f>(h, w)[1] =
|
||||||
|
(im->at<cv::Vec3f>(h, w)[1] - mean[1]) * scale[1];
|
||||||
|
im->at<cv::Vec3f>(h, w)[2] =
|
||||||
|
(im->at<cv::Vec3f>(h, w)[2] - mean[2]) * scale[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResizeImgType0::Run(const cv::Mat &img, cv::Mat &resize_img,
|
||||||
|
int max_size_len, float &ratio_h, float &ratio_w) {
|
||||||
|
int w = img.cols;
|
||||||
|
int h = img.rows;
|
||||||
|
|
||||||
|
float ratio = 1.f;
|
||||||
|
int max_wh = w >= h ? w : h;
|
||||||
|
if (max_wh > max_size_len) {
|
||||||
|
if (h > w) {
|
||||||
|
ratio = float(max_size_len) / float(h);
|
||||||
|
} else {
|
||||||
|
ratio = float(max_size_len) / float(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int resize_h = int(float(h) * ratio);
|
||||||
|
int resize_w = int(float(w) * ratio);
|
||||||
|
if (resize_h % 32 == 0)
|
||||||
|
resize_h = resize_h;
|
||||||
|
else if (resize_h / 32 < 1 + 1e-5)
|
||||||
|
resize_h = 32;
|
||||||
|
else
|
||||||
|
resize_h = (resize_h / 32 - 1) * 32;
|
||||||
|
|
||||||
|
if (resize_w % 32 == 0)
|
||||||
|
resize_w = resize_w;
|
||||||
|
else if (resize_w / 32 < 1)
|
||||||
|
resize_w = 32;
|
||||||
|
else
|
||||||
|
resize_w = (resize_w / 32 - 1) * 32;
|
||||||
|
|
||||||
|
cv::resize(img, resize_img, cv::Size(resize_w, resize_h));
|
||||||
|
|
||||||
|
ratio_h = float(resize_h) / float(h);
|
||||||
|
ratio_w = float(resize_w) / float(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrnnResizeImg::Run(const cv::Mat &img, cv::Mat &resize_img, float wh_ratio,
|
||||||
|
const std::vector<int> &rec_image_shape) {
|
||||||
|
int imgC, imgH, imgW;
|
||||||
|
imgC = rec_image_shape[0];
|
||||||
|
imgH = rec_image_shape[1];
|
||||||
|
imgW = rec_image_shape[2];
|
||||||
|
|
||||||
|
imgW = int(32 * wh_ratio);
|
||||||
|
|
||||||
|
float ratio = float(img.cols) / float(img.rows);
|
||||||
|
int resize_w, resize_h;
|
||||||
|
if (ceilf(imgH * ratio) > imgW)
|
||||||
|
resize_w = imgW;
|
||||||
|
else
|
||||||
|
resize_w = int(ceilf(imgH * ratio));
|
||||||
|
|
||||||
|
cv::resize(img, resize_img, cv::Size(resize_w, imgH), 0.f, 0.f,
|
||||||
|
cv::INTER_LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <include/utility.h>
|
||||||
|
|
||||||
|
namespace PaddleOCR {
|
||||||
|
|
||||||
|
std::vector<std::string> Utility::ReadDict(const std::string &path) {
|
||||||
|
std::ifstream in(path);
|
||||||
|
std::string line;
|
||||||
|
std::vector<std::string> m_vec;
|
||||||
|
if (in) {
|
||||||
|
while (getline(in, line)) {
|
||||||
|
m_vec.push_back(line);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "no such label file: " << path << ", exit the program..."
|
||||||
|
<< std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return m_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utility::VisualizeBboxes(
|
||||||
|
const cv::Mat &srcimg,
|
||||||
|
const std::vector<std::vector<std::vector<int>>> &boxes) {
|
||||||
|
cv::Point rook_points[boxes.size()][4];
|
||||||
|
for (int n = 0; n < boxes.size(); n++) {
|
||||||
|
for (int m = 0; m < boxes[0].size(); m++) {
|
||||||
|
rook_points[n][m] = cv::Point(int(boxes[n][m][0]), int(boxes[n][m][1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cv::Mat img_vis;
|
||||||
|
srcimg.copyTo(img_vis);
|
||||||
|
for (int n = 0; n < boxes.size(); n++) {
|
||||||
|
const cv::Point *ppt[1] = {rook_points[n]};
|
||||||
|
int npt[] = {4};
|
||||||
|
cv::polylines(img_vis, ppt, npt, 1, 1, CV_RGB(0, 255, 0), 2, 8, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::imwrite("./ocr_vis.png", img_vis);
|
||||||
|
std::cout << "The detection visualized image saved in ./ocr_vis.png.pn"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PaddleOCR
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
OPENCV_DIR=your_opencv_dir
|
||||||
|
LIB_DIR=your_paddle_inference_dir
|
||||||
|
CUDA_LIB_DIR=your_cuda_lib_dir
|
||||||
|
CUDNN_LIB_DIR=/your_cudnn_lib_dir
|
||||||
|
|
||||||
|
BUILD_DIR=build
|
||||||
|
rm -rf ${BUILD_DIR}
|
||||||
|
mkdir ${BUILD_DIR}
|
||||||
|
cd ${BUILD_DIR}
|
||||||
|
cmake .. \
|
||||||
|
-DPADDLE_LIB=${LIB_DIR} \
|
||||||
|
-DWITH_MKL=ON \
|
||||||
|
-DDEMO_NAME=ocr_system \
|
||||||
|
-DWITH_GPU=OFF \
|
||||||
|
-DWITH_STATIC_LIB=OFF \
|
||||||
|
-DUSE_TENSORRT=OFF \
|
||||||
|
-DOPENCV_DIR=${OPENCV_DIR} \
|
||||||
|
-DCUDNN_LIB=${CUDNN_LIB_DIR} \
|
||||||
|
-DCUDA_LIB=${CUDA_LIB_DIR} \
|
||||||
|
|
||||||
|
make -j
|
|
@ -0,0 +1,21 @@
|
||||||
|
# model load config
|
||||||
|
use_gpu 0
|
||||||
|
gpu_id 0
|
||||||
|
gpu_mem 4000
|
||||||
|
cpu_math_library_num_threads 1
|
||||||
|
|
||||||
|
# det config
|
||||||
|
max_side_len 960
|
||||||
|
det_db_thresh 0.3
|
||||||
|
det_db_box_thresh 0.5
|
||||||
|
det_db_unclip_ratio 2.0
|
||||||
|
det_model_dir ./inference/det_db
|
||||||
|
|
||||||
|
# rec config
|
||||||
|
rec_model_dir ./inference/rec_crnn
|
||||||
|
char_list_file ../../ppocr/utils/ppocr_keys_v1.txt
|
||||||
|
img_path ../../doc/imgs/11.jpg
|
||||||
|
|
||||||
|
# show the detection results
|
||||||
|
visualize 1
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
./build/ocr_system ./tools/config.txt ../../doc/imgs/6.jpg
|
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Loading…
Reference in New Issue