docs: Update README and compilation guides for clarity and consistency, including path corrections and improved formatting. Add copyright notices to source files and adjust file permissions for several scripts and directories.

This commit is contained in:
dian.yuan 2026-02-28 11:06:26 +08:00
parent f960c5030d
commit bd891a96dd
136 changed files with 14413 additions and 9399 deletions

0
examples/ppocr-det/cpp/.gitkeep Normal file → Executable file
View file

View file

@ -1,38 +1,38 @@
cmake_minimum_required(VERSION 3.10...3.27)
project(yolo_world_demo)
set(CMAKE_CXX_STANDARD 17)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../../../cmake")
find_package(AMLNN REQUIRED)
include_directories(${AMLNN_INCLUDE_DIR})
link_directories(${AMLNN_LIBRARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/../../../../common)
# Set 3rdparty path
set(3RDPARTY_DIR "${CMAKE_SOURCE_DIR}/../../../../dependency")
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
# Android needs log
link_libraries(log)
endif()
# Find OpenCV
message(STATUS "OpenCV_DIR: ${OpenCV_DIR}")
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(paddleocr_det_demo
main.cpp
postprocess.cpp
postprocess.h
clipper.cpp
clipper.h
${CMAKE_SOURCE_DIR}/../../../../common/model_loader.cpp
)
target_link_libraries(paddleocr_det_demo
${OpenCV_LIBS}
${AMLNN_LIBRARY}
)
cmake_minimum_required(VERSION 3.10...3.27)
project(yolo_world_demo)
set(CMAKE_CXX_STANDARD 17)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../../../cmake")
find_package(AMLNN REQUIRED)
include_directories(${AMLNN_INCLUDE_DIR})
link_directories(${AMLNN_LIBRARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/../../../../common)
# Set 3rdparty path
set(3RDPARTY_DIR "${CMAKE_SOURCE_DIR}/../../../../dependency")
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
# Android needs log
link_libraries(log)
endif()
# Find OpenCV
message(STATUS "OpenCV_DIR: ${OpenCV_DIR}")
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(paddleocr_det_demo
main.cpp
postprocess.cpp
postprocess.h
clipper.cpp
clipper.h
${CMAKE_SOURCE_DIR}/../../../../common/model_loader.cpp
)
target_link_libraries(paddleocr_det_demo
${OpenCV_LIBS}
${AMLNN_LIBRARY}
)

File diff suppressed because it is too large Load diff

View file

@ -1,425 +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 performance.
//#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 Children;
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.Children
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
/*******************************************************************************
* *
* 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 performance.
//#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 Children;
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.Children
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

View file

@ -1,91 +1,91 @@
/*
* Copyright (C) 20242025 Amlogic, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include <chrono>
#include "nn_sdk.h"
#include "model_loader.h"
#include "postprocess.h"
const std::string DEFAULT_OUTPUT_PATH = "result.png";
int main(int argc, char** argv) {
if (argc < 3) {
printf("Usage: %s <model_path> <image_path> [output_path]\n", argv[0]);
return -1;
}
std::string model_path = argv[1];
std::string image_path = argv[2];
std::string output_path = (argc > 3) ? argv[3] : DEFAULT_OUTPUT_PATH;
printf("Model: %s\n", model_path.c_str());
printf("Image: %s\n", image_path.c_str());
// 1. Initialize Network
void* ctx = init_network(model_path.c_str());
if (!ctx) {
fprintf(stderr, "Failed to initialize network\n");
return -1;
}
// 2. Load Image
cv::Mat img = cv::imread(image_path);
if (img.empty()) {
fprintf(stderr, "Failed to load image: %s\n", image_path.c_str());
uninit_network(ctx);
return -1;
}
// 3. Preprocess
auto start_time = std::chrono::high_resolution_clock::now();
cv::Mat pre_image;
float scale = 1.0f;
preprocess(img, pre_image, MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT, scale);
printf("scale: %f\n", scale);
// 4. Inference
nn_output* outdata = (nn_output*)run_paddleocr_network(ctx, pre_image, MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT, MODEL_INPUT_CHANNELS);
if (!outdata) {
fprintf(stderr, "Inference failed\n");
uninit_network(ctx);
return -1;
}
// 5. Postprocess
float* out0 = (float*)outdata->out[0].buf;
std::vector<Object> results;
postprocess(out0, img, BOX_SCORE_THRESH, BOX_THRESH, results, scale);
auto end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> inference_time = end_time - start_time;
printf("Inference + Postprocess time: %.2f ms\n", inference_time.count());
printf("Results: %zu\n", results.size());
// 6. Draw and Save
cv::Mat res = draw_objects(img, results);
cv::imwrite(output_path, res);
printf("Saved result to %s\n", output_path.c_str());
// 7. Cleanup
uninit_network(ctx);
return 0;
}
/*
* Copyright (C) 20242025 Amlogic, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include <chrono>
#include "nn_sdk.h"
#include "model_loader.h"
#include "postprocess.h"
const std::string DEFAULT_OUTPUT_PATH = "result.png";
int main(int argc, char** argv) {
if (argc < 3) {
printf("Usage: %s <model_path> <image_path> [output_path]\n", argv[0]);
return -1;
}
std::string model_path = argv[1];
std::string image_path = argv[2];
std::string output_path = (argc > 3) ? argv[3] : DEFAULT_OUTPUT_PATH;
printf("Model: %s\n", model_path.c_str());
printf("Image: %s\n", image_path.c_str());
// 1. Initialize Network
void* ctx = init_network(model_path.c_str());
if (!ctx) {
fprintf(stderr, "Failed to initialize network\n");
return -1;
}
// 2. Load Image
cv::Mat img = cv::imread(image_path);
if (img.empty()) {
fprintf(stderr, "Failed to load image: %s\n", image_path.c_str());
uninit_network(ctx);
return -1;
}
// 3. Preprocess
auto start_time = std::chrono::high_resolution_clock::now();
cv::Mat pre_image;
float scale = 1.0f;
preprocess(img, pre_image, MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT, scale);
printf("scale: %f\n", scale);
// 4. Inference
nn_output* outdata = (nn_output*)run_paddleocr_network(ctx, pre_image, MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT, MODEL_INPUT_CHANNELS);
if (!outdata) {
fprintf(stderr, "Inference failed\n");
uninit_network(ctx);
return -1;
}
// 5. Postprocess
float* out0 = (float*)outdata->out[0].buf;
std::vector<Object> results;
postprocess(out0, img, BOX_SCORE_THRESH, BOX_THRESH, results, scale);
auto end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> inference_time = end_time - start_time;
printf("Inference + Postprocess time: %.2f ms\n", inference_time.count());
printf("Results: %zu\n", results.size());
// 6. Draw and Save
cv::Mat res = draw_objects(img, results);
cv::imwrite(output_path, res);
printf("Saved result to %s\n", output_path.c_str());
// 7. Cleanup
uninit_network(ctx);
return 0;
}

View file

@ -1,272 +1,272 @@
/*
* Copyright (C) 20242025 Amlogic, Inc. 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 "postprocess.h"
#include "clipper.h"
#include <algorithm>
#include <limits>
#include <cstdint>
int preprocess(const cv::Mat& image, cv::Mat& pre_image, const int width, const int height, float& scale ) {
if (image.empty() || width <= 0 || height <= 0)
return -1;
int w = image.cols;
int h = image.rows;
float width_ratio = (float) image.cols / width;
float height_ratio = (float) image.rows / height;
float ratio_max = std::max(width_ratio, height_ratio);
int new_w = std::min(int(image.cols / ratio_max), w);
int new_h = std::min(int(image.rows / ratio_max), h);
cv::Mat resized_img;
cv::resize(image, resized_img, cv::Size(new_w, new_h));
pre_image = cv::Mat::zeros(height, width, CV_8UC3);
cv::Rect roi_rect = cv::Rect(0, 0, new_w, new_h);
resized_img.copyTo(pre_image(roi_rect));
scale = ratio_max;
return 0;
}
int postprocess(float* out, const cv::Mat& image, float box_score_thresh, float box_thresh, std::vector<Object>& result, float scale) {
if (out == NULL)
return -1;
cv::Mat pred_map(MODEL_INPUT_HEIGHT, MODEL_INPUT_WIDTH, CV_32FC1, out);
cv::Mat bit_map;
bit_map = pred_map > box_thresh;
cv::Mat dila_ele =
cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::dilate(bit_map, bit_map, dila_ele, cv::Point(-1, -1), 1);
result = find_box(pred_map, bit_map, box_score_thresh, 1.5f, image, scale);
return 0;
}
void* run_paddleocr_network(void* qcontext, cv::Mat& image, const int width, const int height, const int channel) {
unsigned char* rawdata = image.data;
nn_input inData;
memset(&inData, 0, sizeof(nn_input));
inData.input_type = BINARY_RAW_DATA;
inData.input = rawdata;
inData.input_index = 0;
inData.size = width * height * channel * sizeof(uint8_t);
int ret = aml_module_input_set(qcontext, &inData);
if (ret) {
printf("aml_module_input_set fail for index %d. Ret=%d", 0, ret);
return NULL;
}
aml_output_config_t outconfig;
memset(&outconfig, 0, sizeof(aml_output_config_t));
outconfig.typeSize = sizeof(aml_output_config_t);
outconfig.format = AML_OUTDATA_FLOAT32;
return aml_module_output_get(qcontext, outconfig);
}
std::vector<Object> find_box(const cv::Mat pred_map, const cv::Mat& bit_map,
const float box_score_thresh, const float unclip_ratio,
const cv::Mat& image, float scale) {
std::vector<Object> res_boxes;
res_boxes.clear();
std::vector<std::vector<cv::Point>> contours;
cv::findContours(bit_map, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
int num_coutours = contours.size() >= MAX_CANDIDATES ? MAX_CANDIDATES : contours.size();
for (int i = 0; i < num_coutours; i++) {
if (contours[i].size() <= 2) {
continue;
}
float min_side_len;
float perimeter;
Object text_box;
std::vector<cv::Point> min_box = get_min_boxes(contours[i], min_side_len, perimeter);
if (min_side_len < MIN_SIZE)
continue;
// score
float score = get_box_score_fast(pred_map, contours[i]);
if (score < box_score_thresh)
continue;
//--- use clipper
std::vector<cv::Point> clip_box = unclip(min_box, perimeter, unclip_ratio);
std::vector<cv::Point> clip_min_box = get_min_boxes(clip_box, min_side_len, perimeter);
if (min_side_len < MIN_SIZE + 2)
continue;
for (int j = 0; j < clip_min_box.size(); ++j) {
clip_min_box[j].x = (float)(clip_min_box[j].x / 1.0f);
clip_min_box[j].x = std::min(std::max(int(clip_min_box[j].x * scale), 0), image.cols);
clip_min_box[j].y = (float)(clip_min_box[j].y / 1.0f);
clip_min_box[j].y = std::min(std::max(int(clip_min_box[j].y * scale), 0), image.rows);
text_box.box.push_back(clip_min_box[j]);
}
text_box.score = score;
// printf("text detect:%f \n", score);
res_boxes.push_back(text_box);
}
return res_boxes;
}
std::vector<cv::Point> get_min_boxes(const std::vector<cv::Point>& in_vec, float& min_side_len, float& perimeter) {
std::vector<cv::Point> min_box_vec;
cv::RotatedRect text_rect = cv::minAreaRect(in_vec);
cv::Mat box_point2f;
cv::boxPoints(text_rect, box_point2f);
float* p1 = (float*) box_point2f.data;
std::vector<cv::Point> temp_vec;
for (int i = 0; i < 4; ++i, p1 += 2) {
temp_vec.emplace_back(int(p1[0]), int(p1[1]));
}
std::sort(temp_vec.begin(), temp_vec.end(), cv_point_compare);
int index1, index2, index3, index4;
if (temp_vec[1].y > temp_vec[0].y) {
index1 = 0;
index4 = 1;
}
else {
index1 = 1;
index4 = 0;
}
if (temp_vec[3].y > temp_vec[2].y) {
index2 = 2;
index3 = 3;
}
else {
index2 = 3;
index3 = 2;
}
min_box_vec.clear();
min_box_vec.push_back(temp_vec[index1]);
min_box_vec.push_back(temp_vec[index2]);
min_box_vec.push_back(temp_vec[index3]);
min_box_vec.push_back(temp_vec[index4]);
min_side_len = std::min(text_rect.size.width, text_rect.size.height);
perimeter = 2.f * (text_rect.size.width + text_rect.size.height);
return min_box_vec;
}
float get_box_score_fast(const cv::Mat& in_mat, const std::vector<cv::Point>& in_box) {
std::vector<cv::Point> box = in_box;
int width = in_mat.cols;
int height = in_mat.rows;
int max_x = -1;
int max_y = -1;
int min_x = std::numeric_limits<int>::max();
int min_y = std::numeric_limits<int>::max();
for (int i = 0; i < box.size(); ++i) {
if (max_x < box[i].x)
max_x = box[i].x;
if (max_y < box[i].y)
max_y = box[i].y;
if (min_x > box[i].x)
min_x = box[i].x;
if (min_y > box[i].y)
min_y = box[i].y;
}
max_x = std::min(std::max(max_x, 0), width - 1);
max_y = std::min(std::max(max_y, 0), height - 1);
min_x = std::max(std::min(min_x, width - 1), 0);
min_y = std::max(std::min(min_y, height - 1), 0);
for (int i = 0; i < box.size(); ++i) {
box[i].x = box[i].x - min_x;
box[i].y = box[i].y - min_y;
}
std::vector<std::vector<cv::Point>> mask_box;
mask_box.push_back(box);
cv::Mat mask_mat(max_y - min_y + 1, max_x - min_x + 1, CV_8UC1, cv::Scalar(0, 0, 0));
cv::fillPoly(mask_mat, mask_box, cv::Scalar(1, 1, 1), 1);
return cv::mean(in_mat(cv::Rect(cv::Point(min_x, min_y), cv::Point(max_x + 1, max_y + 1))).clone(), mask_mat).val[0];
}
std::vector<cv::Point> unclip(const std::vector<cv::Point>& in_box, float perimeter, float unclip_ratio) {
std::vector<cv::Point> out_box;
ClipperLib::Path poly;
for (int i = 0; i < in_box.size(); ++i) {
poly.push_back(ClipperLib::IntPoint(in_box[i].x, in_box[i].y));
}
double distance = unclip_ratio * ClipperLib::Area(poly) / (double) perimeter;
ClipperLib::ClipperOffset clipper_offset;
clipper_offset.AddPath(poly, ClipperLib::JoinType::jtRound, ClipperLib::EndType::etClosedPolygon);
ClipperLib::Paths polys;
polys.push_back(poly);
clipper_offset.Execute(polys, distance);
out_box.clear();
for (int i = 0; i < polys.size(); ++i) {
ClipperLib::Path temp_poly = polys[i];
for (int j = 0; j < temp_poly.size(); ++j) {
out_box.emplace_back(temp_poly[j].X, temp_poly[j].Y);
}
}
return out_box;
}
bool cv_point_compare(const cv::Point& a, const cv::Point& b) {
return a.x < b.x;
}
cv::Mat draw_objects(cv::Mat image, const std::vector<Object>& results) {
for (int i = 0; i < results.size(); i++) {
cv::polylines(image, results[i].box, true, cv::Scalar(0, 0, 255), 2);
}
return image;
/*
* Copyright (C) 20242025 Amlogic, Inc. 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 "postprocess.h"
#include "clipper.h"
#include <algorithm>
#include <limits>
#include <cstdint>
int preprocess(const cv::Mat& image, cv::Mat& pre_image, const int width, const int height, float& scale ) {
if (image.empty() || width <= 0 || height <= 0)
return -1;
int w = image.cols;
int h = image.rows;
float width_ratio = (float) image.cols / width;
float height_ratio = (float) image.rows / height;
float ratio_max = std::max(width_ratio, height_ratio);
int new_w = std::min(int(image.cols / ratio_max), w);
int new_h = std::min(int(image.rows / ratio_max), h);
cv::Mat resized_img;
cv::resize(image, resized_img, cv::Size(new_w, new_h));
pre_image = cv::Mat::zeros(height, width, CV_8UC3);
cv::Rect roi_rect = cv::Rect(0, 0, new_w, new_h);
resized_img.copyTo(pre_image(roi_rect));
scale = ratio_max;
return 0;
}
int postprocess(float* out, const cv::Mat& image, float box_score_thresh, float box_thresh, std::vector<Object>& result, float scale) {
if (out == NULL)
return -1;
cv::Mat pred_map(MODEL_INPUT_HEIGHT, MODEL_INPUT_WIDTH, CV_32FC1, out);
cv::Mat bit_map;
bit_map = pred_map > box_thresh;
cv::Mat dila_ele =
cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::dilate(bit_map, bit_map, dila_ele, cv::Point(-1, -1), 1);
result = find_box(pred_map, bit_map, box_score_thresh, 1.5f, image, scale);
return 0;
}
void* run_paddleocr_network(void* qcontext, cv::Mat& image, const int width, const int height, const int channel) {
unsigned char* rawdata = image.data;
nn_input inData;
memset(&inData, 0, sizeof(nn_input));
inData.input_type = BINARY_RAW_DATA;
inData.input = rawdata;
inData.input_index = 0;
inData.size = width * height * channel * sizeof(uint8_t);
int ret = aml_module_input_set(qcontext, &inData);
if (ret) {
printf("aml_module_input_set fail for index %d. Ret=%d", 0, ret);
return NULL;
}
aml_output_config_t outconfig;
memset(&outconfig, 0, sizeof(aml_output_config_t));
outconfig.typeSize = sizeof(aml_output_config_t);
outconfig.format = AML_OUTDATA_FLOAT32;
return aml_module_output_get(qcontext, outconfig);
}
std::vector<Object> find_box(const cv::Mat pred_map, const cv::Mat& bit_map,
const float box_score_thresh, const float unclip_ratio,
const cv::Mat& image, float scale) {
std::vector<Object> res_boxes;
res_boxes.clear();
std::vector<std::vector<cv::Point>> contours;
cv::findContours(bit_map, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
int num_coutours = contours.size() >= MAX_CANDIDATES ? MAX_CANDIDATES : contours.size();
for (int i = 0; i < num_coutours; i++) {
if (contours[i].size() <= 2) {
continue;
}
float min_side_len;
float perimeter;
Object text_box;
std::vector<cv::Point> min_box = get_min_boxes(contours[i], min_side_len, perimeter);
if (min_side_len < MIN_SIZE)
continue;
// score
float score = get_box_score_fast(pred_map, contours[i]);
if (score < box_score_thresh)
continue;
//--- use clipper
std::vector<cv::Point> clip_box = unclip(min_box, perimeter, unclip_ratio);
std::vector<cv::Point> clip_min_box = get_min_boxes(clip_box, min_side_len, perimeter);
if (min_side_len < MIN_SIZE + 2)
continue;
for (int j = 0; j < clip_min_box.size(); ++j) {
clip_min_box[j].x = (float)(clip_min_box[j].x / 1.0f);
clip_min_box[j].x = std::min(std::max(int(clip_min_box[j].x * scale), 0), image.cols);
clip_min_box[j].y = (float)(clip_min_box[j].y / 1.0f);
clip_min_box[j].y = std::min(std::max(int(clip_min_box[j].y * scale), 0), image.rows);
text_box.box.push_back(clip_min_box[j]);
}
text_box.score = score;
// printf("text detect:%f \n", score);
res_boxes.push_back(text_box);
}
return res_boxes;
}
std::vector<cv::Point> get_min_boxes(const std::vector<cv::Point>& in_vec, float& min_side_len, float& perimeter) {
std::vector<cv::Point> min_box_vec;
cv::RotatedRect text_rect = cv::minAreaRect(in_vec);
cv::Mat box_point2f;
cv::boxPoints(text_rect, box_point2f);
float* p1 = (float*) box_point2f.data;
std::vector<cv::Point> temp_vec;
for (int i = 0; i < 4; ++i, p1 += 2) {
temp_vec.emplace_back(int(p1[0]), int(p1[1]));
}
std::sort(temp_vec.begin(), temp_vec.end(), cv_point_compare);
int index1, index2, index3, index4;
if (temp_vec[1].y > temp_vec[0].y) {
index1 = 0;
index4 = 1;
}
else {
index1 = 1;
index4 = 0;
}
if (temp_vec[3].y > temp_vec[2].y) {
index2 = 2;
index3 = 3;
}
else {
index2 = 3;
index3 = 2;
}
min_box_vec.clear();
min_box_vec.push_back(temp_vec[index1]);
min_box_vec.push_back(temp_vec[index2]);
min_box_vec.push_back(temp_vec[index3]);
min_box_vec.push_back(temp_vec[index4]);
min_side_len = std::min(text_rect.size.width, text_rect.size.height);
perimeter = 2.f * (text_rect.size.width + text_rect.size.height);
return min_box_vec;
}
float get_box_score_fast(const cv::Mat& in_mat, const std::vector<cv::Point>& in_box) {
std::vector<cv::Point> box = in_box;
int width = in_mat.cols;
int height = in_mat.rows;
int max_x = -1;
int max_y = -1;
int min_x = std::numeric_limits<int>::max();
int min_y = std::numeric_limits<int>::max();
for (int i = 0; i < box.size(); ++i) {
if (max_x < box[i].x)
max_x = box[i].x;
if (max_y < box[i].y)
max_y = box[i].y;
if (min_x > box[i].x)
min_x = box[i].x;
if (min_y > box[i].y)
min_y = box[i].y;
}
max_x = std::min(std::max(max_x, 0), width - 1);
max_y = std::min(std::max(max_y, 0), height - 1);
min_x = std::max(std::min(min_x, width - 1), 0);
min_y = std::max(std::min(min_y, height - 1), 0);
for (int i = 0; i < box.size(); ++i) {
box[i].x = box[i].x - min_x;
box[i].y = box[i].y - min_y;
}
std::vector<std::vector<cv::Point>> mask_box;
mask_box.push_back(box);
cv::Mat mask_mat(max_y - min_y + 1, max_x - min_x + 1, CV_8UC1, cv::Scalar(0, 0, 0));
cv::fillPoly(mask_mat, mask_box, cv::Scalar(1, 1, 1), 1);
return cv::mean(in_mat(cv::Rect(cv::Point(min_x, min_y), cv::Point(max_x + 1, max_y + 1))).clone(), mask_mat).val[0];
}
std::vector<cv::Point> unclip(const std::vector<cv::Point>& in_box, float perimeter, float unclip_ratio) {
std::vector<cv::Point> out_box;
ClipperLib::Path poly;
for (int i = 0; i < in_box.size(); ++i) {
poly.push_back(ClipperLib::IntPoint(in_box[i].x, in_box[i].y));
}
double distance = unclip_ratio * ClipperLib::Area(poly) / (double) perimeter;
ClipperLib::ClipperOffset clipper_offset;
clipper_offset.AddPath(poly, ClipperLib::JoinType::jtRound, ClipperLib::EndType::etClosedPolygon);
ClipperLib::Paths polys;
polys.push_back(poly);
clipper_offset.Execute(polys, distance);
out_box.clear();
for (int i = 0; i < polys.size(); ++i) {
ClipperLib::Path temp_poly = polys[i];
for (int j = 0; j < temp_poly.size(); ++j) {
out_box.emplace_back(temp_poly[j].X, temp_poly[j].Y);
}
}
return out_box;
}
bool cv_point_compare(const cv::Point& a, const cv::Point& b) {
return a.x < b.x;
}
cv::Mat draw_objects(cv::Mat image, const std::vector<Object>& results) {
for (int i = 0; i < results.size(); i++) {
cv::polylines(image, results[i].box, true, cv::Scalar(0, 0, 255), 2);
}
return image;
}

View file

@ -1,61 +1,61 @@
/*
* Copyright (C) 20242025 Amlogic, Inc. 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.
*/
#ifndef __AMLNN_PADDLEOCR_DET_DEMO_POSTPROCESS_H__
#define __AMLNN_PADDLEOCR_DET_DEMO_POSTPROCESS_H__
#include <opencv2/opencv.hpp>
#include <vector>
#include "nn_sdk.h"
const int MIN_SIZE = 3;
const int MAX_CANDIDATES = 1000;
const int MODEL_INPUT_WIDTH = 640;
const int MODEL_INPUT_HEIGHT = 640;
const int MODEL_INPUT_CHANNELS = 3;
const float BOX_SCORE_THRESH = 0.5;
const float BOX_THRESH = 0.3;
typedef struct {
float score;
std::vector<cv::Point> box;
} Object;
void* run_paddleocr_network(void* qcontext, cv::Mat& image, const int width, const int height, const int channel);
int preprocess(const cv::Mat& image, cv::Mat& pre_image, const int width, const int height, float& scale );
int postprocess(float* out, const cv::Mat& image, float box_score_thresh, float box_thresh, std::vector<Object>& result, float scale);
std::vector<Object> find_box(const cv::Mat pred_map, const cv::Mat& bit_map,
const float box_score_thresh, const float unclip_ratio,
const cv::Mat& image, float scale);
std::vector<cv::Point> get_min_boxes(const std::vector<cv::Point>& in_vec,
float& min_side_len, float& perimeter);
float get_box_score_fast(const cv::Mat& in_mat, const std::vector<cv::Point>& in_box);
std::vector<cv::Point> unclip(const std::vector<cv::Point>& in_box, float perimeter, float unclip_ratio);
bool cv_point_compare(const cv::Point& a, const cv::Point& b);
cv::Mat draw_objects(cv::Mat image, const std::vector<Object>& results);
/*
* Copyright (C) 20242025 Amlogic, Inc. 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.
*/
#ifndef __AMLNN_PADDLEOCR_DET_DEMO_POSTPROCESS_H__
#define __AMLNN_PADDLEOCR_DET_DEMO_POSTPROCESS_H__
#include <opencv2/opencv.hpp>
#include <vector>
#include "nn_sdk.h"
const int MIN_SIZE = 3;
const int MAX_CANDIDATES = 1000;
const int MODEL_INPUT_WIDTH = 640;
const int MODEL_INPUT_HEIGHT = 640;
const int MODEL_INPUT_CHANNELS = 3;
const float BOX_SCORE_THRESH = 0.5;
const float BOX_THRESH = 0.3;
typedef struct {
float score;
std::vector<cv::Point> box;
} Object;
void* run_paddleocr_network(void* qcontext, cv::Mat& image, const int width, const int height, const int channel);
int preprocess(const cv::Mat& image, cv::Mat& pre_image, const int width, const int height, float& scale );
int postprocess(float* out, const cv::Mat& image, float box_score_thresh, float box_thresh, std::vector<Object>& result, float scale);
std::vector<Object> find_box(const cv::Mat pred_map, const cv::Mat& bit_map,
const float box_score_thresh, const float unclip_ratio,
const cv::Mat& image, float scale);
std::vector<cv::Point> get_min_boxes(const std::vector<cv::Point>& in_vec,
float& min_side_len, float& perimeter);
float get_box_score_fast(const cv::Mat& in_mat, const std::vector<cv::Point>& in_box);
std::vector<cv::Point> unclip(const std::vector<cv::Point>& in_box, float perimeter, float unclip_ratio);
bool cv_point_compare(const cv::Point& a, const cv::Point& b);
cv::Mat draw_objects(cv::Mat image, const std::vector<Object>& results);
#endif