Initial setup for CLion
This commit is contained in:
15
ANSOCR/ANSPaddleOCR/include/args.h
Normal file
15
ANSOCR/ANSPaddleOCR/include/args.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
DECLARE_string(input);
|
||||
DECLARE_string(type);
|
||||
DECLARE_string(output_dir);
|
||||
DECLARE_string(det_model_dir);
|
||||
DECLARE_string(cls_model_dir);
|
||||
DECLARE_string(rec_model_dir);
|
||||
DECLARE_string(lay_model_dir);
|
||||
DECLARE_string(tab_model_dir);
|
||||
DECLARE_string(label_dir);
|
||||
DECLARE_string(layout_dict_dir);
|
||||
DECLARE_string(table_dict_dir);
|
||||
425
ANSOCR/ANSPaddleOCR/include/clipper.h
Normal file
425
ANSOCR/ANSPaddleOCR/include/clipper.h
Normal file
@@ -0,0 +1,425 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#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
|
||||
45
ANSOCR/ANSPaddleOCR/include/ocr_cls.h
Normal file
45
ANSOCR/ANSPaddleOCR/include/ocr_cls.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#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/preprocess_op.h>
|
||||
#include <include/postprocess_op.h>
|
||||
#include <openvino/openvino.hpp>
|
||||
#include <openvino/core/preprocess/pre_post_process.hpp>
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
class Classifier
|
||||
{
|
||||
public:
|
||||
explicit Classifier(std::string model_path);
|
||||
void Run(std::vector<cv::Mat> img_list, std::vector<OCRPredictResult>& ocr_results);
|
||||
void SetParameters(int cls_batch_num, double cls_thresh);
|
||||
void GetParameters(int& cls_batch_num, double& cls_thresh);
|
||||
private:
|
||||
ov::InferRequest infer_request;
|
||||
std::string model_path;
|
||||
std::shared_ptr<ov::Model> model;
|
||||
ov::CompiledModel compiled_model;
|
||||
std::recursive_mutex _mutex;
|
||||
|
||||
double e = 1.0 / 255.0;
|
||||
std::vector<float> mean_ = { 0.5f, 0.5f, 0.5f };
|
||||
std::vector<float> scale_ = { 0.5f, 0.5f, 0.5f };
|
||||
|
||||
int cls_batch_num_ = 1;
|
||||
double cls_thresh = 0.9;
|
||||
|
||||
std::vector<size_t> cls_image_shape = { 3, 48, 192 };
|
||||
std::string GetOpenVINODevice();
|
||||
// resize
|
||||
ClsResizeImg resize_op_;
|
||||
};
|
||||
}
|
||||
71
ANSOCR/ANSPaddleOCR/include/ocr_det.h
Normal file
71
ANSOCR/ANSPaddleOCR/include/ocr_det.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#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/paddleocr_utility.h>
|
||||
#include <include/preprocess_op.h>
|
||||
#include <include/postprocess_op.h>
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
namespace PaddleOCR {
|
||||
class Detector
|
||||
{
|
||||
public:
|
||||
explicit Detector(std::string model_path);
|
||||
void Run(const cv::Mat& src_img, std::vector<OCRPredictResult>& ocr_results);
|
||||
void SetParameters(std::string limit_type,
|
||||
std::string det_db_score_mode,
|
||||
bool is_scale,
|
||||
double det_db_thresh,
|
||||
double det_db_box_thresh,
|
||||
double det_db_unclip_ratio,
|
||||
bool use_dilation);
|
||||
void GetParameters(std::string& limit_type,
|
||||
std::string& det_db_score_mode,
|
||||
bool& is_scale,
|
||||
double& det_db_thresh,
|
||||
double& det_db_box_thresh,
|
||||
double& det_db_unclip_ratio,
|
||||
bool& use_dilation);
|
||||
|
||||
private:
|
||||
ov::InferRequest infer_request;
|
||||
std::string model_path;
|
||||
cv::Mat src_img;
|
||||
std::shared_ptr<ov::Model> model;
|
||||
ov::CompiledModel compiled_model;
|
||||
std::recursive_mutex _mutex;
|
||||
|
||||
float ratio_h{};
|
||||
float ratio_w{};
|
||||
std::vector<float> mean_ = { 0.485f, 0.456f, 0.406f };
|
||||
std::vector<float> scale_ = { 1 / 0.229f, 1 / 0.224f, 1 / 0.225f };
|
||||
cv::Mat resize_img;
|
||||
double e = 1.0 / 255.0;
|
||||
|
||||
std::string limit_type_ = "max";
|
||||
std::string det_db_score_mode_ = "slow";
|
||||
int limit_side_len_ = 960;
|
||||
bool is_scale_ = true;
|
||||
double det_db_thresh_ = 0.3;
|
||||
double det_db_box_thresh_ = 0.6;
|
||||
double det_db_unclip_ratio_ = 1.5;
|
||||
bool use_dilation_ = false;
|
||||
|
||||
// pre-process
|
||||
ResizeImgType0 resize_op_;
|
||||
Normalize normalize_op_;
|
||||
Permute permute_op_;
|
||||
// post-process
|
||||
DBPostProcessor post_processor_;
|
||||
};
|
||||
}
|
||||
46
ANSOCR/ANSPaddleOCR/include/ocr_rec.h
Normal file
46
ANSOCR/ANSPaddleOCR/include/ocr_rec.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#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/paddleocr_utility.h>
|
||||
#include <include/preprocess_op.h>
|
||||
#include <include/postprocess_op.h>
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
class Recognizer
|
||||
{
|
||||
public:
|
||||
explicit Recognizer(std::string model_path, const std::string& label_path);
|
||||
void Run(const std::vector<cv::Mat>& img_list, std::vector<OCRPredictResult>& ocr_results);
|
||||
void SetParameters(int rec_batch_num);
|
||||
void GetParameters(int& rec_batch_num);
|
||||
private:
|
||||
ov::InferRequest infer_request;
|
||||
std::string model_path;
|
||||
std::shared_ptr<ov::Model> model;
|
||||
ov::CompiledModel compiled_model;
|
||||
std::recursive_mutex _mutex;
|
||||
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;
|
||||
std::vector<std::string> label_list_;
|
||||
int rec_img_h_ = 48;
|
||||
int rec_img_w_ = 320;
|
||||
std::vector<int> rec_image_shape_ = { 3, rec_img_h_, rec_img_w_ };
|
||||
int rec_batch_num_ = 1;
|
||||
CrnnResizeImg resize_op_;
|
||||
Normalize normalize_op_;
|
||||
PermuteBatch permute_op_;
|
||||
};
|
||||
}
|
||||
68
ANSOCR/ANSPaddleOCR/include/paddleocr.h
Normal file
68
ANSOCR/ANSPaddleOCR/include/paddleocr.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// 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 <include/ocr_cls.h>
|
||||
#include <include/ocr_det.h>
|
||||
#include <include/ocr_rec.h>
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
class PPOCR {
|
||||
public:
|
||||
explicit PPOCR();
|
||||
~PPOCR();
|
||||
|
||||
std::vector<OCRPredictResult> ocr(const cv::Mat& img);
|
||||
bool Initialize(std::string detectionModelDir, std::string classifierModelDir, std::string recognizerModelDir, std::string labelDir);
|
||||
void SetParameters(std::string limit_type,
|
||||
std::string det_db_score_mode,
|
||||
bool is_scale,
|
||||
double det_db_thresh,
|
||||
double det_db_box_thresh,
|
||||
double det_db_unclip_ratio,
|
||||
bool use_dilation,
|
||||
int cls_batch_num,
|
||||
double cls_thresh,
|
||||
int rec_batch_num);
|
||||
void GetParameters(std::string& limit_type,
|
||||
std::string& det_db_score_mode,
|
||||
bool& is_scale,
|
||||
double& det_db_thresh,
|
||||
double& det_db_box_thresh,
|
||||
double& det_db_unclip_ratio,
|
||||
bool& use_dilation,
|
||||
int& cls_batch_num,
|
||||
double& cls_thresh,
|
||||
int& rec_batch_num);
|
||||
protected:
|
||||
std::unique_ptr<Detector> detector_ = nullptr;
|
||||
std::unique_ptr<Classifier> classifier_ = nullptr;
|
||||
std::unique_ptr<Recognizer> recognizer_ = nullptr;
|
||||
std::recursive_mutex _mutex;
|
||||
|
||||
std::string _limit_type;
|
||||
std::string _det_db_score_mode;
|
||||
bool _is_scale;
|
||||
double _det_db_thresh;
|
||||
double _det_db_box_thresh;
|
||||
double _det_db_unclip_ratio;
|
||||
bool _use_dilation;
|
||||
int _cls_batch_num;
|
||||
double _cls_thresh;
|
||||
int _rec_batch_num;
|
||||
};
|
||||
|
||||
} // namespace PaddleOCR
|
||||
110
ANSOCR/ANSPaddleOCR/include/paddleocr_utility.h
Normal file
110
ANSOCR/ANSPaddleOCR/include/paddleocr_utility.h
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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 {
|
||||
|
||||
struct OCRPredictResult {
|
||||
std::vector<std::vector<int>> box;
|
||||
std::string text;
|
||||
float score = -1.0;
|
||||
float cls_score;
|
||||
int cls_label = -1;
|
||||
};
|
||||
|
||||
struct StructurePredictResult {
|
||||
std::vector<float> box;
|
||||
std::vector<std::vector<int>> cell_box;
|
||||
std::string type;
|
||||
std::vector<OCRPredictResult> text_res;
|
||||
std::string html;
|
||||
float html_score = -1;
|
||||
float confidence;
|
||||
};
|
||||
|
||||
class Utility {
|
||||
public:
|
||||
static std::vector<std::string> ReadDict(const std::string &path);
|
||||
|
||||
static void VisualizeBboxes(const cv::Mat &srcimg,
|
||||
const std::vector<OCRPredictResult> &ocr_result,
|
||||
const std::string &save_path);
|
||||
|
||||
static void VisualizeBboxes(const cv::Mat &srcimg,
|
||||
const StructurePredictResult &structure_result,
|
||||
const std::string &save_path);
|
||||
|
||||
template <class ForwardIterator>
|
||||
inline static size_t argmax(ForwardIterator first, ForwardIterator last) {
|
||||
return std::distance(first, std::max_element(first, last));
|
||||
}
|
||||
|
||||
static void GetAllFiles(const char *dir_name,
|
||||
std::vector<std::string> &all_inputs);
|
||||
|
||||
static cv::Mat GetRotateCropImage(const cv::Mat &srcimage,
|
||||
std::vector<std::vector<int>> box);
|
||||
|
||||
static std::vector<int> argsort(const std::vector<float> &array);
|
||||
|
||||
static std::string basename(const std::string &filename);
|
||||
|
||||
static bool PathExists(const std::string &path);
|
||||
|
||||
static void CreateDir(const std::string &path);
|
||||
|
||||
static void print_result(const std::vector<OCRPredictResult> &ocr_result);
|
||||
|
||||
static cv::Mat crop_image(cv::Mat &img, const std::vector<int> &area);
|
||||
static cv::Mat crop_image(cv::Mat &img, const std::vector<float> &area);
|
||||
|
||||
static void sorted_boxes(std::vector<OCRPredictResult> &ocr_result);
|
||||
|
||||
static std::vector<int> xyxyxyxy2xyxy(std::vector<std::vector<int>> &box);
|
||||
static std::vector<int> xyxyxyxy2xyxy(std::vector<int> &box);
|
||||
|
||||
static float fast_exp(float x);
|
||||
static std::vector<float>
|
||||
activation_function_softmax(std::vector<float> &src);
|
||||
static float iou(std::vector<int> &box1, std::vector<int> &box2);
|
||||
static float iou(std::vector<float> &box1, std::vector<float> &box2);
|
||||
|
||||
private:
|
||||
static bool comparison_box(const OCRPredictResult &result1,
|
||||
const OCRPredictResult &result2) {
|
||||
if (result1.box[0][1] < result2.box[0][1]) {
|
||||
return true;
|
||||
} else if (result1.box[0][1] == result2.box[0][1]) {
|
||||
return result1.box[0][0] < result2.box[0][0];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace PaddleOCR
|
||||
53
ANSOCR/ANSPaddleOCR/include/paddlestructure.h
Normal file
53
ANSOCR/ANSPaddleOCR/include/paddlestructure.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2022 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 <include/paddleocr.h>
|
||||
#include <include/structure_layout.h>
|
||||
#include <include/structure_table.h>
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
class PaddleStructure : public PPOCR {
|
||||
public:
|
||||
explicit PaddleStructure();
|
||||
~PaddleStructure();
|
||||
bool Initialize(std::string layModelDir, std::string layModelDic, std::string tabModelDir, std::string tabModelDic);
|
||||
std::vector<StructurePredictResult> structure(cv::Mat img);
|
||||
|
||||
|
||||
private:
|
||||
Layout *layout_model_ = nullptr;
|
||||
Table *table_model_ = nullptr;
|
||||
|
||||
std::string rebuild_table(std::vector<std::string> rec_html_tags,
|
||||
std::vector<std::vector<int>> rec_boxes,
|
||||
std::vector<OCRPredictResult> &ocr_result);
|
||||
|
||||
float dis(std::vector<int> &box1, std::vector<int> &box2);
|
||||
|
||||
static bool comparison_dis(const std::vector<float> &dis1,
|
||||
const std::vector<float> &dis2) {
|
||||
if (dis1[1] < dis2[1]) {
|
||||
return true;
|
||||
} else if (dis1[1] == dis2[1]) {
|
||||
return dis1[0] < dis2[0];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace PaddleOCR
|
||||
119
ANSOCR/ANSPaddleOCR/include/postprocess_op.h
Normal file
119
ANSOCR/ANSPaddleOCR/include/postprocess_op.h
Normal file
@@ -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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "include/clipper.h"
|
||||
#include "include/paddleocr_utility.h"
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
class DBPostProcessor {
|
||||
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);
|
||||
float PolygonScoreAcc(std::vector<cv::Point> contour, 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,
|
||||
const std::string &det_db_score_mode);
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
class TablePostProcessor {
|
||||
public:
|
||||
void init(std::string label_path, bool merge_no_span_structure = true);
|
||||
void Run(std::vector<float> &loc_preds, std::vector<float> &structure_probs,
|
||||
std::vector<float> &rec_scores, ov::Shape &loc_preds_shape,
|
||||
ov::Shape &structure_probs_shape,
|
||||
std::vector<std::vector<std::string>> &rec_html_tag_batch,
|
||||
std::vector<std::vector<std::vector<int>>> &rec_boxes_batch,
|
||||
std::vector<int> &width_list, std::vector<int> &height_list);
|
||||
|
||||
private:
|
||||
std::vector<std::string> label_list_;
|
||||
std::string end = "eos";
|
||||
std::string beg = "sos";
|
||||
};
|
||||
|
||||
class PicodetPostProcessor {
|
||||
public:
|
||||
void init(std::string label_path, const double score_threshold = 0.4,
|
||||
const double nms_threshold = 0.5,
|
||||
const std::vector<int> &fpn_stride = {8, 16, 32, 64});
|
||||
void Run(std::vector<StructurePredictResult> &results,
|
||||
std::vector<std::vector<float>> outs, std::vector<int> ori_shape,
|
||||
std::vector<int> resize_shape, int eg_max);
|
||||
std::vector<int> fpn_stride_ = {8, 16, 32, 64};
|
||||
|
||||
private:
|
||||
StructurePredictResult disPred2Bbox(std::vector<float> bbox_pred, int label,
|
||||
float score, int x, int y, int stride,
|
||||
std::vector<int> im_shape, int reg_max);
|
||||
void nms(std::vector<StructurePredictResult> &input_boxes,
|
||||
float nms_threshold);
|
||||
|
||||
std::vector<std::string> label_list_;
|
||||
double score_threshold_ = 0.4;
|
||||
double nms_threshold_ = 0.5;
|
||||
int num_class_ = 5;
|
||||
};
|
||||
|
||||
} // namespace PaddleOCR
|
||||
80
ANSOCR/ANSPaddleOCR/include/preprocess_op.h
Normal file
80
ANSOCR/ANSPaddleOCR/include/preprocess_op.h
Normal file
@@ -0,0 +1,80 @@
|
||||
// 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 <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
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 PermuteBatch {
|
||||
public:
|
||||
virtual void Run(const std::vector<cv::Mat> imgs, float *data);
|
||||
};
|
||||
|
||||
class ResizeImgType0 {
|
||||
public:
|
||||
virtual void Run(const cv::Mat &img, cv::Mat &resize_img,
|
||||
std::string limit_type, int limit_side_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});
|
||||
};
|
||||
|
||||
class ClsResizeImg {
|
||||
public:
|
||||
virtual void Run(const cv::Mat &img, cv::Mat &resize_img,
|
||||
const std::vector<size_t> &rec_image_shape = {3, 48, 192});
|
||||
};
|
||||
|
||||
class TableResizeImg {
|
||||
public:
|
||||
virtual void Run(const cv::Mat &img, cv::Mat &resize_img,
|
||||
const int max_len = 488);
|
||||
};
|
||||
|
||||
class TablePadImg {
|
||||
public:
|
||||
virtual void Run(const cv::Mat &img, cv::Mat &resize_img,
|
||||
const int max_len = 488);
|
||||
};
|
||||
|
||||
class Resize {
|
||||
public:
|
||||
virtual void Run(const cv::Mat &img, cv::Mat &resize_img, const int h,
|
||||
const int w);
|
||||
};
|
||||
|
||||
} // namespace PaddleOCR
|
||||
50
ANSOCR/ANSPaddleOCR/include/structure_layout.h
Normal file
50
ANSOCR/ANSPaddleOCR/include/structure_layout.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#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/paddleocr_utility.h>
|
||||
#include <include/preprocess_op.h>
|
||||
#include <include/postprocess_op.h>
|
||||
#include <openvino/openvino.hpp>
|
||||
#include <openvino/core/preprocess/pre_post_process.hpp>
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
class Layout
|
||||
{
|
||||
public:
|
||||
explicit Layout(std::string model_path, std::string layout_dict_path);
|
||||
void Run(cv::Mat &src_img, std::vector<StructurePredictResult> &structure_result);
|
||||
|
||||
private:
|
||||
|
||||
ov::InferRequest infer_request;
|
||||
std::string model_path;
|
||||
std::shared_ptr<ov::Model> model;
|
||||
ov::CompiledModel compiled_model;
|
||||
|
||||
cv::Mat src_img;
|
||||
cv::Mat resize_img;
|
||||
double e = 1.0 / 255.0;
|
||||
const int layout_img_h_ = 800;
|
||||
const int layout_img_w_ = 608;
|
||||
double layout_nms_threshold = 0.5;
|
||||
double layout_score_threshold = 0.5;
|
||||
std::vector<float> mean_ = {0.485f, 0.456f, 0.406f};
|
||||
std::vector<float> scale_ = {0.229f, 0.224f, 0.225f};
|
||||
|
||||
// resize
|
||||
Resize resize_op_;
|
||||
// post-process
|
||||
PicodetPostProcessor post_processor_;
|
||||
};
|
||||
}
|
||||
56
ANSOCR/ANSPaddleOCR/include/structure_table.h
Normal file
56
ANSOCR/ANSPaddleOCR/include/structure_table.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#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/paddleocr_utility.h>
|
||||
#include <include/preprocess_op.h>
|
||||
#include <include/postprocess_op.h>
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
class Table
|
||||
{
|
||||
public:
|
||||
explicit Table(std::string model_path, const std::string table_char_dict_path);
|
||||
void Run(std::vector<cv::Mat> img_list,
|
||||
std::vector<std::vector<std::string>> &structure_html_tags,
|
||||
std::vector<float> &structure_scores,
|
||||
std::vector<std::vector<std::vector<int>>> &structure_boxes);
|
||||
|
||||
private:
|
||||
|
||||
ov::InferRequest infer_request;
|
||||
std::string model_path;
|
||||
std::shared_ptr<ov::Model> model;
|
||||
ov::CompiledModel compiled_model;
|
||||
|
||||
cv::Mat src_img;
|
||||
cv::Mat resize_img;
|
||||
const std::string table_char_dict_path;
|
||||
|
||||
int table_batch_num_ = 1;
|
||||
int table_max_len_ = 488;
|
||||
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
|
||||
TableResizeImg resize_op_;
|
||||
Normalize normalize_op_;
|
||||
PermuteBatch permute_op_;
|
||||
TablePadImg pad_op_;
|
||||
|
||||
// post-process
|
||||
TablePostProcessor post_processor_;
|
||||
};
|
||||
}
|
||||
17
ANSOCR/ANSPaddleOCR/src/args.cpp
Normal file
17
ANSOCR/ANSPaddleOCR/src/args.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
DEFINE_string(input, "", "Required. Path to image file");
|
||||
DEFINE_string(type, "", "Required. Task type ('ocr' or 'structure')");
|
||||
DEFINE_string(output_dir, "./", "Path to output results.");
|
||||
DEFINE_string(det_model_dir, "", "Path to detection model file");
|
||||
DEFINE_string(cls_model_dir, "", "Path to classification model file");
|
||||
DEFINE_string(rec_model_dir, "", "Path to recognition model file");
|
||||
DEFINE_string(lay_model_dir, "", "Path to layout model file");
|
||||
DEFINE_string(tab_model_dir, "", "Path to table model file");
|
||||
DEFINE_string(label_dir, "", "Required. Path to label file");
|
||||
DEFINE_string(layout_dict_dir,
|
||||
"/home/ethan/PaddleOCR_OpenVINO_CPP/data/layout_publaynet_dict.txt",
|
||||
"Path of dictionary.");
|
||||
DEFINE_string(table_dict_dir,
|
||||
"/home/ethan/PaddleOCR_OpenVINO_CPP/data/table_structure_dict.txt",
|
||||
"Path of dictionary.");
|
||||
4382
ANSOCR/ANSPaddleOCR/src/clipper.cpp
Normal file
4382
ANSOCR/ANSPaddleOCR/src/clipper.cpp
Normal file
File diff suppressed because it is too large
Load Diff
115
ANSOCR/ANSPaddleOCR/src/ocr_cls.cpp
Normal file
115
ANSOCR/ANSPaddleOCR/src/ocr_cls.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "include/ocr_cls.h"
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
std::string Classifier::GetOpenVINODevice() {
|
||||
ov::Core core;
|
||||
std::vector<std::string> available_devices = core.get_available_devices();
|
||||
|
||||
// Prioritize devices: NPU > GPU > CPU
|
||||
std::vector<std::string> priority_devices = { "GPU", "CPU" };
|
||||
for (const auto& device : priority_devices) {
|
||||
if (std::find(available_devices.begin(), available_devices.end(), device) != available_devices.end()) {
|
||||
return device; // Return the first available device based on priority
|
||||
}
|
||||
}
|
||||
return "CPU";
|
||||
}
|
||||
Classifier::Classifier(std::string model_path)
|
||||
{
|
||||
this->model_path = model_path;
|
||||
ov::Core core;
|
||||
this->model = core.read_model(this->model_path);
|
||||
// dimension of batch size is dynamic
|
||||
this->model->reshape({ {ov::Dimension(1, 6), cls_image_shape[0], cls_image_shape[1], cls_image_shape[2]} });
|
||||
// preprocessing API
|
||||
ov::preprocess::PrePostProcessor prep(this->model);
|
||||
// declare section of desired application's input format
|
||||
prep.input().tensor()
|
||||
.set_layout("NHWC")
|
||||
.set_color_format(ov::preprocess::ColorFormat::BGR);
|
||||
// specify actual model layout
|
||||
prep.input().model()
|
||||
.set_layout("NCHW");
|
||||
prep.input().preprocess()
|
||||
.mean(this->mean_)
|
||||
.scale(this->scale_);
|
||||
std::string deviceName = GetOpenVINODevice();
|
||||
this->model = prep.build();
|
||||
//core.set_property(deviceName, ov::hint::performance_mode(ov::hint::PerformanceMode::THROUGHPUT));
|
||||
this->compiled_model = core.compile_model(this->model, deviceName);
|
||||
this->infer_request = compiled_model.create_infer_request();
|
||||
}
|
||||
void Classifier::SetParameters(int cls_batch_num, double cls_thresh) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
this->cls_batch_num_ = cls_batch_num;
|
||||
this->cls_thresh = cls_thresh;
|
||||
}
|
||||
void Classifier::GetParameters(int& cls_batch_num, double& cls_thresh) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
cls_batch_num = this->cls_batch_num_;
|
||||
cls_thresh = this->cls_thresh;
|
||||
}
|
||||
void Classifier::Run(std::vector<cv::Mat> img_list, std::vector<OCRPredictResult>& ocr_results)
|
||||
{
|
||||
try {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
std::vector<int> cls_labels(img_list.size(), 0);
|
||||
std::vector<float> cls_scores(img_list.size(), 0);
|
||||
std::vector<double> cls_times;
|
||||
auto input_port = this->compiled_model.input();
|
||||
int img_num = img_list.size();
|
||||
for (int beg_img_no = 0; beg_img_no < img_num; beg_img_no += this->cls_batch_num_) {
|
||||
int end_img_no = std::min(img_num, beg_img_no + this->cls_batch_num_);
|
||||
size_t batch_num = end_img_no - beg_img_no;
|
||||
|
||||
std::vector<ov::Tensor> batch_tensors;
|
||||
ov::Shape intput_shape = { batch_num, cls_image_shape[1], cls_image_shape[2],3 };
|
||||
for (int ino = beg_img_no; ino < end_img_no; ino++) {
|
||||
cv::Mat srcimg;
|
||||
img_list[ino].copyTo(srcimg);
|
||||
cv::Mat resize_img;
|
||||
// preprocess
|
||||
this->resize_op_.Run(srcimg, resize_img, this->cls_image_shape);
|
||||
resize_img.convertTo(resize_img, CV_32FC3, e);
|
||||
if (resize_img.cols < cls_image_shape[2]) {
|
||||
cv::copyMakeBorder(resize_img, resize_img, 0, 0, 0,
|
||||
cls_image_shape[2] - resize_img.cols,
|
||||
cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));
|
||||
}
|
||||
// prepare input tensor
|
||||
ov::Tensor input_tensor(input_port.get_element_type(), intput_shape, (float*)resize_img.data);
|
||||
batch_tensors.push_back(input_tensor);
|
||||
}
|
||||
|
||||
// set batched input tensors
|
||||
this->infer_request.set_input_tensors(batch_tensors);
|
||||
// start inference
|
||||
//this->infer_request.start_async();
|
||||
//this->infer_request.wait();
|
||||
this->infer_request.infer();
|
||||
// get output tensor
|
||||
auto output = this->infer_request.get_output_tensor();
|
||||
const float* out_data = output.data<const float>();
|
||||
for (size_t batch_idx = 0; batch_idx < output.get_size() / 2; batch_idx++) {
|
||||
int label = int(
|
||||
Utility::argmax(&out_data[batch_idx * 2],
|
||||
&out_data[(batch_idx + 1) * 2]));
|
||||
float score = float(*std::max_element(
|
||||
&out_data[batch_idx * 2],
|
||||
&out_data[(batch_idx + 1) * 2]));
|
||||
cls_labels[beg_img_no + batch_idx] = label;
|
||||
cls_scores[beg_img_no + batch_idx] = score;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < cls_labels.size(); i++) {
|
||||
ocr_results[i].cls_label = cls_labels[i];
|
||||
ocr_results[i].cls_score = cls_scores[i];
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
124
ANSOCR/ANSPaddleOCR/src/ocr_det.cpp
Normal file
124
ANSOCR/ANSPaddleOCR/src/ocr_det.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "include/ocr_det.h"
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
Detector::Detector(std::string model_path)
|
||||
{
|
||||
ov::Core core;
|
||||
this->model_path = model_path;
|
||||
this->model = core.read_model(this->model_path);
|
||||
this->model->reshape({ 1, 3, ov::Dimension(32, this->limit_side_len_), ov::Dimension(1, this->limit_side_len_) });
|
||||
//core.set_property("CPU", ov::hint::performance_mode(ov::hint::PerformanceMode::THROUGHPUT));
|
||||
this->compiled_model = core.compile_model(this->model, "CPU");
|
||||
//this->compiled_model = core.compile_model(this->model, "CPU");
|
||||
this->infer_request = this->compiled_model.create_infer_request();
|
||||
}
|
||||
void Detector::SetParameters(std::string limit_type,
|
||||
std::string det_db_score_mode,
|
||||
bool is_scale,
|
||||
double det_db_thresh,
|
||||
double det_db_box_thresh,
|
||||
double det_db_unclip_ratio,
|
||||
bool use_dilation)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
this->limit_type_ = limit_type;
|
||||
this->det_db_score_mode_ = det_db_score_mode;
|
||||
this->is_scale_ = is_scale;
|
||||
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->use_dilation_ = use_dilation;
|
||||
}
|
||||
void Detector::GetParameters(std::string& limit_type,
|
||||
std::string& det_db_score_mode,
|
||||
bool& is_scale,
|
||||
double& det_db_thresh,
|
||||
double& det_db_box_thresh,
|
||||
double& det_db_unclip_ratio,
|
||||
bool& use_dilation)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
limit_type = this->limit_type_;
|
||||
det_db_score_mode = this->det_db_score_mode_;
|
||||
is_scale = this->is_scale_;
|
||||
det_db_thresh = this->det_db_thresh_;
|
||||
det_db_box_thresh = this->det_db_box_thresh_;
|
||||
det_db_unclip_ratio = this->det_db_unclip_ratio_;
|
||||
use_dilation = this->use_dilation_;
|
||||
}
|
||||
void Detector::Run(const cv::Mat& src_img, std::vector<OCRPredictResult>& ocr_results)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
try {
|
||||
this->src_img = src_img;
|
||||
this->resize_op_.Run(this->src_img, this->resize_img, this->limit_type_,
|
||||
this->limit_side_len_, this->ratio_h, this->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);
|
||||
ov::Shape intput_shape = { 1, 3, (size_t)resize_img.rows, (size_t)resize_img.cols };
|
||||
this->permute_op_.Run(&resize_img, input.data());
|
||||
|
||||
std::vector<std::vector<std::vector<int>>> boxes;
|
||||
auto input_port = this->compiled_model.input();
|
||||
|
||||
// -------- set input --------
|
||||
ov::Tensor input_tensor(input_port.get_element_type(), intput_shape, input.data());
|
||||
this->infer_request.set_input_tensor(input_tensor);
|
||||
// -------- start inference --------
|
||||
|
||||
/* this->infer_request.start_async();
|
||||
this->infer_request.wait();*/
|
||||
|
||||
this->infer_request.infer();
|
||||
|
||||
auto output = this->infer_request.get_output_tensor(0);
|
||||
const float* out_data = output.data<const float>();
|
||||
|
||||
ov::Shape output_shape = output.get_shape();
|
||||
const size_t n2 = output_shape[2];
|
||||
const size_t n3 = output_shape[3];
|
||||
const 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);
|
||||
if (this->use_dilation_) {
|
||||
cv::Mat dila_ele =
|
||||
cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2));
|
||||
cv::dilate(bit_map, bit_map, dila_ele);
|
||||
}
|
||||
|
||||
boxes = post_processor_.BoxesFromBitmap(
|
||||
pred_map, bit_map, this->det_db_box_thresh_, this->det_db_unclip_ratio_,
|
||||
this->det_db_score_mode_);
|
||||
|
||||
boxes = post_processor_.FilterTagDetRes(boxes, this->ratio_h, this->ratio_w, this->src_img);
|
||||
for (int i = 0; i < boxes.size(); i++) {
|
||||
OCRPredictResult res;
|
||||
res.box = boxes[i];
|
||||
ocr_results.push_back(res);
|
||||
}
|
||||
// sort boex from top to bottom, from left to right
|
||||
Utility::sorted_boxes(ocr_results);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
130
ANSOCR/ANSPaddleOCR/src/ocr_rec.cpp
Normal file
130
ANSOCR/ANSPaddleOCR/src/ocr_rec.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "include/ocr_rec.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace PaddleOCR {
|
||||
Recognizer::Recognizer(string model_path, const string& label_path) {
|
||||
ov::Core core;
|
||||
this->model_path = model_path;
|
||||
this->model = core.read_model(this->model_path);
|
||||
// reshape the model for dynamic batch size and sentence width
|
||||
this->model->reshape({ {ov::Dimension(1, 6), this->rec_image_shape_[0], this->rec_image_shape_[1], -1} });
|
||||
//core.set_property("CPU", ov::hint::performance_mode(ov::hint::PerformanceMode::THROUGHPUT));
|
||||
this->compiled_model = core.compile_model(this->model, "CPU");
|
||||
//this->compiled_model = core.compile_model(this->model, "CPU");
|
||||
this->infer_request = this->compiled_model.create_infer_request();
|
||||
this->label_list_ = Utility::ReadDict(label_path);
|
||||
this->label_list_.insert(this->label_list_.begin(),
|
||||
"#"); // blank char for ctc
|
||||
this->label_list_.push_back(" ");
|
||||
}
|
||||
void Recognizer::SetParameters(int rec_batch_num) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
this->rec_batch_num_ = rec_batch_num;
|
||||
|
||||
}
|
||||
void Recognizer::GetParameters(int& rec_batch_num) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
rec_batch_num = this->rec_batch_num_;
|
||||
|
||||
}
|
||||
void Recognizer::Run(const std::vector<cv::Mat> &img_list, std::vector<OCRPredictResult>& ocr_results) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
try {
|
||||
std::vector<std::string> rec_texts(img_list.size(), "");
|
||||
std::vector<float> rec_text_scores(img_list.size(), 0);
|
||||
int img_num = img_list.size();
|
||||
std::vector<float> width_list;
|
||||
for (int i = 0; i < img_num; i++) {
|
||||
width_list.push_back(float(img_list[i].cols) / img_list[i].rows);
|
||||
}
|
||||
std::vector<int> indices = Utility::argsort(width_list);
|
||||
|
||||
for (int beg_img_no = 0; beg_img_no < img_num;
|
||||
beg_img_no += this->rec_batch_num_) {
|
||||
int end_img_no = std::min(img_num, beg_img_no + this->rec_batch_num_);
|
||||
size_t batch_num = end_img_no - beg_img_no;
|
||||
size_t imgH = this->rec_image_shape_[1];
|
||||
size_t imgW = this->rec_image_shape_[2];
|
||||
float max_wh_ratio = imgW * 1.0 / imgH;
|
||||
for (int ino = beg_img_no; ino < end_img_no; ino++) {
|
||||
int h = img_list[indices[ino]].rows;
|
||||
int w = img_list[indices[ino]].cols;
|
||||
float wh_ratio = w * 1.0 / h;
|
||||
max_wh_ratio = std::max(max_wh_ratio, wh_ratio);
|
||||
}
|
||||
|
||||
int batch_width = imgW;
|
||||
std::vector<cv::Mat> norm_img_batch;
|
||||
for (int ino = beg_img_no; ino < end_img_no; ino++) {
|
||||
cv::Mat srcimg;
|
||||
img_list[indices[ino]].copyTo(srcimg);
|
||||
cv::Mat resize_img;
|
||||
// preprocess
|
||||
this->resize_op_.Run(srcimg, resize_img, max_wh_ratio, this->rec_image_shape_);
|
||||
this->normalize_op_.Run(&resize_img, this->mean_, this->scale_,
|
||||
this->is_scale_);
|
||||
norm_img_batch.push_back(resize_img);
|
||||
batch_width = std::max(resize_img.cols, batch_width);
|
||||
}
|
||||
// prepare input tensor
|
||||
std::vector<float> input(batch_num * 3 * imgH * batch_width, 0.0f);
|
||||
ov::Shape intput_shape = { batch_num, 3, imgH, (size_t)batch_width };
|
||||
this->permute_op_.Run(norm_img_batch, input.data());
|
||||
auto input_port = this->compiled_model.input();
|
||||
ov::Tensor input_tensor(input_port.get_element_type(), intput_shape, input.data());
|
||||
this->infer_request.set_input_tensor(input_tensor);
|
||||
// start inference
|
||||
/* this->infer_request.start_async();
|
||||
this->infer_request.wait();*/
|
||||
this->infer_request.infer();
|
||||
|
||||
auto output = this->infer_request.get_output_tensor();
|
||||
const float* out_data = output.data<const float>();
|
||||
auto predict_shape = output.get_shape();
|
||||
|
||||
// predict_batch is the result of Last FC with softmax
|
||||
for (int m = 0; m < predict_shape[0]; m++) {
|
||||
std::string str_res;
|
||||
int argmax_idx;
|
||||
int last_index = 0;
|
||||
float score = 0.f;
|
||||
int count = 0;
|
||||
float max_value = 0.0f;
|
||||
|
||||
for (int n = 0; n < predict_shape[1]; n++) {
|
||||
// get idx
|
||||
argmax_idx = int(Utility::argmax(
|
||||
&out_data[(m * predict_shape[1] + n) * predict_shape[2]],
|
||||
&out_data[(m * predict_shape[1] + n + 1) * predict_shape[2]]));
|
||||
// get score
|
||||
max_value = float(*std::max_element(
|
||||
&out_data[(m * predict_shape[1] + n) * predict_shape[2]],
|
||||
&out_data[(m * predict_shape[1] + n + 1) * predict_shape[2]]));
|
||||
|
||||
if (argmax_idx > 0 && (!(n > 0 && argmax_idx == last_index))) {
|
||||
score += max_value;
|
||||
count += 1;
|
||||
str_res += this->label_list_[argmax_idx];
|
||||
}
|
||||
last_index = argmax_idx;
|
||||
}
|
||||
score /= count;
|
||||
if (std::isnan(score)) {
|
||||
continue;
|
||||
}
|
||||
rec_texts[indices[beg_img_no + m]] = str_res;
|
||||
rec_text_scores[indices[beg_img_no + m]] = score;
|
||||
}
|
||||
}
|
||||
// sort boex from top to bottom, from left to right
|
||||
for (int i = 0; i < rec_texts.size(); i++) {
|
||||
ocr_results[i].text = rec_texts[i];
|
||||
ocr_results[i].score = rec_text_scores[i];
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
192
ANSOCR/ANSPaddleOCR/src/paddleocr.cpp
Normal file
192
ANSOCR/ANSPaddleOCR/src/paddleocr.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
// 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/paddleocr.h>
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
PPOCR::PPOCR() {
|
||||
this->_limit_type = "max";
|
||||
this->_det_db_score_mode = "slow";
|
||||
this->_is_scale = true;
|
||||
this->_det_db_thresh = 0.3;
|
||||
this->_det_db_box_thresh = 0.6;
|
||||
this->_det_db_unclip_ratio = 1.5;
|
||||
this->_use_dilation = false;
|
||||
this->_cls_batch_num = 1;
|
||||
this->_cls_thresh = 0.9;
|
||||
this->_rec_batch_num = 1;
|
||||
};
|
||||
|
||||
bool PPOCR::Initialize(std::string detectionModelDir, std::string classifierModelDir, std::string recognizerModelDir, std::string labelDir) {
|
||||
this->detector_ = std::make_unique<Detector>(detectionModelDir);
|
||||
if (!classifierModelDir.empty()) {
|
||||
this->classifier_ = std::make_unique<Classifier>(classifierModelDir);
|
||||
}
|
||||
this->recognizer_ = std::make_unique<Recognizer>(recognizerModelDir, labelDir);
|
||||
if (detector_) detector_->SetParameters(_limit_type, _det_db_score_mode, _is_scale, _det_db_thresh, _det_db_box_thresh, _det_db_unclip_ratio, _use_dilation);
|
||||
if (classifier_) classifier_->SetParameters(_cls_batch_num, _cls_thresh);
|
||||
if (recognizer_) recognizer_->SetParameters(_rec_batch_num);
|
||||
return true;
|
||||
}
|
||||
void PPOCR::SetParameters(std::string limit_type,
|
||||
std::string det_db_score_mode,
|
||||
bool is_scale,
|
||||
double det_db_thresh,
|
||||
double det_db_box_thresh,
|
||||
double det_db_unclip_ratio,
|
||||
bool use_dilation,
|
||||
int cls_batch_num,
|
||||
double cls_thresh,
|
||||
int rec_batch_num)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
this->_limit_type = limit_type;
|
||||
this->_det_db_score_mode = det_db_score_mode;
|
||||
this->_is_scale = is_scale;
|
||||
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->_use_dilation = use_dilation;
|
||||
this->_cls_batch_num = cls_batch_num;
|
||||
this->_cls_thresh = cls_thresh;
|
||||
this->_rec_batch_num = rec_batch_num;
|
||||
if (detector_) detector_->SetParameters(limit_type, det_db_score_mode, is_scale, det_db_thresh, det_db_box_thresh, det_db_unclip_ratio, use_dilation);
|
||||
if (classifier_) classifier_->SetParameters(cls_batch_num, cls_thresh);
|
||||
if (recognizer_) recognizer_->SetParameters(rec_batch_num);
|
||||
}
|
||||
void PPOCR::GetParameters(std::string& limit_type,
|
||||
std::string& det_db_score_mode,
|
||||
bool& is_scale,
|
||||
double& det_db_thresh,
|
||||
double& det_db_box_thresh,
|
||||
double& det_db_unclip_ratio,
|
||||
bool& use_dilation,
|
||||
int& cls_batch_num,
|
||||
double& cls_thresh,
|
||||
int& rec_batch_num)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
if (detector_) detector_->GetParameters(limit_type, det_db_score_mode, is_scale, det_db_thresh, det_db_box_thresh, det_db_unclip_ratio, use_dilation);
|
||||
if (classifier_) classifier_->GetParameters(cls_batch_num, cls_thresh);
|
||||
if (recognizer_) recognizer_->GetParameters(rec_batch_num);
|
||||
}
|
||||
//std::vector<OCRPredictResult> PPOCR::ocr(cv::Mat img)
|
||||
//{
|
||||
// std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
// try {
|
||||
// std::vector<OCRPredictResult> ocr_result;
|
||||
// // detect the sentence in input image
|
||||
// this->detector_->Run(img, ocr_result);
|
||||
// // crop image
|
||||
// std::vector<cv::Mat> img_list;
|
||||
// for (int j = 0; j < ocr_result.size(); j++) {
|
||||
// cv::Mat crop_img;
|
||||
// crop_img = Utility::GetRotateCropImage(img, ocr_result[j].box);
|
||||
// img_list.push_back(crop_img);
|
||||
// }
|
||||
|
||||
// if (this->classifier_ != nullptr) {
|
||||
// // find the reversed sentence and flip it
|
||||
// this->classifier_->Run(img_list, ocr_result);
|
||||
// for (int i = 0; i < img_list.size(); i++) {
|
||||
// if (ocr_result[i].cls_label % 2 == 1 &&
|
||||
// ocr_result[i].cls_score > _cls_thresh) {
|
||||
// cv::rotate(img_list[i], img_list[i], 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // recognize the words in sentence and print them
|
||||
// this->recognizer_->Run(img_list, ocr_result);
|
||||
|
||||
// return ocr_result;
|
||||
// }
|
||||
// catch (const std::exception& e) {
|
||||
// std::cerr << e.what() << std::endl;
|
||||
// return std::vector<OCRPredictResult>();
|
||||
// }
|
||||
//}
|
||||
std::vector<OCRPredictResult> PPOCR::ocr(const cv::Mat& img) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
std::vector<OCRPredictResult> ocr_result;
|
||||
|
||||
try {
|
||||
if (img.empty()) {
|
||||
std::cerr << "[PPOCR] Input image is empty!" << std::endl;
|
||||
return ocr_result;
|
||||
}
|
||||
|
||||
if (!this->detector_ || !this->recognizer_) {
|
||||
std::cerr << "[PPOCR] Detector or recognizer not initialized!" << std::endl;
|
||||
return ocr_result;
|
||||
}
|
||||
|
||||
// Run detector
|
||||
this->detector_->Run(img, ocr_result);
|
||||
|
||||
// Crop each detected region
|
||||
std::vector<cv::Mat> img_list;
|
||||
for (const auto& result : ocr_result) {
|
||||
try {
|
||||
cv::Mat crop_img = Utility::GetRotateCropImage(img, result.box);
|
||||
img_list.push_back(crop_img);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "[PPOCR] Error cropping region: " << e.what() << std::endl;
|
||||
img_list.push_back(cv::Mat()); // Push empty mat to preserve indexing
|
||||
}
|
||||
}
|
||||
|
||||
// Run classifier if available
|
||||
if (this->classifier_) {
|
||||
try {
|
||||
this->classifier_->Run(img_list, ocr_result);
|
||||
for (size_t i = 0; i < img_list.size() && i < ocr_result.size(); ++i) {
|
||||
if (!img_list[i].empty() &&
|
||||
(ocr_result[i].cls_label % 2 == 1) &&
|
||||
(ocr_result[i].cls_score > _cls_thresh)) {
|
||||
cv::rotate(img_list[i], img_list[i], cv::ROTATE_180); // same as rotate(img, img, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "[PPOCR] Classifier error: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Run recognizer
|
||||
try {
|
||||
this->recognizer_->Run(img_list, ocr_result);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "[PPOCR] Recognizer error: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "[PPOCR] General exception: " << e.what() << std::endl;
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "[PPOCR] Unknown exception occurred!" << std::endl;
|
||||
}
|
||||
|
||||
return ocr_result;
|
||||
}
|
||||
PPOCR::~PPOCR() {
|
||||
if (detector_) detector_.reset();
|
||||
if (classifier_) classifier_.reset();
|
||||
if (recognizer_) recognizer_.reset();
|
||||
}
|
||||
} // namespace PaddleOCR
|
||||
431
ANSOCR/ANSPaddleOCR/src/paddleocr_utility.cpp
Normal file
431
ANSOCR/ANSPaddleOCR/src/paddleocr_utility.cpp
Normal file
@@ -0,0 +1,431 @@
|
||||
// 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 <dirent.h>
|
||||
#include <include/paddleocr_utility.h>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
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<OCRPredictResult>& ocr_result,
|
||||
const std::string& save_path) {
|
||||
cv::Mat img_vis;
|
||||
srcimg.copyTo(img_vis);
|
||||
for (int n = 0; n < ocr_result.size(); n++) {
|
||||
cv::Point rook_points[4];
|
||||
for (int m = 0; m < ocr_result[n].box.size(); m++) {
|
||||
rook_points[m] =
|
||||
cv::Point(int(ocr_result[n].box[m][0]), int(ocr_result[n].box[m][1]));
|
||||
}
|
||||
|
||||
const cv::Point* ppt[1] = { rook_points };
|
||||
int npt[] = { 4 };
|
||||
cv::polylines(img_vis, ppt, npt, 1, 1, CV_RGB(0, 255, 0), 2, 8, 0);
|
||||
}
|
||||
|
||||
cv::imwrite(save_path, img_vis);
|
||||
std::cout << "The detection visualized image saved in " + save_path
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void Utility::VisualizeBboxes(const cv::Mat& srcimg,
|
||||
const StructurePredictResult& structure_result,
|
||||
const std::string& save_path) {
|
||||
cv::Mat img_vis;
|
||||
srcimg.copyTo(img_vis);
|
||||
img_vis = crop_image(img_vis, structure_result.box);
|
||||
for (int n = 0; n < structure_result.cell_box.size(); n++) {
|
||||
if (structure_result.cell_box[n].size() == 8) {
|
||||
cv::Point rook_points[4];
|
||||
for (int m = 0; m < structure_result.cell_box[n].size(); m += 2) {
|
||||
rook_points[m / 2] =
|
||||
cv::Point(int(structure_result.cell_box[n][m]),
|
||||
int(structure_result.cell_box[n][m + 1]));
|
||||
}
|
||||
const cv::Point* ppt[1] = { rook_points };
|
||||
int npt[] = { 4 };
|
||||
cv::polylines(img_vis, ppt, npt, 1, 1, CV_RGB(0, 255, 0), 2, 8, 0);
|
||||
}
|
||||
else if (structure_result.cell_box[n].size() == 4) {
|
||||
cv::Point rook_points[2];
|
||||
rook_points[0] = cv::Point(int(structure_result.cell_box[n][0]),
|
||||
int(structure_result.cell_box[n][1]));
|
||||
rook_points[1] = cv::Point(int(structure_result.cell_box[n][2]),
|
||||
int(structure_result.cell_box[n][3]));
|
||||
cv::rectangle(img_vis, rook_points[0], rook_points[1], CV_RGB(0, 255, 0),
|
||||
2, 8, 0);
|
||||
}
|
||||
}
|
||||
|
||||
cv::imwrite(save_path, img_vis);
|
||||
std::cout << "The table visualized image saved in " + save_path << std::endl;
|
||||
}
|
||||
|
||||
// list all files under a directory
|
||||
void Utility::GetAllFiles(const char* dir_name,
|
||||
std::vector<std::string>& all_inputs) {
|
||||
if (NULL == dir_name) {
|
||||
std::cout << " dir_name is null ! " << std::endl;
|
||||
return;
|
||||
}
|
||||
struct stat s;
|
||||
stat(dir_name, &s);
|
||||
if (!S_ISDIR(s.st_mode)) {
|
||||
std::cout << "dir_name is not a valid directory !" << std::endl;
|
||||
all_inputs.push_back(dir_name);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
struct dirent* filename; // return value for readdir()
|
||||
DIR* dir; // return value for opendir()
|
||||
dir = opendir(dir_name);
|
||||
if (NULL == dir) {
|
||||
std::cout << "Can not open dir " << dir_name << std::endl;
|
||||
return;
|
||||
}
|
||||
std::cout << "Successfully opened the dir !" << std::endl;
|
||||
while ((filename = readdir(dir)) != NULL) {
|
||||
if (strcmp(filename->d_name, ".") == 0 ||
|
||||
strcmp(filename->d_name, "..") == 0)
|
||||
continue;
|
||||
// img_dir + std::string("/") + all_inputs[0];
|
||||
all_inputs.push_back(dir_name + std::string("/") +
|
||||
std::string(filename->d_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat Utility::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;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> Utility::argsort(const std::vector<float>& array) {
|
||||
const int array_len(array.size());
|
||||
std::vector<int> array_index(array_len, 0);
|
||||
for (int i = 0; i < array_len; ++i)
|
||||
array_index[i] = i;
|
||||
|
||||
std::sort(
|
||||
array_index.begin(), array_index.end(),
|
||||
[&array](int pos1, int pos2) { return (array[pos1] < array[pos2]); });
|
||||
|
||||
return array_index;
|
||||
}
|
||||
|
||||
std::string Utility::basename(const std::string& filename) {
|
||||
if (filename.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
auto len = filename.length();
|
||||
auto index = filename.find_last_of("/\\");
|
||||
|
||||
if (index == std::string::npos) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
if (index + 1 >= len) {
|
||||
|
||||
len--;
|
||||
index = filename.substr(0, len).find_last_of("/\\");
|
||||
|
||||
if (len == 0) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
return filename.substr(1, len - 1);
|
||||
}
|
||||
|
||||
if (index == std::string::npos) {
|
||||
return filename.substr(0, len);
|
||||
}
|
||||
|
||||
return filename.substr(index + 1, len - index - 1);
|
||||
}
|
||||
|
||||
return filename.substr(index + 1, len - index);
|
||||
}
|
||||
|
||||
bool Utility::PathExists(const std::string& path) {
|
||||
#ifdef _WIN32
|
||||
struct _stat buffer;
|
||||
return (_stat(path.c_str(), &buffer) == 0);
|
||||
#else
|
||||
struct stat buffer;
|
||||
return (stat(path.c_str(), &buffer) == 0);
|
||||
#endif // !_WIN32
|
||||
}
|
||||
|
||||
void Utility::CreateDir(const std::string& path) {
|
||||
#ifdef _WIN32
|
||||
_mkdir(path.c_str());
|
||||
#else
|
||||
mkdir(path.c_str(), 0777);
|
||||
#endif // !_WIN32
|
||||
}
|
||||
|
||||
void Utility::print_result(const std::vector<OCRPredictResult>& ocr_result) {
|
||||
for (int i = 0; i < ocr_result.size(); i++) {
|
||||
std::cout << i << "\t";
|
||||
// det
|
||||
std::vector<std::vector<int>> boxes = ocr_result[i].box;
|
||||
if (boxes.size() > 0) {
|
||||
std::cout << "det boxes: [";
|
||||
for (int n = 0; n < boxes.size(); n++) {
|
||||
std::cout << '[' << boxes[n][0] << ',' << boxes[n][1] << "]";
|
||||
if (n != boxes.size() - 1) {
|
||||
std::cout << ',';
|
||||
}
|
||||
}
|
||||
std::cout << "] ";
|
||||
}
|
||||
// rec
|
||||
if (ocr_result[i].score != -1.0) {
|
||||
std::cout << "rec text: " << ocr_result[i].text
|
||||
<< " rec score: " << ocr_result[i].score << " ";
|
||||
}
|
||||
|
||||
// cls
|
||||
if (ocr_result[i].cls_label != -1) {
|
||||
std::cout << "cls label: " << ocr_result[i].cls_label
|
||||
<< " cls score: " << ocr_result[i].cls_score;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat Utility::crop_image(cv::Mat& img, const std::vector<int>& box) {
|
||||
cv::Mat crop_im;
|
||||
int crop_x1 = std::max(0, box[0]);
|
||||
int crop_y1 = std::max(0, box[1]);
|
||||
int crop_x2 = std::min(img.cols - 1, box[2] - 1);
|
||||
int crop_y2 = std::min(img.rows - 1, box[3] - 1);
|
||||
|
||||
crop_im = cv::Mat::zeros(box[3] - box[1], box[2] - box[0], 16);
|
||||
cv::Mat crop_im_window =
|
||||
crop_im(cv::Range(crop_y1 - box[1], crop_y2 + 1 - box[1]),
|
||||
cv::Range(crop_x1 - box[0], crop_x2 + 1 - box[0]));
|
||||
cv::Mat roi_img =
|
||||
img(cv::Range(crop_y1, crop_y2 + 1), cv::Range(crop_x1, crop_x2 + 1));
|
||||
crop_im_window += roi_img;
|
||||
return crop_im;
|
||||
}
|
||||
|
||||
cv::Mat Utility::crop_image(cv::Mat& img, const std::vector<float>& box) {
|
||||
std::vector<int> box_int = { (int)box[0], (int)box[1], (int)box[2],
|
||||
(int)box[3] };
|
||||
return crop_image(img, box_int);
|
||||
}
|
||||
|
||||
void Utility::sorted_boxes(std::vector<OCRPredictResult>& ocr_result) {
|
||||
std::sort(ocr_result.begin(), ocr_result.end(), Utility::comparison_box);
|
||||
if (ocr_result.size() > 0) {
|
||||
for (int i = 0; i < ocr_result.size() - 1; i++) {
|
||||
for (int j = i; j > 0; j--) {
|
||||
if (abs(ocr_result[j + 1].box[0][1] - ocr_result[j].box[0][1]) < 10 &&
|
||||
(ocr_result[j + 1].box[0][0] < ocr_result[j].box[0][0])) {
|
||||
std::swap(ocr_result[i], ocr_result[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> Utility::xyxyxyxy2xyxy(std::vector<std::vector<int>>& 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));
|
||||
std::vector<int> box1(4, 0);
|
||||
box1[0] = left;
|
||||
box1[1] = top;
|
||||
box1[2] = right;
|
||||
box1[3] = bottom;
|
||||
return box1;
|
||||
}
|
||||
|
||||
std::vector<int> Utility::xyxyxyxy2xyxy(std::vector<int>& box) {
|
||||
int x_collect[4] = { box[0], box[2], box[4], box[6] };
|
||||
int y_collect[4] = { box[1], box[3], box[5], box[7] };
|
||||
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));
|
||||
std::vector<int> box1(4, 0);
|
||||
box1[0] = left;
|
||||
box1[1] = top;
|
||||
box1[2] = right;
|
||||
box1[3] = bottom;
|
||||
return box1;
|
||||
}
|
||||
|
||||
float Utility::fast_exp(float x) {
|
||||
union {
|
||||
uint32_t i;
|
||||
float f;
|
||||
} v{};
|
||||
v.i = (1 << 23) * (1.4426950409 * x + 126.93490512f);
|
||||
return v.f;
|
||||
}
|
||||
|
||||
std::vector<float>
|
||||
Utility::activation_function_softmax(std::vector<float>& src) {
|
||||
int length = src.size();
|
||||
std::vector<float> dst;
|
||||
dst.resize(length);
|
||||
const float alpha = float(*std::max_element(&src[0], &src[0 + length]));
|
||||
float denominator{ 0 };
|
||||
|
||||
for (int i = 0; i < length; ++i) {
|
||||
dst[i] = fast_exp(src[i] - alpha);
|
||||
denominator += dst[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; ++i) {
|
||||
dst[i] /= denominator;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
float Utility::iou(std::vector<int>& box1, std::vector<int>& box2) {
|
||||
int area1 = std::max(0, box1[2] - box1[0]) * std::max(0, box1[3] - box1[1]);
|
||||
int area2 = std::max(0, box2[2] - box2[0]) * std::max(0, box2[3] - box2[1]);
|
||||
|
||||
// computing the sum_area
|
||||
int sum_area = area1 + area2;
|
||||
|
||||
// find the each point of intersect rectangle
|
||||
int x1 = std::max(box1[0], box2[0]);
|
||||
int y1 = std::max(box1[1], box2[1]);
|
||||
int x2 = std::min(box1[2], box2[2]);
|
||||
int y2 = std::min(box1[3], box2[3]);
|
||||
|
||||
// judge if there is an intersect
|
||||
if (y1 >= y2 || x1 >= x2) {
|
||||
return 0.0;
|
||||
}
|
||||
else {
|
||||
int intersect = (x2 - x1) * (y2 - y1);
|
||||
return intersect / (sum_area - intersect + 0.00000001);
|
||||
}
|
||||
}
|
||||
|
||||
float Utility::iou(std::vector<float>& box1, std::vector<float>& box2) {
|
||||
float area1 = std::max((float)0.0, box1[2] - box1[0]) *
|
||||
std::max((float)0.0, box1[3] - box1[1]);
|
||||
float area2 = std::max((float)0.0, box2[2] - box2[0]) *
|
||||
std::max((float)0.0, box2[3] - box2[1]);
|
||||
|
||||
// computing the sum_area
|
||||
float sum_area = area1 + area2;
|
||||
|
||||
// find the each point of intersect rectangle
|
||||
float x1 = std::max(box1[0], box2[0]);
|
||||
float y1 = std::max(box1[1], box2[1]);
|
||||
float x2 = std::min(box1[2], box2[2]);
|
||||
float y2 = std::min(box1[3], box2[3]);
|
||||
|
||||
// judge if there is an intersect
|
||||
if (y1 >= y2 || x1 >= x2) {
|
||||
return 0.0;
|
||||
}
|
||||
else {
|
||||
float intersect = (x2 - x1) * (y2 - y1);
|
||||
return intersect / (sum_area - intersect + 0.00000001);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PaddleOCR
|
||||
200
ANSOCR/ANSPaddleOCR/src/paddlestructure.cpp
Normal file
200
ANSOCR/ANSPaddleOCR/src/paddlestructure.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
// 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/paddlestructure.h>
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
PaddleStructure::PaddleStructure() {
|
||||
|
||||
};
|
||||
bool PaddleStructure::Initialize(std::string layModelDir, std::string layModelDic, std::string tabModelDir, std::string tabModelDic) {
|
||||
this->layout_model_ = new Layout(layModelDir, layModelDic);
|
||||
this->table_model_ = new Table(tabModelDir, tabModelDic);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<StructurePredictResult> PaddleStructure::structure(cv::Mat src_img) {
|
||||
std::vector<StructurePredictResult> structure_results;
|
||||
|
||||
this->layout_model_->Run(src_img, structure_results);
|
||||
cv::Mat roi_img;
|
||||
for (int i = 0; i < structure_results.size(); i++) {
|
||||
// crop image
|
||||
roi_img = Utility::crop_image(src_img, structure_results[i].box);
|
||||
if (structure_results[i].type == "table") {
|
||||
std::vector<std::vector<std::string>> structure_html_tags;
|
||||
std::vector<float> structure_scores(1, 0);
|
||||
std::vector<std::vector<std::vector<int>>> structure_boxes;
|
||||
std::vector<cv::Mat> img_list;
|
||||
|
||||
img_list.push_back(roi_img);
|
||||
this->table_model_->Run(img_list, structure_html_tags, structure_scores, structure_boxes);
|
||||
std::vector<OCRPredictResult> ocr_result;
|
||||
std::string html;
|
||||
int expand_pixel = 3;
|
||||
|
||||
for (int j = 0; j < img_list.size(); j++) {
|
||||
this->detector_->Run(img_list[j], ocr_result);
|
||||
// crop image
|
||||
std::vector<cv::Mat> rec_img_list;
|
||||
std::vector<int> ocr_box;
|
||||
for (int k = 0; k < ocr_result.size(); k++) {
|
||||
ocr_box = Utility::xyxyxyxy2xyxy(ocr_result[k].box);
|
||||
ocr_box[0] = std::max(0, ocr_box[0] - expand_pixel);
|
||||
ocr_box[1] = std::max(0, ocr_box[1] - expand_pixel),
|
||||
ocr_box[2] = std::min(img_list[j].cols, ocr_box[2] + expand_pixel);
|
||||
ocr_box[3] = std::min(img_list[j].rows, ocr_box[3] + expand_pixel);
|
||||
|
||||
cv::Mat crop_img = Utility::crop_image(img_list[j], ocr_box);
|
||||
rec_img_list.push_back(crop_img);
|
||||
}
|
||||
// rec
|
||||
this->recognizer_->Run(rec_img_list, ocr_result);
|
||||
// rebuild table
|
||||
html = this->rebuild_table(structure_html_tags[j], structure_boxes[j],
|
||||
ocr_result);
|
||||
structure_results[i].html = html;
|
||||
structure_results[i].cell_box = structure_boxes[j];
|
||||
structure_results[i].html_score = structure_scores[j];
|
||||
}
|
||||
}
|
||||
else {
|
||||
structure_results[i].text_res = ocr(roi_img);
|
||||
}
|
||||
}
|
||||
return structure_results;
|
||||
};
|
||||
|
||||
std::string
|
||||
PaddleStructure::rebuild_table(std::vector<std::string> structure_html_tags,
|
||||
std::vector<std::vector<int>> structure_boxes,
|
||||
std::vector<OCRPredictResult>& ocr_result) {
|
||||
// match text in same cell
|
||||
std::vector<std::vector<std::string>> matched(structure_boxes.size(),
|
||||
std::vector<std::string>());
|
||||
|
||||
std::vector<int> ocr_box;
|
||||
std::vector<int> structure_box;
|
||||
for (int i = 0; i < ocr_result.size(); i++) {
|
||||
ocr_box = Utility::xyxyxyxy2xyxy(ocr_result[i].box);
|
||||
ocr_box[0] -= 1;
|
||||
ocr_box[1] -= 1;
|
||||
ocr_box[2] += 1;
|
||||
ocr_box[3] += 1;
|
||||
std::vector<std::vector<float>> dis_list(structure_boxes.size(),
|
||||
std::vector<float>(3, 100000.0));
|
||||
for (int j = 0; j < structure_boxes.size(); j++) {
|
||||
if (structure_boxes[i].size() == 8) {
|
||||
structure_box = Utility::xyxyxyxy2xyxy(structure_boxes[j]);
|
||||
}
|
||||
else {
|
||||
structure_box = structure_boxes[j];
|
||||
}
|
||||
dis_list[j][0] = this->dis(ocr_box, structure_box);
|
||||
dis_list[j][1] = 1 - Utility::iou(ocr_box, structure_box);
|
||||
dis_list[j][2] = j;
|
||||
}
|
||||
// find min dis idx
|
||||
std::sort(dis_list.begin(), dis_list.end(),
|
||||
PaddleStructure::comparison_dis);
|
||||
matched[dis_list[0][2]].push_back(ocr_result[i].text);
|
||||
}
|
||||
|
||||
// get pred html
|
||||
std::string html_str = "";
|
||||
int td_tag_idx = 0;
|
||||
for (int i = 0; i < structure_html_tags.size(); i++) {
|
||||
if (structure_html_tags[i].find("</td>") != std::string::npos) {
|
||||
if (structure_html_tags[i].find("<td></td>") != std::string::npos) {
|
||||
html_str += "<td>";
|
||||
}
|
||||
if (matched[td_tag_idx].size() > 0) {
|
||||
bool b_with = false;
|
||||
if (matched[td_tag_idx][0].find("<b>") != std::string::npos &&
|
||||
matched[td_tag_idx].size() > 1) {
|
||||
b_with = true;
|
||||
html_str += "<b>";
|
||||
}
|
||||
for (int j = 0; j < matched[td_tag_idx].size(); j++) {
|
||||
std::string content = matched[td_tag_idx][j];
|
||||
if (matched[td_tag_idx].size() > 1) {
|
||||
// remove blank, <b> and </b>
|
||||
if (content.length() > 0 && content.at(0) == ' ') {
|
||||
content = content.substr(0);
|
||||
}
|
||||
if (content.length() > 2 && content.substr(0, 3) == "<b>") {
|
||||
content = content.substr(3);
|
||||
}
|
||||
if (content.length() > 4 &&
|
||||
content.substr(content.length() - 4) == "</b>") {
|
||||
content = content.substr(0, content.length() - 4);
|
||||
}
|
||||
if (content.empty()) {
|
||||
continue;
|
||||
}
|
||||
// add blank
|
||||
if (j != matched[td_tag_idx].size() - 1 &&
|
||||
content.at(content.length() - 1) != ' ') {
|
||||
content += ' ';
|
||||
}
|
||||
}
|
||||
html_str += content;
|
||||
}
|
||||
if (b_with) {
|
||||
html_str += "</b>";
|
||||
}
|
||||
}
|
||||
if (structure_html_tags[i].find("<td></td>") != std::string::npos) {
|
||||
html_str += "</td>";
|
||||
}
|
||||
else {
|
||||
html_str += structure_html_tags[i];
|
||||
}
|
||||
td_tag_idx += 1;
|
||||
}
|
||||
else {
|
||||
html_str += structure_html_tags[i];
|
||||
}
|
||||
}
|
||||
return html_str;
|
||||
}
|
||||
|
||||
float PaddleStructure::dis(std::vector<int>& box1, std::vector<int>& box2) {
|
||||
int x1_1 = box1[0];
|
||||
int y1_1 = box1[1];
|
||||
int x2_1 = box1[2];
|
||||
int y2_1 = box1[3];
|
||||
|
||||
int x1_2 = box2[0];
|
||||
int y1_2 = box2[1];
|
||||
int x2_2 = box2[2];
|
||||
int y2_2 = box2[3];
|
||||
|
||||
float dis =
|
||||
abs(x1_2 - x1_1) + abs(y1_2 - y1_1) + abs(x2_2 - x2_1) + abs(y2_2 - y2_1);
|
||||
float dis_2 = abs(x1_2 - x1_1) + abs(y1_2 - y1_1);
|
||||
float dis_3 = abs(x2_2 - x2_1) + abs(y2_2 - y2_1);
|
||||
return dis + std::min(dis_2, dis_3);
|
||||
}
|
||||
|
||||
PaddleStructure::~PaddleStructure() {
|
||||
if (this->layout_model_ != nullptr) {
|
||||
delete this->layout_model_;
|
||||
}
|
||||
if (this->table_model_ != nullptr) {
|
||||
delete this->table_model_;
|
||||
}
|
||||
};
|
||||
} // namespace PaddleOCR
|
||||
580
ANSOCR/ANSPaddleOCR/src/postprocess_op.cpp
Normal file
580
ANSOCR/ANSPaddleOCR/src/postprocess_op.cpp
Normal file
@@ -0,0 +1,580 @@
|
||||
// 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 DBPostProcessor::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 DBPostProcessor::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;
|
||||
if (points.size() <= 0) {
|
||||
res = cv::RotatedRect(cv::Point2f(0, 0), cv::Size2f(1, 1), 0);
|
||||
}
|
||||
else {
|
||||
res = cv::minAreaRect(points);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
float** DBPostProcessor::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>>
|
||||
DBPostProcessor::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>> DBPostProcessor::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 DBPostProcessor::XsortFp32(std::vector<float> a, std::vector<float> b) {
|
||||
if (a[0] != b[0])
|
||||
return a[0] < b[0];
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DBPostProcessor::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>>
|
||||
DBPostProcessor::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 DBPostProcessor::PolygonScoreAcc(std::vector<cv::Point> contour,
|
||||
cv::Mat pred) {
|
||||
int width = pred.cols;
|
||||
int height = pred.rows;
|
||||
std::vector<float> box_x;
|
||||
std::vector<float> box_y;
|
||||
for (int i = 0; i < contour.size(); ++i) {
|
||||
box_x.push_back(contour[i].x);
|
||||
box_y.push_back(contour[i].y);
|
||||
}
|
||||
|
||||
int xmin =
|
||||
clamp(int(std::floor(*(std::min_element(box_x.begin(), box_x.end())))), 0,
|
||||
width - 1);
|
||||
int xmax =
|
||||
clamp(int(std::ceil(*(std::max_element(box_x.begin(), box_x.end())))), 0,
|
||||
width - 1);
|
||||
int ymin =
|
||||
clamp(int(std::floor(*(std::min_element(box_y.begin(), box_y.end())))), 0,
|
||||
height - 1);
|
||||
int ymax =
|
||||
clamp(int(std::ceil(*(std::max_element(box_y.begin(), box_y.end())))), 0,
|
||||
height - 1);
|
||||
|
||||
cv::Mat mask;
|
||||
mask = cv::Mat::zeros(ymax - ymin + 1, xmax - xmin + 1, CV_8UC1);
|
||||
|
||||
cv::Point* rook_point = new cv::Point[contour.size()];
|
||||
|
||||
for (int i = 0; i < contour.size(); ++i) {
|
||||
rook_point[i] = cv::Point(int(box_x[i]) - xmin, int(box_y[i]) - ymin);
|
||||
}
|
||||
const cv::Point* ppt[1] = { rook_point };
|
||||
int npt[] = { int(contour.size()) };
|
||||
|
||||
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);
|
||||
float score = cv::mean(croppedImg, mask)[0];
|
||||
|
||||
delete[] rook_point;
|
||||
return score;
|
||||
}
|
||||
|
||||
float DBPostProcessor::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>>> DBPostProcessor::BoxesFromBitmap(
|
||||
const cv::Mat pred, const cv::Mat bitmap, const float& box_thresh,
|
||||
const float& det_db_unclip_ratio, const std::string& det_db_score_mode) {
|
||||
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++) {
|
||||
if (contours[_i].size() <= 2) {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
if (det_db_score_mode == "slow")
|
||||
/* compute using polygon*/
|
||||
score = PolygonScoreAcc(contours[_i], pred);
|
||||
else
|
||||
score = BoxScoreFast(array, pred);
|
||||
|
||||
if (score < box_thresh)
|
||||
continue;
|
||||
|
||||
// start for unclip
|
||||
cv::RotatedRect points = UnClip(box_for_unclip, det_db_unclip_ratio);
|
||||
if (points.size.height < 1.001 && points.size.width < 1.001) {
|
||||
continue;
|
||||
}
|
||||
// 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>>> DBPostProcessor::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 <= 4 || rect_height <= 4)
|
||||
continue;
|
||||
root_points.push_back(boxes[n]);
|
||||
}
|
||||
return root_points;
|
||||
}
|
||||
|
||||
void TablePostProcessor::init(std::string label_path,
|
||||
bool merge_no_span_structure) {
|
||||
this->label_list_ = Utility::ReadDict(label_path);
|
||||
if (merge_no_span_structure) {
|
||||
this->label_list_.push_back("<td></td>");
|
||||
std::vector<std::string>::iterator it;
|
||||
for (it = this->label_list_.begin(); it != this->label_list_.end();) {
|
||||
if (*it == "<td>") {
|
||||
it = this->label_list_.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
// add_special_char
|
||||
this->label_list_.insert(this->label_list_.begin(), this->beg);
|
||||
this->label_list_.push_back(this->end);
|
||||
}
|
||||
|
||||
void TablePostProcessor::Run(
|
||||
std::vector<float>& loc_preds, std::vector<float>& structure_probs,
|
||||
std::vector<float>& rec_scores, ov::Shape& loc_preds_shape,
|
||||
ov::Shape& structure_probs_shape,
|
||||
std::vector<std::vector<std::string>>& rec_html_tag_batch,
|
||||
std::vector<std::vector<std::vector<int>>>& rec_boxes_batch,
|
||||
std::vector<int>& width_list, std::vector<int>& height_list) {
|
||||
for (int batch_idx = 0; batch_idx < structure_probs_shape[0]; batch_idx++) {
|
||||
// image tags and boxs
|
||||
std::vector<std::string> rec_html_tags;
|
||||
std::vector<std::vector<int>> rec_boxes;
|
||||
|
||||
float score = 0.f;
|
||||
int count = 0;
|
||||
float char_score = 0.f;
|
||||
int char_idx = 0;
|
||||
|
||||
// step
|
||||
for (int step_idx = 0; step_idx < structure_probs_shape[1]; step_idx++) {
|
||||
std::string html_tag;
|
||||
std::vector<int> rec_box;
|
||||
// html tag
|
||||
int step_start_idx = (batch_idx * structure_probs_shape[1] + step_idx) *
|
||||
structure_probs_shape[2];
|
||||
char_idx = int(Utility::argmax(
|
||||
&structure_probs[step_start_idx],
|
||||
&structure_probs[step_start_idx + structure_probs_shape[2]]));
|
||||
char_score = float(*std::max_element(
|
||||
&structure_probs[step_start_idx],
|
||||
&structure_probs[step_start_idx + structure_probs_shape[2]]));
|
||||
html_tag = this->label_list_[char_idx];
|
||||
|
||||
if (step_idx > 0 && html_tag == this->end) {
|
||||
break;
|
||||
}
|
||||
if (html_tag == this->beg) {
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
score += char_score;
|
||||
rec_html_tags.push_back(html_tag);
|
||||
|
||||
// box
|
||||
if (html_tag == "<td>" || html_tag == "<td" || html_tag == "<td></td>") {
|
||||
for (int point_idx = 0; point_idx < loc_preds_shape[2]; point_idx++) {
|
||||
step_start_idx = (batch_idx * structure_probs_shape[1] + step_idx) *
|
||||
loc_preds_shape[2] +
|
||||
point_idx;
|
||||
float point = loc_preds[step_start_idx];
|
||||
if (point_idx % 2 == 0) {
|
||||
point = int(point * width_list[batch_idx]);
|
||||
}
|
||||
else {
|
||||
point = int(point * height_list[batch_idx]);
|
||||
}
|
||||
rec_box.push_back(point);
|
||||
}
|
||||
rec_boxes.push_back(rec_box);
|
||||
}
|
||||
}
|
||||
score /= count;
|
||||
if (std::isnan(score) || rec_boxes.size() == 0) {
|
||||
score = -1;
|
||||
}
|
||||
rec_scores.push_back(score);
|
||||
rec_boxes_batch.push_back(rec_boxes);
|
||||
rec_html_tag_batch.push_back(rec_html_tags);
|
||||
}
|
||||
}
|
||||
|
||||
void PicodetPostProcessor::init(std::string label_path,
|
||||
const double score_threshold,
|
||||
const double nms_threshold,
|
||||
const std::vector<int>& fpn_stride) {
|
||||
this->label_list_ = Utility::ReadDict(label_path);
|
||||
this->score_threshold_ = score_threshold;
|
||||
this->nms_threshold_ = nms_threshold;
|
||||
this->num_class_ = label_list_.size();
|
||||
this->fpn_stride_ = fpn_stride;
|
||||
}
|
||||
|
||||
void PicodetPostProcessor::Run(std::vector<StructurePredictResult>& results,
|
||||
std::vector<std::vector<float>> outs,
|
||||
std::vector<int> ori_shape,
|
||||
std::vector<int> resize_shape, int reg_max) {
|
||||
int in_h = resize_shape[0];
|
||||
int in_w = resize_shape[1];
|
||||
float scale_factor_h = resize_shape[0] / float(ori_shape[0]);
|
||||
float scale_factor_w = resize_shape[1] / float(ori_shape[1]);
|
||||
|
||||
std::vector<std::vector<StructurePredictResult>> bbox_results;
|
||||
bbox_results.resize(this->num_class_);
|
||||
for (int i = 0; i < this->fpn_stride_.size(); ++i) {
|
||||
int feature_h = std::ceil((float)in_h / this->fpn_stride_[i]);
|
||||
int feature_w = std::ceil((float)in_w / this->fpn_stride_[i]);
|
||||
for (int idx = 0; idx < feature_h * feature_w; idx++) {
|
||||
// score and label
|
||||
float score = 0;
|
||||
int cur_label = 0;
|
||||
for (int label = 0; label < this->num_class_; label++) {
|
||||
if (outs[i][idx * this->num_class_ + label] > score) {
|
||||
score = outs[i][idx * this->num_class_ + label];
|
||||
cur_label = label;
|
||||
}
|
||||
}
|
||||
// bbox
|
||||
if (score > this->score_threshold_) {
|
||||
int row = idx / feature_w;
|
||||
int col = idx % feature_w;
|
||||
std::vector<float> bbox_pred(
|
||||
outs[i + this->fpn_stride_.size()].begin() + idx * 4 * reg_max,
|
||||
outs[i + this->fpn_stride_.size()].begin() +
|
||||
(idx + 1) * 4 * reg_max);
|
||||
bbox_results[cur_label].push_back(
|
||||
this->disPred2Bbox(bbox_pred, cur_label, score, col, row,
|
||||
this->fpn_stride_[i], resize_shape, reg_max));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < bbox_results.size(); i++) {
|
||||
bool flag = bbox_results[i].size() <= 0;
|
||||
}
|
||||
for (int i = 0; i < bbox_results.size(); i++) {
|
||||
bool flag = bbox_results[i].size() <= 0;
|
||||
if (bbox_results[i].size() <= 0) {
|
||||
continue;
|
||||
}
|
||||
this->nms(bbox_results[i], this->nms_threshold_);
|
||||
for (auto box : bbox_results[i]) {
|
||||
box.box[0] = box.box[0] / scale_factor_w;
|
||||
box.box[2] = box.box[2] / scale_factor_w;
|
||||
box.box[1] = box.box[1] / scale_factor_h;
|
||||
box.box[3] = box.box[3] / scale_factor_h;
|
||||
results.push_back(box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StructurePredictResult
|
||||
PicodetPostProcessor::disPred2Bbox(std::vector<float> bbox_pred, int label,
|
||||
float score, int x, int y, int stride,
|
||||
std::vector<int> im_shape, int reg_max) {
|
||||
float ct_x = (x + 0.5) * stride;
|
||||
float ct_y = (y + 0.5) * stride;
|
||||
std::vector<float> dis_pred;
|
||||
dis_pred.resize(4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float dis = 0;
|
||||
std::vector<float> bbox_pred_i(bbox_pred.begin() + i * reg_max,
|
||||
bbox_pred.begin() + (i + 1) * reg_max);
|
||||
std::vector<float> dis_after_sm =
|
||||
Utility::activation_function_softmax(bbox_pred_i);
|
||||
for (int j = 0; j < reg_max; j++) {
|
||||
dis += j * dis_after_sm[j];
|
||||
}
|
||||
dis *= stride;
|
||||
dis_pred[i] = dis;
|
||||
}
|
||||
|
||||
float xmin = (std::max)(ct_x - dis_pred[0], .0f);
|
||||
float ymin = (std::max)(ct_y - dis_pred[1], .0f);
|
||||
float xmax = (std::min)(ct_x + dis_pred[2], (float)im_shape[1]);
|
||||
float ymax = (std::min)(ct_y + dis_pred[3], (float)im_shape[0]);
|
||||
|
||||
StructurePredictResult result_item;
|
||||
result_item.box = { xmin, ymin, xmax, ymax };
|
||||
result_item.type = this->label_list_[label];
|
||||
result_item.confidence = score;
|
||||
|
||||
return result_item;
|
||||
}
|
||||
|
||||
void PicodetPostProcessor::nms(std::vector<StructurePredictResult>& input_boxes,
|
||||
float nms_threshold) {
|
||||
std::sort(input_boxes.begin(), input_boxes.end(),
|
||||
[](StructurePredictResult a, StructurePredictResult b) {
|
||||
return a.confidence > b.confidence;
|
||||
});
|
||||
std::vector<int> picked(input_boxes.size(), 1);
|
||||
|
||||
for (int i = 0; i < input_boxes.size(); ++i) {
|
||||
if (picked[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
for (int j = i + 1; j < input_boxes.size(); ++j) {
|
||||
if (picked[j] == 0) {
|
||||
continue;
|
||||
}
|
||||
float iou = Utility::iou(input_boxes[i].box, input_boxes[j].box);
|
||||
if (iou > nms_threshold) {
|
||||
picked[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<StructurePredictResult> input_boxes_nms;
|
||||
for (int i = 0; i < input_boxes.size(); ++i) {
|
||||
if (picked[i] == 1) {
|
||||
input_boxes_nms.push_back(input_boxes[i]);
|
||||
}
|
||||
}
|
||||
input_boxes = input_boxes_nms;
|
||||
}
|
||||
|
||||
} // namespace PaddleOCR
|
||||
165
ANSOCR/ANSPaddleOCR/src/preprocess_op.cpp
Normal file
165
ANSOCR/ANSPaddleOCR/src/preprocess_op.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
// 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/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 PermuteBatch::Run(const std::vector<cv::Mat> imgs, float* data) {
|
||||
for (int j = 0; j < imgs.size(); j++) {
|
||||
int rh = imgs[j].rows;
|
||||
int rw = imgs[j].cols;
|
||||
int rc = imgs[j].channels();
|
||||
for (int i = 0; i < rc; ++i) {
|
||||
cv::extractChannel(
|
||||
imgs[j], cv::Mat(rh, rw, CV_32FC1, data + (j * rc + 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);
|
||||
std::vector<cv::Mat> bgr_channels(3);
|
||||
cv::split(*im, bgr_channels);
|
||||
for (auto i = 0; i < bgr_channels.size(); i++) {
|
||||
bgr_channels[i].convertTo(bgr_channels[i], CV_32FC1, 1.0 * scale[i],
|
||||
(0.0 - mean[i]) * scale[i]);
|
||||
}
|
||||
cv::merge(bgr_channels, *im);
|
||||
}
|
||||
|
||||
void ResizeImgType0::Run(const cv::Mat& img, cv::Mat& resize_img,
|
||||
std::string limit_type, int limit_side_len,
|
||||
float& ratio_h, float& ratio_w) {
|
||||
int w = img.cols;
|
||||
int h = img.rows;
|
||||
float ratio = 1.f;
|
||||
if (limit_type == "min") {
|
||||
int min_wh = std::min(h, w);
|
||||
if (min_wh < limit_side_len) {
|
||||
if (h < w) {
|
||||
ratio = float(limit_side_len) / float(h);
|
||||
}
|
||||
else {
|
||||
ratio = float(limit_side_len) / float(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
int max_wh = std::max(h, w);
|
||||
if (max_wh > limit_side_len) {
|
||||
if (h > w) {
|
||||
ratio = float(limit_side_len) / float(h);
|
||||
}
|
||||
else {
|
||||
ratio = float(limit_side_len) / float(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int resize_h = int(float(h) * ratio);
|
||||
int resize_w = int(float(w) * ratio);
|
||||
|
||||
resize_h = std::max(int(round(float(resize_h) / 32) * 32), 32);
|
||||
resize_w = std::max(int(round(float(resize_w) / 32) * 32), 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(imgH * 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);
|
||||
cv::copyMakeBorder(resize_img, resize_img, 0, 0, 0,
|
||||
int(imgW - resize_img.cols), cv::BORDER_CONSTANT,
|
||||
{ 127, 127, 127 });
|
||||
}
|
||||
|
||||
void ClsResizeImg::Run(const cv::Mat& img, cv::Mat& resize_img,
|
||||
const std::vector<size_t>& rec_image_shape) {
|
||||
int imgC, imgH, imgW;
|
||||
imgC = rec_image_shape[0];
|
||||
imgH = rec_image_shape[1];
|
||||
imgW = rec_image_shape[2];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void TableResizeImg::Run(const cv::Mat& img, cv::Mat& resize_img,
|
||||
const int max_len) {
|
||||
int w = img.cols;
|
||||
int h = img.rows;
|
||||
|
||||
int max_wh = w >= h ? w : h;
|
||||
float ratio = w >= h ? float(max_len) / float(w) : float(max_len) / float(h);
|
||||
|
||||
int resize_h = int(float(h) * ratio);
|
||||
int resize_w = int(float(w) * ratio);
|
||||
|
||||
cv::resize(img, resize_img, cv::Size(resize_w, resize_h));
|
||||
}
|
||||
|
||||
void TablePadImg::Run(const cv::Mat& img, cv::Mat& resize_img,
|
||||
const int max_len) {
|
||||
int w = img.cols;
|
||||
int h = img.rows;
|
||||
cv::copyMakeBorder(img, resize_img, 0, max_len - h, 0, max_len - w,
|
||||
cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));
|
||||
}
|
||||
|
||||
void Resize::Run(const cv::Mat& img, cv::Mat& resize_img, const int h,
|
||||
const int w) {
|
||||
cv::resize(img, resize_img, cv::Size(w, h));
|
||||
}
|
||||
|
||||
} // namespace PaddleOCR
|
||||
172
ANSOCR/ANSPaddleOCR/src/rec.bak
Normal file
172
ANSOCR/ANSPaddleOCR/src/rec.bak
Normal file
@@ -0,0 +1,172 @@
|
||||
#include "include/rec.h"
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
Rec::Rec() {}
|
||||
|
||||
Rec::~Rec() {}
|
||||
|
||||
bool Rec::init(string model_path, const string &label_path)
|
||||
{
|
||||
this->model_path = model_path;
|
||||
this->model = this->core.read_model(this->model_path);
|
||||
// -------- Step 3. Preprocessing API--------
|
||||
ov::preprocess::PrePostProcessor prep(this->model);
|
||||
// Declare section of desired application's input format
|
||||
prep.input().tensor()
|
||||
.set_layout("NHWC")
|
||||
.set_color_format(ov::preprocess::ColorFormat::BGR);
|
||||
// Specify actual model layout
|
||||
prep.input().model()
|
||||
.set_layout("NCHW");
|
||||
prep.input().preprocess()
|
||||
.mean({0.5f, 0.5f, 0.5f})
|
||||
.scale({0.5f, 0.5f, 0.5f});
|
||||
// Dump preprocessor
|
||||
std::cout << "Preprocessor: " << prep << std::endl;
|
||||
this->model = prep.build();
|
||||
this->label_list_ = Utility::ReadDict(label_path);
|
||||
this->label_list_.insert(this->label_list_.begin(),
|
||||
"#"); // blank char for ctc
|
||||
this->label_list_.push_back(" ");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rec::run(std::vector<cv::Mat> img_list, std::vector<OCRPredictResult> &ocr_results)
|
||||
{
|
||||
std::vector<std::string> rec_texts(img_list.size(), "");
|
||||
std::vector<float> rec_text_scores(img_list.size(), 0);
|
||||
|
||||
int img_num = img_list.size();
|
||||
std::vector<float> width_list;
|
||||
for (int i = 0; i < img_num; i++) {
|
||||
width_list.push_back(float(img_list[i].cols) / img_list[i].rows);
|
||||
}
|
||||
std::vector<int> indices = Utility::argsort(width_list);
|
||||
|
||||
|
||||
|
||||
for (int beg_img_no = 0; beg_img_no < img_num;
|
||||
beg_img_no += this->rec_batch_num_) {
|
||||
int end_img_no = std::min(img_num, beg_img_no + this->rec_batch_num_);
|
||||
int batch_num = end_img_no - beg_img_no;
|
||||
int imgH = this->rec_image_shape_[1];
|
||||
int imgW = this->rec_image_shape_[2];
|
||||
float max_wh_ratio = imgW * 1.0 / imgH;
|
||||
for (int ino = beg_img_no; ino < end_img_no; ino++) {
|
||||
int h = img_list[indices[ino]].rows;
|
||||
int w = img_list[indices[ino]].cols;
|
||||
float wh_ratio = w * 1.0 / h;
|
||||
max_wh_ratio = std::max(max_wh_ratio, wh_ratio);
|
||||
}
|
||||
|
||||
std::vector<cv::Mat> img_batch;
|
||||
std::vector<ov::Tensor> batch_tensors;
|
||||
|
||||
int batch_width = imgW;
|
||||
std::vector<cv::Mat> norm_img_batch;
|
||||
for (int ino = beg_img_no; ino < end_img_no; ino++) {
|
||||
cv::Mat srcimg;
|
||||
img_list[indices[ino]].copyTo(srcimg);
|
||||
cv::Mat resize_img;
|
||||
this->resize_op_.Run(srcimg, resize_img, max_wh_ratio, this->rec_image_shape_);
|
||||
double e = 1.0;
|
||||
e /= 255.0;
|
||||
resize_img.convertTo(resize_img, CV_32FC3, e);
|
||||
|
||||
norm_img_batch.push_back(resize_img);
|
||||
|
||||
// auto input_tensor = ov::Tensor(this->model->input().get_element_type(), {1, imgH, resize_img.cols, 3});
|
||||
// auto input_data = input_tensor.data<float>();
|
||||
// input_data = (float*)resize_img.data;
|
||||
// batch_tensors.push_back(input_tensor);
|
||||
batch_width = max(resize_img.cols, batch_width);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// for (int batch = 0; batch < batch_num; batch++)
|
||||
// {
|
||||
// for (int h = 0; h < imgH; h++)
|
||||
// {
|
||||
// for (int w = 0; w < batch_width; w++)
|
||||
// {
|
||||
// for (int c = 0; c < 3; c++)
|
||||
// {
|
||||
// int index = c + 3*w + 3*batch_width*h + 3*batch_width*imgH*batch;
|
||||
// data[index] = float(norm_img_batch[batch].at<Vec3b>(h, w)[c]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
this->model->reshape({batch_num, imgH, batch_width,3});
|
||||
// float data[batch_num * 3 * imgH * batch_width];
|
||||
|
||||
|
||||
|
||||
this->rec_model = this->core.compile_model(this->model, "CPU");
|
||||
this->infer_request = this->rec_model.create_infer_request();
|
||||
auto input_port = this->rec_model.input();
|
||||
ov::Tensor input_tensor = this->infer_request.get_input_tensor();
|
||||
|
||||
const size_t batch_size = norm_img_batch.size();
|
||||
|
||||
for (size_t image_id = 0; image_id < norm_img_batch.size(); ++image_id) {
|
||||
const size_t image_size = ov::shape_size(this->model->input().get_shape()) / batch_size;
|
||||
std::memcpy(input_tensor.data<float>() + image_id * image_size, (float*)norm_img_batch[image_id].data, image_size*sizeof(float));
|
||||
}
|
||||
// ov::Tensor input_tensor(input_port.get_element_type(), input_port.get_shape(), data);
|
||||
// this->infer_request.set_input_tensor(input_tensor);
|
||||
// -------- Step 7. Start inference --------
|
||||
this->infer_request.infer();
|
||||
|
||||
auto output = this->infer_request.get_output_tensor();
|
||||
const float *out_data = output.data<const float>();
|
||||
|
||||
auto predict_shape = output.get_shape();
|
||||
|
||||
|
||||
// predict_batch is the result of Last FC with softmax
|
||||
for (int m = 0; m < predict_shape[0]; m++) {
|
||||
std::string str_res;
|
||||
int argmax_idx;
|
||||
int last_index = 0;
|
||||
float score = 0.f;
|
||||
int count = 0;
|
||||
float max_value = 0.0f;
|
||||
|
||||
for (int n = 0; n < predict_shape[1]; n++) {
|
||||
// get idx
|
||||
argmax_idx = int(Utility::argmax(
|
||||
&out_data[(m * predict_shape[1] + n) * predict_shape[2]],
|
||||
&out_data[(m * predict_shape[1] + n + 1) * predict_shape[2]]));
|
||||
// get score
|
||||
max_value = float(*std::max_element(
|
||||
&out_data[(m * predict_shape[1] + n) * predict_shape[2]],
|
||||
&out_data[(m * predict_shape[1] + n + 1) * predict_shape[2]]));
|
||||
|
||||
if (argmax_idx > 0 && (!(n > 0 && argmax_idx == last_index))) {
|
||||
score += max_value;
|
||||
count += 1;
|
||||
str_res += this->label_list_[argmax_idx];
|
||||
}
|
||||
last_index = argmax_idx;
|
||||
}
|
||||
score /= count;
|
||||
if (std::isnan(score)) {
|
||||
continue;
|
||||
}
|
||||
rec_texts[indices[beg_img_no + m]] = str_res;
|
||||
rec_text_scores[indices[beg_img_no + m]] = score;
|
||||
}
|
||||
}
|
||||
// sort boex from top to bottom, from left to right
|
||||
for (int i = 0; i < rec_texts.size(); i++) {
|
||||
ocr_results[i].text = rec_texts[i];
|
||||
ocr_results[i].score = rec_text_scores[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
69
ANSOCR/ANSPaddleOCR/src/structure_layout.cpp
Normal file
69
ANSOCR/ANSPaddleOCR/src/structure_layout.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "include/structure_layout.h"
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
Layout::Layout(std::string model_path, std::string layout_dict_path) {
|
||||
ov::Core core;
|
||||
this->model_path = model_path;
|
||||
this->model = core.read_model(this->model_path);
|
||||
this->model->reshape({ 1, 3, this->layout_img_h_, this->layout_img_w_ });
|
||||
|
||||
// preprocessing API
|
||||
ov::preprocess::PrePostProcessor prep(this->model);
|
||||
// declare section of desired application's input format
|
||||
prep.input().tensor().set_layout("NHWC").set_color_format(ov::preprocess::ColorFormat::BGR);
|
||||
// specify actual model layout
|
||||
prep.input().model().set_layout("NCHW");
|
||||
prep.input().preprocess().mean(this->mean_).scale(this->scale_);
|
||||
// dump preprocessor
|
||||
std::cout << "Preprocessor: " << prep << std::endl;
|
||||
this->model = prep.build();
|
||||
this->compiled_model = core.compile_model(this->model, "CPU");
|
||||
this->infer_request = this->compiled_model.create_infer_request();
|
||||
|
||||
this->post_processor_.init(layout_dict_path, this->layout_score_threshold,
|
||||
this->layout_nms_threshold);
|
||||
}
|
||||
|
||||
void Layout::Run(cv::Mat& src_img, std::vector<StructurePredictResult>& structure_result) {
|
||||
this->src_img = src_img;
|
||||
this->resize_op_.Run(this->src_img, this->resize_img, this->layout_img_h_, this->layout_img_w_);
|
||||
std::vector<std::vector<std::vector<int>>> boxes;
|
||||
auto input_port = this->compiled_model.input();
|
||||
|
||||
// -------- set input --------
|
||||
this->resize_img.convertTo(this->resize_img, CV_32FC3, e);
|
||||
ov::Tensor input_tensor(input_port.get_element_type(), input_port.get_shape(), (float*)this->resize_img.data);
|
||||
this->infer_request.set_input_tensor(input_tensor);
|
||||
// -------- start inference --------
|
||||
this->infer_request.infer();
|
||||
|
||||
std::vector<std::vector<float>> out_tensor_list;
|
||||
std::vector<ov::Shape> output_shape_list;
|
||||
for (int j = 0; j < (this->model->outputs()).size(); j++) {
|
||||
auto output = this->infer_request.get_output_tensor(j);
|
||||
auto output_shape = output.get_shape();
|
||||
int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 1,
|
||||
std::multiplies<int>());
|
||||
output_shape_list.push_back(output_shape);
|
||||
|
||||
const float* out_data = output.data<const float>();
|
||||
std::vector<float> out_tensor(out_data, out_data + out_num);
|
||||
out_tensor_list.push_back(out_tensor);
|
||||
}
|
||||
|
||||
std::vector<int> bbox_num;
|
||||
int reg_max = 0;
|
||||
for (int i = 0; i < out_tensor_list.size(); i++) {
|
||||
if (i == this->post_processor_.fpn_stride_.size()) {
|
||||
reg_max = output_shape_list[i][2] / 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::vector<int> ori_shape = { this->src_img.rows, this->src_img.cols };
|
||||
std::vector<int> resize_shape = { this->resize_img.rows, this->resize_img.cols };
|
||||
this->post_processor_.Run(structure_result, out_tensor_list, ori_shape, resize_shape,
|
||||
reg_max);
|
||||
bbox_num.push_back(structure_result.size());
|
||||
}
|
||||
}
|
||||
96
ANSOCR/ANSPaddleOCR/src/structure_table.cpp
Normal file
96
ANSOCR/ANSPaddleOCR/src/structure_table.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "include/structure_table.h"
|
||||
|
||||
namespace PaddleOCR {
|
||||
|
||||
Table::Table(std::string model_path, const std::string table_char_dict_path) {
|
||||
ov::Core core;
|
||||
this->model_path = model_path;
|
||||
this->model = core.read_model(this->model_path);
|
||||
// reshape the model for dynamic batch size and sentence width
|
||||
this->model->reshape({ {ov::Dimension(1, this->table_batch_num_), 3, this->table_max_len_, this->table_max_len_} });
|
||||
this->compiled_model = core.compile_model(this->model, "CPU");
|
||||
this->infer_request = this->compiled_model.create_infer_request();
|
||||
this->post_processor_.init(table_char_dict_path, false);
|
||||
}
|
||||
|
||||
void Table::Run(std::vector<cv::Mat> img_list,
|
||||
std::vector<std::vector<std::string>>& structure_html_tags,
|
||||
std::vector<float>& structure_scores,
|
||||
std::vector<std::vector<std::vector<int>>>& structure_boxes) {
|
||||
int img_num = img_list.size();
|
||||
for (int beg_img_no = 0; beg_img_no < img_num;
|
||||
beg_img_no += this->table_batch_num_) {
|
||||
// preprocess
|
||||
auto preprocess_start = std::chrono::steady_clock::now();
|
||||
int end_img_no = std::min(img_num, beg_img_no + this->table_batch_num_);
|
||||
size_t batch_num = end_img_no - beg_img_no;
|
||||
std::vector<cv::Mat> norm_img_batch;
|
||||
std::vector<int> width_list;
|
||||
std::vector<int> height_list;
|
||||
for (int ino = beg_img_no; ino < end_img_no; ino++) {
|
||||
cv::Mat srcimg;
|
||||
img_list[ino].copyTo(srcimg);
|
||||
cv::Mat resize_img;
|
||||
cv::Mat pad_img;
|
||||
this->resize_op_.Run(srcimg, resize_img, this->table_max_len_);
|
||||
this->normalize_op_.Run(&resize_img, this->mean_, this->scale_,
|
||||
this->is_scale_);
|
||||
this->pad_op_.Run(resize_img, pad_img, this->table_max_len_);
|
||||
norm_img_batch.push_back(pad_img);
|
||||
width_list.push_back(srcimg.cols);
|
||||
height_list.push_back(srcimg.rows);
|
||||
}
|
||||
|
||||
size_t tableMaxLen = this->table_max_len_;
|
||||
|
||||
std::vector<float> input(batch_num * 3 * this->table_max_len_ * this->table_max_len_, 0.0f);
|
||||
ov::Shape intput_shape = { batch_num, 3, tableMaxLen, tableMaxLen };
|
||||
this->permute_op_.Run(norm_img_batch, input.data());
|
||||
// inference.
|
||||
auto input_port = this->compiled_model.input();
|
||||
ov::Tensor input_tensor(input_port.get_element_type(), intput_shape, input.data());
|
||||
this->infer_request.set_input_tensor(input_tensor);
|
||||
// start inference
|
||||
this->infer_request.infer();
|
||||
|
||||
auto output0 = this->infer_request.get_output_tensor(0);
|
||||
const float* out_data0 = output0.data<const float>();
|
||||
auto predict_shape0 = output0.get_shape();
|
||||
auto output1 = this->infer_request.get_output_tensor(1);
|
||||
const float* out_data1 = output1.data<const float>();
|
||||
auto predict_shape1 = output1.get_shape();
|
||||
|
||||
int out_num0 = std::accumulate(predict_shape0.begin(), predict_shape0.end(),
|
||||
1, std::multiplies<int>());
|
||||
int out_num1 = std::accumulate(predict_shape1.begin(), predict_shape1.end(),
|
||||
1, std::multiplies<int>());
|
||||
|
||||
std::vector<float> loc_preds(out_data0, out_data0 + out_num0);
|
||||
std::vector<float> structure_probs(out_data1, out_data1 + out_num1);
|
||||
|
||||
// postprocess
|
||||
std::vector<std::vector<std::string>> structure_html_tag_batch;
|
||||
std::vector<float> structure_score_batch;
|
||||
std::vector<std::vector<std::vector<int>>> structure_boxes_batch;
|
||||
this->post_processor_.Run(loc_preds, structure_probs, structure_score_batch,
|
||||
predict_shape0, predict_shape1,
|
||||
structure_html_tag_batch, structure_boxes_batch,
|
||||
width_list, height_list);
|
||||
for (int m = 0; m < predict_shape0[0]; m++) {
|
||||
|
||||
structure_html_tag_batch[m].insert(structure_html_tag_batch[m].begin(),
|
||||
"<table>");
|
||||
structure_html_tag_batch[m].insert(structure_html_tag_batch[m].begin(),
|
||||
"<body>");
|
||||
structure_html_tag_batch[m].insert(structure_html_tag_batch[m].begin(),
|
||||
"<html>");
|
||||
structure_html_tag_batch[m].push_back("</table>");
|
||||
structure_html_tag_batch[m].push_back("</body>");
|
||||
structure_html_tag_batch[m].push_back("</html>");
|
||||
structure_html_tags.push_back(structure_html_tag_batch[m]);
|
||||
structure_scores.push_back(structure_score_batch[m]);
|
||||
structure_boxes.push_back(structure_boxes_batch[m]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user