增加多线程执行定位检测算法

增加edcircle算法到项目仓库里
master
bob.pan 5 years ago
parent d9f3ef31c8
commit 4b345d96ef

@ -53,7 +53,6 @@ cv::Mat ImageProcess::findCircleObject(const Mat &srcImg, const Mat& backgroundI
cv::resize(src, detectImg, cv::Size(src.cols / REAIZE, src.rows / REAIZE));
int bBaseX = detectImg.cols;
int bBaseY = detectImg.rows;
//if (nThres<=1)
equalizeHist(detectImg, detectImg);
detectImg = _EnhanImg_sharpen(detectImg);
@ -85,24 +84,17 @@ cv::Mat ImageProcess::findCircleObject(const Mat &srcImg, const Mat& backgroundI
if (startX > 0 && startY > 0 && hight > 0 \
&& startX < src.cols &&startY < src.rows \
&&hight < src.cols&&hight < src.rows \
&& startX + hight < src.cols && startY + hight < src.rows)
&& (startX + hight) < src.cols && (startY + hight) < src.rows)
{
Mat cutMat = src(Rect(startX, startY, hight, hight));
if (cutMat.data != NULL)
{
//Mat dst;
//double rate = src.cols*1.0 / ALG_RESIZE_IMAGE_WIDTH;
//const cv::Size cSize = cv::Size(cutMat.cols*1.0 / rate, cutMat.rows*1.0 / rate);
//cv::resize(cutMat, dst, cSize);
if (hight < 50)
return Mat();
cv::Point2d center;
center.x = EDCircle[nIndex].center.x * REAIZE;
center.y = EDCircle[nIndex].center.y * REAIZE;
pCircle->ptCenter = center;
//float fScale = src.cols / ALG_RESIZE_IMAGE_WIDTH;
//pCircle->fRadius = hight*1.0 / fScale;
pCircle->fRadius = radius * REAIZE;
//2021-05-10 增加图像大小判断 对超过900像素的图像进行再一次压缩

@ -0,0 +1,100 @@
#ifndef _ED_
#define _ED_
#include <opencv2/opencv.hpp>
#include "EDColor.h"
/// Special defines
#define EDGE_VERTICAL 1
#define EDGE_HORIZONTAL 2
#define ANCHOR_PIXEL 254
#define EDGE_PIXEL 255
#define LEFT 1
#define RIGHT 2
#define UP 3
#define DOWN 4
enum GradientOperator { PREWITT_OPERATOR = 101, SOBEL_OPERATOR = 102, SCHARR_OPERATOR = 103, LSD_OPERATOR = 104 };
struct StackNode {//存放需要发起搜索的像素点
int r, c; // 像素点位置
int parent; // 这个像素点隶属的链表
int dir; // 搜索方向
};
struct Chain {//边缘画线时用于记录链表信息每个Chain的方向是相同的不同Chain之间通过parentchildren的值进行查找
int dir; // 当前链的方向
int len; // 当前链的长度,像素个数
int parent; // 当前链的双亲
int children[2]; // 当前链两个方向的孩子children[0]代表left和up方向children[1]代表right和down方向
cv::Point *pixels; // 组成当前链的像素点的首地址
};
class ED {
public:
ED(cv::Mat _srcImage, GradientOperator _op = PREWITT_OPERATOR, int _gradThresh = 20, int _anchorThresh = 0, int _scanInterval = 1, int _minPathLen = 10, double _sigma = 1.0, bool _sumFlag = true);
ED(const ED &cpyObj);
ED(short* gradImg, uchar *dirImg, int _width, int _height, int _gradThresh, int _anchorThresh, int _scanInterval = 1, int _minPathLen = 10, bool selectStableAnchors = true);
ED(EDColor &cpyObj);
ED();
cv::Mat getEdgeImage();
cv::Mat getAnchorImage();
cv::Mat getSmoothImage();
cv::Mat getGradImage();
int getSegmentNo();
int getAnchorNo();
std::vector<cv::Point> getAnchorPoints();
std::vector<std::vector<cv::Point>> getSegments();
std::vector<std::vector<cv::Point>> getSortedSegments();
cv::Mat drawParticularSegments(std::vector<int> list);
protected:
int width; // 源图像宽度
int height; // 源图像高度
uchar *srcImg; //指向原图的数据区
std::vector<std::vector< cv::Point> > segmentPoints;//边缘段像素链二维容器每一行代表一条边缘每个数据是一个Point
double sigma; //高斯宽度参数σ,σ越大作用范围越宽
cv::Mat smoothImage;
uchar *edgeImg; //指向得到的边缘图像数据区
uchar *smoothImg; //指向高斯平滑后的图像数据区
int segmentNos;//第几条边缘
int minPathLen;//用于滤除短、细、杂、碎的边缘
cv::Mat srcImage;
private:
void ComputeGradient();
void ComputeAnchorPoints();
void JoinAnchorPointsUsingSortedAnchors();
void sortAnchorsByGradValue();
int* sortAnchorsByGradValue1();
static int LongestChain(Chain *chains, int root);//计算出某条边缘的链表集中边缘像素点总数
static int RetrieveChainNos(Chain *chains, int root, int chainNos[]);
int anchorNos;//找到的锚点个数
std::vector<cv::Point> anchorPoints;
std::vector<cv::Point> edgePoints;
cv::Mat edgeImage;//边缘图像
cv::Mat gradImage;//梯度图像当用Gx+Gy时两者之和可能会大于255所以要用short型。
uchar *dirImg; //指向边缘方向的数据区,用于边缘路径追踪
short *gradImg; //指向梯度图像的数据区
GradientOperator op; //枚举梯度算子类型
int gradThresh; //梯度阈值,用于抑制弱边缘点
int anchorThresh; //锚点阈值,阈值越小,找到的锚点个数越多
int scanInterval; //扫描间隔每隔scanInterval行scanInterval列扫描下一行必须小于高斯核的尺寸。
bool sumFlag;//=1时直接将两个方向的梯度相加默认为true=0时求两者平方和的开方计算量大大增加
};
#endif

@ -0,0 +1,275 @@
#ifndef _EDCIRCLES_
#define _EDCIRCLES_
#include "EDPF.h"
#include "EDLines.h"
#define PI 3.141592653589793238462
#define TWOPI (2*PI)
// Circular arc, circle thresholds
#define VERY_SHORT_ARC_ERROR 0.40 // Used for very short arcs (>= CANDIDATE_CIRCLE_RATIO1 && < CANDIDATE_CIRCLE_RATIO2)
#define SHORT_ARC_ERROR 1.00 // Used for short arcs (>= CANDIDATE_CIRCLE_RATIO2 && < HALF_CIRCLE_RATIO)
#define HALF_ARC_ERROR 1.25 // Used for arcs with length (>=HALF_CIRCLE_RATIO && < FULL_CIRCLE_RATIO)
#define LONG_ARC_ERROR 1.50 // Used for long arcs (>= FULL_CIRCLE_RATIO)
#define CANDIDATE_CIRCLE_RATIO1 0.25 // 25% -- If only 25% of the circle is detected, it may be a candidate for validation
#define CANDIDATE_CIRCLE_RATIO2 0.33 // 33% -- If only 33% of the circle is detected, it may be a candidate for validation
#define HALF_CIRCLE_RATIO 0.50 // 50% -- If 50% of a circle is detected at any point during joins, we immediately make it a candidate
#define FULL_CIRCLE_RATIO 0.87 // 67% -- If 67% of the circle is detected, we assume that it is fully covered
// Ellipse thresholds
#define CANDIDATE_ELLIPSE_RATIO 0.50 // 50% -- If 50% of the ellipse is detected, it may be candidate for validation
#define ELLIPSE_ERROR 1.50 // Used for ellipses. (used to be 1.65 for what reason?)
#define BOOKSTEIN 0 // method1 for ellipse fit
#define FPF 1 // method2 for ellipse fit
enum ImageStyle{NONE=0, CIRCLES, ELLIPSES, BOTH};
// Circle equation: (x-xc)^2 + (y-yc)^2 = r^2
struct mCircle {
cv::Point2d center;
double r;
mCircle(cv::Point2d _center, double _r) { center = _center; r = _r; }
};
// Ellipse equation: Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0
struct mEllipse {
cv::Point2d center;
cv::Size axes;
double theta;
mEllipse(cv::Point2d _center, cv::Size _axes, double _theta) { center = _center; axes = _axes; theta = _theta; }
};
//----------------------------------------------------------
// Ellipse Equation is of the form:
// Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0
//
struct EllipseEquation {
double coeff[7]; // coeff[1] = A
EllipseEquation() {
for (int i = 0; i<7; i++) coeff[i] = 0;
} //end-EllipseEquation
double A() { return coeff[1]; }
double B() { return coeff[2]; }
double C() { return coeff[3]; }
double D() { return coeff[4]; }
double E() { return coeff[5]; }
double F() { return coeff[6]; }
};
// ================================ CIRCLES ================================
struct Circle {
double xc, yc, r; // Center (xc, yc) & radius.
double circleFitError; // circle fit error
double coverRatio; // Percentage of the circle covered by the arcs making up this circle [0-1]
double *x, *y; // Pointers to buffers containing the pixels making up this circle
int noPixels; // # of pixels making up this circle
// If this circle is better approximated by an ellipse, we set isEllipse to true & eq contains the ellipse's equation
EllipseEquation eq;
double ellipseFitError; // ellipse fit error
bool isEllipse;
double majorAxisLength; // Length of the major axis
double minorAxisLength; // Length of the minor axis
};
// ------------------------------------------- ARCS ----------------------------------------------------
struct MyArc {
double xc, yc, r; // center x, y and radius
double circleFitError; // Error during circle fit
double sTheta, eTheta; // Start & end angle in radius
double coverRatio; // Ratio of the pixels covered on the covering circle [0-1] (noPixels/circumference)
int turn; // Turn direction: 1 or -1
int segmentNo; // SegmentNo where this arc belongs
int sx, sy; // Start (x, y) coordinate
int ex, ey; // End (x, y) coordinate of the arc
double *x, *y; // Pointer to buffer containing the pixels making up this arc
int noPixels; // # of pixels making up the arc
bool isEllipse; // Did we fit an ellipse to this arc?
EllipseEquation eq; // If an ellipse, then the ellipse's equation
double ellipseFitError; // Error during ellipse fit
};
// =============================== AngleSet ==================================
//-------------------------------------------------------------------------
// add a circular arc to the list of arcs
//
inline double ArcLength(double sTheta, double eTheta) {
if (eTheta > sTheta) return eTheta - sTheta;
else return TWOPI - sTheta + eTheta;
} // end-ArcLength
// A fast implementation of the AngleSet class. The slow implementation is really bad. About 10 times slower than this!
struct AngleSetArc {
double sTheta;
double eTheta;
int next; // Next AngleSetArc in the linked list
};
struct AngleSet {
AngleSetArc angles[360];
int head;
int next; // Next AngleSetArc to be allocated
double overlapAmount; // Total overlap of the arcs in angleSet. Computed during set() function
AngleSet() { clear(); } //end-AngleSet
void clear() { head = -1; next = 0; overlapAmount = 0; }
double overlapRatio() { return overlapAmount / (TWOPI); }
void _set(double sTheta, double eTheta);
void set(double sTheta, double eTheta);
double _overlap(double sTheta, double eTheta);
double overlap(double sTheta, double eTheta);
void computeStartEndTheta(double &sTheta, double &eTheta);
double coverRatio();
};
struct EDArcs {
MyArc *arcs;
int noArcs;
public:
EDArcs(int size = 10000) {
arcs = new MyArc[size];
noArcs = 0;
} //end-EDArcs
~EDArcs() {
delete arcs;
} //end-~EDArcs
};
//-----------------------------------------------------------------
// Buffer manager
struct BufferManager {
double *x, *y;
int index;
BufferManager(int maxSize) {
x = new double[maxSize];
y = new double[maxSize];
index = 0;
} //end-BufferManager
~BufferManager() {
delete x;
delete y;
} //end-~BufferManager
double *getX() { return &x[index]; }
double *getY() { return &y[index]; }
void move(int size) { index += size; }
};
struct Info {
int sign; // -1 or 1: sign of the cross product
double angle; // angle with the next line (in radians)
bool taken; // Is this line taken during arc detection
};
class EDCircles: public EDPF {
public:
EDCircles(cv::Mat srcImage);
EDCircles(ED obj);
EDCircles(EDColor obj);
cv::Mat drawResult(bool, ImageStyle);
std::vector<mCircle> getCircles();
std::vector<mEllipse> getEllipses();
int getCirclesNo();
int getEllipsesNo();
private:
int noEllipses;
int noCircles;
std::vector<mCircle> circles;
std::vector<mEllipse> ellipses;
Circle *circles1;
Circle *circles2;
Circle *circles3;
int noCircles1;
int noCircles2;
int noCircles3;
EDArcs *edarcs1;
EDArcs *edarcs2;
EDArcs *edarcs3;
EDArcs *edarcs4;
int *segmentStartLines;
BufferManager *bm;
Info *info;
NFALUT *nfa;
void GenerateCandidateCircles();
void DetectArcs(std::vector<LineSegment> lines);
void ValidateCircles();
void JoinCircles();
void JoinArcs1();
void JoinArcs2();
void JoinArcs3();
// circle utility functions
static Circle *addCircle(Circle *circles, int &noCircles,double xc, double yc, double r, double circleFitError, double *x, double *y, int noPixels);
static Circle *addCircle(Circle *circles, int &noCircles,double xc, double yc, double r, double circleFitError, EllipseEquation *pEq, double ellipseFitError, double *x, double *y, int noPixels);
static void sortCircles(Circle *circles, int noCircles);
static bool CircleFit(double *x, double *y, int N, double *pxc, double *pyc, double *pr, double *pe);
static void ComputeCirclePoints(double xc, double yc, double r, double *px, double *py, int *noPoints);
static void sortCircle(Circle *circles, int noCircles);
// ellipse utility functions
static bool EllipseFit(double *x, double *y, int noPoints, EllipseEquation *pResult, int mode=FPF);
static double **AllocateMatrix(int noRows, int noColumns);
static void A_TperB(double **_A, double **_B, double **_res, int _righA, int _colA, int _righB, int _colB);
static void choldc(double **a, int n, double **l);
static int inverse(double **TB, double **InvB, int N);
static void DeallocateMatrix(double **m, int noRows);
static void AperB_T(double **_A, double **_B, double **_res, int _righA, int _colA, int _righB, int _colB);
static void AperB(double **_A, double **_B, double **_res, int _righA, int _colA, int _righB, int _colB);
static void jacobi(double **a, int n, double d[], double **v, int nrot);
static void ROTATE(double **a, int i, int j, int k, int l, double tau, double s);
static double computeEllipsePerimeter(EllipseEquation *eq);
static double ComputeEllipseError(EllipseEquation *eq, double *px, double *py, int noPoints);
static double ComputeEllipseCenterAndAxisLengths(EllipseEquation *eq, double *pxc, double *pyc, double *pmajorAxisLength, double *pminorAxisLength);
static void ComputeEllipsePoints(double *pvec, double *px, double *py, int noPoints);
// arc utility functions
static void joinLastTwoArcs(MyArc *arcs, int &noArcs);
static void addArc(MyArc *arcs, int &noArchs,double xc, double yc, double r, double circleFitError, // Circular arc
double sTheta, double eTheta, int turn, int segmentNo,
int sx, int sy, int ex, int ey,
double *x, double *y, int noPixels, double overlapRatio = 0.0);
static void addArc(MyArc *arcs, int &noArchs, double xc, double yc, double r, double circleFitError, // Elliptic arc
double sTheta, double eTheta, int turn, int segmentNo,
EllipseEquation *pEq, double ellipseFitError,
int sx, int sy, int ex, int ey,
double *x, double *y, int noPixels, double overlapRatio = 0.0);
static void ComputeStartAndEndAngles(double xc, double yc, double r,
double *x, double *y, int len,
double *psTheta, double *peTheta);
static void sortArc(MyArc *arcs, int noArcs);
};
#endif // ! _EDCIRCLES_

@ -0,0 +1,77 @@
#ifndef _EDColor_
#define _EDColor_
#include <opencv2/opencv.hpp>
// Look up table size for fast color space conversion
#define LUT_SIZE (1024*4096)
// Special defines
#define EDGE_VERTICAL 1
#define EDGE_HORIZONTAL 2
#define EDGE_45 3
#define EDGE_135 4
#define MAX_GRAD_VALUE 128*256
#define EPSILON 1.0
#define MIN_PATH_LEN 10
class EDColor {
public:
EDColor(cv::Mat srcImage, int gradThresh = 20, int anchor_thresh = 4, double sigma = 1.5, bool validateSegments=false);
cv::Mat getEdgeImage();
std::vector<std::vector<cv::Point>> getSegments();
int getSegmentNo();
int getWidth();
int getHeight();
cv::Mat inputImage;
private:
uchar *L_Img;
uchar *a_Img;
uchar *b_Img;
uchar *smooth_L;
uchar *smooth_a;
uchar *smooth_b;
uchar *dirImg;
short *gradImg;
cv::Mat edgeImage;
uchar *edgeImg;
const uchar *blueImg;
const uchar *greenImg;
const uchar *redImg;
int width;
int height;
double divForTestSegment;
double *H;
int np;
int segmentNo;
std::vector<std::vector<cv::Point>> segments;
static double LUT1[LUT_SIZE + 1];
static double LUT2[LUT_SIZE + 1];
static bool LUT_Initialized;
void MyRGB2LabFast();
void ComputeGradientMapByDiZenzo();
void smoothChannel(uchar *src, uchar *smooth, double sigma);
void validateEdgeSegments();
void testSegment(int i, int index1, int index2);
void extractNewSegments();
double NFA(double prob, int len);
static void fixEdgeSegments(std::vector<std::vector<cv::Point>> map, int noPixels);
static void InitColorEDLib();
};
#endif // ! _EDColor_

@ -0,0 +1,100 @@
#ifndef _EDLines_
#define _EDLines_
#include "ED.h"
#include "EDColor.h"
#include "NFA.h"
#define SS 0
#define SE 1
#define ES 2
#define EE 3
// light weight struct for Start & End coordinates of the line segment
struct LS {
cv::Point2d start;
cv::Point2d end;
LS(cv::Point2d _start, cv::Point2d _end)
{
start = _start;
end = _end;
}
};
struct LineSegment {
double a, b; // y = a + bx (if invert = 0) || x = a + by (if invert = 1)
int invert;
double sx, sy; // starting x & y coordinates
double ex, ey; // ending x & y coordinates
int segmentNo; // Edge segment that this line belongs to
int firstPixelIndex; // Index of the first pixel within the segment of pixels
int len; // No of pixels making up the line segment
LineSegment(double _a, double _b, int _invert, double _sx, double _sy, double _ex, double _ey, int _segmentNo, int _firstPixelIndex, int _len) {
a = _a;
b = _b;
invert = _invert;
sx = _sx;
sy = _sy;
ex = _ex;
ey = _ey;
segmentNo = _segmentNo;
firstPixelIndex = _firstPixelIndex;
len = _len;
}
};
class EDLines : public ED {//继承ED
public:
EDLines(cv::Mat srcImage, double _line_error = 1.0, int _min_line_len = -1, double _max_distance_between_two_lines = 6.0, double _max_error = 1.3);
EDLines(ED obj, double _line_error = 1.0, int _min_line_len = -1, double _max_distance_between_two_lines = 6.0, double _max_error = 1.3);
EDLines(EDColor obj, double _line_error = 1.0, int _min_line_len = -1, double _max_distance_between_two_lines = 6.0, double _max_error = 1.3);
EDLines();
std::vector<LS> getLines();
int getLinesNo();
cv::Mat getLineImage();
cv::Mat drawOnImage();
// EDCircle uses this one
static void SplitSegment2Lines(double *x, double *y, int noPixels, int segmentNo, std::vector<LineSegment> &lines, int min_line_len = 6, double line_error = 1.0);
private:
std::vector<LineSegment> lines;//拟合得到的线段
std::vector<LineSegment> invalidLines;
std::vector<LS> linePoints;
int linesNo;
int min_line_len;//拟合得到的最短线段长度即在极限的情况下用长度为min_line_len的线段去逼近边缘段
double line_error;//点到直线的距离最大值
double max_distance_between_two_lines;
double max_error;
double prec;
NFALUT *nfa;
int ComputeMinLineLength();
void SplitSegment2Lines(double *x, double *y, int noPixels, int segmentNo);
void JoinCollinearLines();
void ValidateLineSegments();
bool ValidateLineSegmentRect(int *x, int *y, LineSegment *ls);
bool TryToJoinTwoLineSegments(LineSegment *ls1, LineSegment *ls2, int changeIndex);
static double ComputeMinDistance(double x1, double y1, double a, double b, int invert);
static void ComputeClosestPoint(double x1, double y1, double a, double b, int invert, double &xOut, double &yOut);
static void LineFit(double *x, double *y, int count, double &a, double &b, int invert);
static void LineFit(double *x, double *y, int count, double &a, double &b, double &e, int &invert);
static double ComputeMinDistanceBetweenTwoLines(LineSegment *ls1, LineSegment *ls2, int *pwhich);
static void UpdateLineParameters(LineSegment *ls);
static void EnumerateRectPoints(double sx, double sy, double ex, double ey,int ptsx[], int ptsy[], int *pNoPoints);
// Utility math functions
};
#endif

@ -0,0 +1,27 @@
#ifndef _EDPF_
#define _EDPF_
#include "ED.h"
#define MAX_GRAD_VALUE 128*256
#define EPSILON 1.0
class EDPF : public ED {
public:
EDPF(cv::Mat srcImage);
EDPF(ED obj);
EDPF(EDColor obj);
private:
double divForTestSegment;
double *H;
int np;
short *gradImg;
void validateEdgeSegments();
short *ComputePrewitt3x3(); // differs from base class's prewit function (calculates H)
void TestSegment(int i, int index1, int index2);
void ExtractNewSegments();
double NFA(double prob, int len);
};
#endif // ! _EDPF_

@ -0,0 +1,51 @@
#ifndef _NFA_
#define _NFA_
#define TABSIZE 100000
//----------------------------------------------
// Fast arctan2 using a lookup table
//
#define MAX_LUT_SIZE 1024
#ifndef TRUE
#define TRUE 1
#endif /* !TRUE */
/** ln(10) */
#ifndef M_LN10
#define M_LN10 2.30258509299404568402
#endif /* !M_LN10 */
/** PI */
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif /* !M_PI */
#define RELATIVE_ERROR_FACTOR 100.0
// Lookup table (LUT) for NFA computation
class NFALUT {
public:
NFALUT(int size, double _prob, double _logNT);
~NFALUT();
int *LUT; // look up table
int LUTSize;
double prob;
double logNT;
bool checkValidationByNFA(int n, int k);
static double myAtan2(double yy, double xx);
private:
double nfa(int n, int k);
static double log_gamma_lanczos(double x);
static double log_gamma_windschitl(double x);
static double log_gamma(double x);
static int double_equal(double a, double b);
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,624 @@
#include "EDColor.h"
#include "ED.h"
using namespace cv;
using namespace std;
EDColor::EDColor(Mat srcImage, int gradThresh, int anchor_thresh , double sigma, bool validateSegments)
{
inputImage = srcImage.clone();
// check parameters for sanity
if (sigma < 1) sigma = 1;
if (gradThresh < 1) gradThresh = 1;
if (anchor_thresh < 0) anchor_thresh = 0;
if (validateSegments) { // setup for validation
anchor_thresh = 0;
divForTestSegment = 2.25;
}
// split channels (OpenCV uses BGR)
Mat bgr[3];
split(srcImage, bgr);
blueImg = bgr[0].data;
greenImg = bgr[1].data;
redImg = bgr[2].data;
height = srcImage.rows;
width = srcImage.cols;
// Allocate space for L*a*b color space
L_Img = new uchar[width*height];
a_Img = new uchar[width*height];
b_Img = new uchar[width*height];
// Convert RGB2Lab
MyRGB2LabFast();
// Allocate space for smooth channels
smooth_L = new uchar[width*height];
smooth_a = new uchar[width*height];
smooth_b = new uchar[width*height];
// Smooth Channels
smoothChannel(L_Img, smooth_L, sigma);
smoothChannel(a_Img, smooth_a, sigma);
smoothChannel(b_Img, smooth_b, sigma);
// Allocate space for direction and gradient images
dirImg = new uchar[width*height];
gradImg = new short[width*height];
// Compute Gradient & Edge Direction Maps
ComputeGradientMapByDiZenzo();
// Validate edge segments if the flag is set
if (validateSegments) {
// Get Edge Image using ED
ED edgeObj = ED(gradImg, dirImg, width, height, gradThresh, anchor_thresh, 1, 10, false);
segments = edgeObj.getSegments();
edgeImage = edgeObj.getEdgeImage();
sigma /= 2.5;
smoothChannel(L_Img, smooth_L, sigma);
smoothChannel(a_Img, smooth_a, sigma);
smoothChannel(b_Img, smooth_b, sigma);
edgeImg = edgeImage.data; // validation steps uses pointer to edgeImage
validateEdgeSegments();
// Extract the new edge segments after validation
extractNewSegments();
}
else {
ED edgeObj = ED(gradImg, dirImg, width, height, gradThresh, anchor_thresh);
segments = edgeObj.getSegments();
edgeImage = edgeObj.getEdgeImage();
segmentNo = edgeObj.getSegmentNo();
}
// Fix 1 pixel errors in the edge map
fixEdgeSegments(segments, 1);
// clean space
delete[] L_Img;
delete[] a_Img;
delete[] b_Img;
delete[] smooth_L;
delete[] smooth_a;
delete[] smooth_b;
delete[] gradImg;
delete[] dirImg;
}
cv::Mat EDColor::getEdgeImage()
{
return edgeImage;
}
std::vector<std::vector<cv::Point>> EDColor::getSegments()
{
return segments;
}
int EDColor::getSegmentNo()
{
return segmentNo;
}
int EDColor::getWidth()
{
return width;
}
int EDColor::getHeight()
{
return height;
}
void EDColor::MyRGB2LabFast()
{
// Inialize LUTs if necessary
if (!LUT_Initialized)
InitColorEDLib();
// First RGB 2 XYZ
double red, green, blue;
double x, y, z;
// Space for temp. allocation
double *L = new double[width*height];
double *a = new double[width*height];
double *b = new double[width*height];
for (int i = 0; i<width*height; i++) {
red = redImg[i] / 255.0;
green = greenImg[i] / 255.0;
blue = blueImg[i] / 255.0;
red = LUT1[(int)(red*LUT_SIZE + 0.5)];
green = LUT1[(int)(green*LUT_SIZE + 0.5)];
blue = LUT1[(int)(blue*LUT_SIZE + 0.5)];
red = red * 100;
green = green * 100;
blue = blue * 100;
//Observer. = 2? Illuminant = D65
x = red*0.4124564 + green*0.3575761 + blue*0.1804375;
y = red*0.2126729 + green*0.7151522 + blue*0.0721750;
z = red*0.0193339 + green*0.1191920 + blue*0.9503041;
// Now xyz 2 Lab
double refX = 95.047;
double refY = 100.000;
double refZ = 108.883;
x = x / refX; //ref_X = 95.047 Observer= 2? Illuminant= D65
y = y / refY; //ref_Y = 100.000
z = z / refZ; //ref_Z = 108.883
x = LUT2[(int)(x*LUT_SIZE + 0.5)];
y = LUT2[(int)(y*LUT_SIZE + 0.5)];
z = LUT2[(int)(z*LUT_SIZE + 0.5)];
L[i] = (116.0*y) - 16;
a[i] = 500 * (x / y);
b[i] = 200 * (y - z);
} //end-for
// Scale L to [0-255]
double min = 1e10;
double max = -1e10;
for (int i = 0; i<width*height; i++) {
if (L[i]<min) min = L[i];
else if (L[i]>max) max = L[i];
} //end-for
double scale = 255.0 / (max - min);
for (int i = 0; i<width*height; i++) { L_Img[i] = (unsigned char)((L[i] - min)*scale); }
// Scale a to [0-255]
min = 1e10;
max = -1e10;
for (int i = 0; i<width*height; i++) {
if (a[i]<min) min = a[i];
else if (a[i]>max) max = a[i];
} //end-for
scale = 255.0 / (max - min);
for (int i = 0; i<width*height; i++) { a_Img[i] = (unsigned char)((a[i] - min)*scale); }
// Scale b to [0-255]
min = 1e10;
max = -1e10;
for (int i = 0; i<width*height; i++) {
if (b[i]<min) min = b[i];
else if (b[i]>max) max = b[i];
} //end-for
scale = 255.0 / (max - min);
for (int i = 0; i<width*height; i++) { b_Img[i] = (unsigned char)((b[i] - min)*scale); }
// clean space
delete[] L;
delete[] a;
delete[] b;
}
void EDColor::ComputeGradientMapByDiZenzo()
{
memset(gradImg, 0, sizeof(short)*width*height);
int max = 0;
for (int i = 1; i < height - 1; i++) {
for (int j = 1; j < width - 1; j++) {
#if 1
// Prewitt for channel1
int com1 = smooth_L[(i + 1)*width + j + 1] - smooth_L[(i - 1)*width + j - 1];
int com2 = smooth_L[(i - 1)*width + j + 1] - smooth_L[(i + 1)*width + j - 1];
int gxCh1 = com1 + com2 + (smooth_L[i*width + j + 1] - smooth_L[i*width + j - 1]);
int gyCh1 = com1 - com2 + (smooth_L[(i + 1)*width + j] - smooth_L[(i - 1)*width + j]);
// Prewitt for channel2
com1 = smooth_a[(i + 1)*width + j + 1] - smooth_a[(i - 1)*width + j - 1];
com2 = smooth_a[(i - 1)*width + j + 1] - smooth_a[(i + 1)*width + j - 1];
int gxCh2 = com1 + com2 + (smooth_a[i*width + j + 1] - smooth_a[i*width + j - 1]);
int gyCh2 = com1 - com2 + (smooth_a[(i + 1)*width + j] - smooth_a[(i - 1)*width + j]);
// Prewitt for channel3
com1 = smooth_b[(i + 1)*width + j + 1] - smooth_b[(i - 1)*width + j - 1];
com2 = smooth_b[(i - 1)*width + j + 1] - smooth_b[(i + 1)*width + j - 1];
int gxCh3 = com1 + com2 + (smooth_b[i*width + j + 1] - smooth_b[i*width + j - 1]);
int gyCh3 = com1 - com2 + (smooth_b[(i + 1)*width + j] - smooth_b[(i - 1)*width + j]);
#else
// Sobel for channel1
int com1 = smooth_L[(i + 1)*width + j + 1] - smooth_L[(i - 1)*width + j - 1];
int com2 = smooth_L[(i - 1)*width + j + 1] - smooth_L[(i + 1)*width + j - 1];
int gxCh1 = com1 + com2 + 2 * (smooth_L[i*width + j + 1] - smooth_L[i*width + j - 1]);
int gyCh1 = com1 - com2 + 2 * (smooth_L[(i + 1)*width + j] - smooth_L[(i - 1)*width + j]);
// Sobel for channel2
com1 = smooth_a[(i + 1)*width + j + 1] - smooth_a[(i - 1)*width + j - 1];
com2 = smooth_a[(i - 1)*width + j + 1] - smooth_a[(i + 1)*width + j - 1];
int gxCh2 = com1 + com2 + 2 * (smooth_a[i*width + j + 1] - smooth_a[i*width + j - 1]);
int gyCh2 = com1 - com2 + 2 * (smooth_a[(i + 1)*width + j] - smooth_a[(i - 1)*width + j]);
// Sobel for channel3
com1 = smooth_b[(i + 1)*width + j + 1] - smooth_b[(i - 1)*width + j - 1];
com2 = smooth_b[(i - 1)*width + j + 1] - smooth_b[(i + 1)*width + j - 1];
int gxCh3 = com1 + com2 + 2 * (smooth_b[i*width + j + 1] - smooth_b[i*width + j - 1]);
int gyCh3 = com1 - com2 + 2 * (smooth_b[(i + 1)*width + j] - smooth_b[(i - 1)*width + j]);
#endif
int gxx = gxCh1*gxCh1 + gxCh2*gxCh2 + gxCh3*gxCh3;
int gyy = gyCh1*gyCh1 + gyCh2*gyCh2 + gyCh3*gyCh3;
int gxy = gxCh1*gyCh1 + gxCh2*gyCh2 + gxCh3*gyCh3;
#if 1
// Di Zenzo's formulas from Gonzales & Woods - Page 337
double theta = atan2(2.0*gxy, (double)(gxx - gyy)) / 2; // Gradient Direction
int grad = (int)(sqrt(((gxx + gyy) + (gxx - gyy)*cos(2 * theta) + 2 * gxy*sin(2 * theta)) / 2.0) + 0.5); // Gradient Magnitude
#else
// Koschan & Abidi - 2005 - Signal Processing Magazine
double theta = atan2(2.0*gxy, (double)(gxx - gyy)) / 2; // Gradient Direction
double cosTheta = cos(theta);
double sinTheta = sin(theta);
int grad = (int)(sqrt(gxx*cosTheta*cosTheta + 2 * gxy*sinTheta*cosTheta + gyy*sinTheta*sinTheta) + 0.5); // Gradient Magnitude
#endif
// Gradient is perpendicular to the edge passing through the pixel
if (theta >= -3.14159 / 4 && theta <= 3.14159 / 4)
dirImg[i*width + j] = EDGE_VERTICAL;
else
dirImg[i*width + j] = EDGE_HORIZONTAL;
gradImg[i*width + j] = grad;
if (grad > max) max = grad;
}
} // end outer for
// Scale the gradient values to 0-255
double scale = 255.0 / max;
for (int i = 0; i<width*height; i++)
gradImg[i] = (short)(gradImg[i] * scale);
}
void EDColor::smoothChannel(uchar *src, uchar *smooth, double sigma)
{
Mat srcImage = Mat(height, width, CV_8UC1, src);
Mat smoothImage = Mat(height, width, CV_8UC1, smooth);
if (sigma == 1.0)
GaussianBlur(srcImage, smoothImage, Size(5, 5), 1);
else if (sigma == 1.5)
GaussianBlur(srcImage, smoothImage, Size(7, 7), 1.5); // seems to be better?
else
GaussianBlur(srcImage, smoothImage, Size(), sigma);
}
//--------------------------------------------------------------------------------------------------------------------
// Validate the edge segments using the Helmholtz principle (for color images) channel1, channel2 and channel3 images
//
void EDColor::validateEdgeSegments()
{
int maxGradValue = MAX_GRAD_VALUE;
H = new double[maxGradValue];
memset(H, 0, sizeof(double)*maxGradValue);
memset(edgeImg, 0, width*height); // clear edge image
// Compute the gradient
memset(gradImg, 0, sizeof(short)*width*height); // reset gradient Image pixels to zero
int *grads = new int[maxGradValue];
memset(grads, 0, sizeof(int)*maxGradValue);
for (int i = 1; i<height - 1; i++) {
for (int j = 1; j<width - 1; j++) {
// Gradient for channel1
int com1 = smooth_L[(i + 1)*width + j + 1] - smooth_L[(i - 1)*width + j - 1];
int com2 = smooth_L[(i - 1)*width + j + 1] - smooth_L[(i + 1)*width + j - 1];
int gxCh1 = abs(com1 + com2 + (smooth_L[i*width + j + 1] - smooth_L[i*width + j - 1]));
int gyCh1 = abs(com1 - com2 + (smooth_L[(i + 1)*width + j] - smooth_L[(i - 1)*width + j]));
int ch1Grad = gxCh1 + gyCh1;
// Gradient for channel2
com1 = smooth_a[(i + 1)*width + j + 1] - smooth_a[(i - 1)*width + j - 1];
com2 = smooth_a[(i - 1)*width + j + 1] - smooth_a[(i + 1)*width + j - 1];
int gxCh2 = abs(com1 + com2 + (smooth_a[i*width + j + 1] - smooth_a[i*width + j - 1]));
int gyCh2 = abs(com1 - com2 + (smooth_a[(i + 1)*width + j] - smooth_a[(i - 1)*width + j]));
int ch2Grad = gxCh2 + gyCh2;
// Gradient for channel3
com1 = smooth_b[(i + 1)*width + j + 1] - smooth_b[(i - 1)*width + j - 1];
com2 = smooth_b[(i - 1)*width + j + 1] - smooth_b[(i + 1)*width + j - 1];
int gxCh3 = abs(com1 + com2 + (smooth_b[i*width + j + 1] - smooth_b[i*width + j - 1]));
int gyCh3 = abs(com1 - com2 + (smooth_b[(i + 1)*width + j] - smooth_b[(i - 1)*width + j]));
int ch3Grad = gxCh3 + gyCh3;
// Take average
int grad = (ch1Grad + ch2Grad + ch3Grad + 2) / 3;
gradImg[i*width + j] = grad;
grads[grad]++;
} //end-for
} //end-for
Mat gradImage = Mat(height, width, CV_16SC1, gradImg);
imwrite("newGrad.pgm", gradImage);
// Compute probability function H
int size = (width - 2)*(height - 2);
// size -= grads[0];
for (int i = maxGradValue - 1; i>0; i--)
grads[i - 1] += grads[i];
for (int i = 0; i<maxGradValue; i++)
H[i] = (double)grads[i] / ((double)size);
// Compute np: # of segment pieces
np = 0;
for (int i = 0; i<segments.size(); i++) {
int len = segments[i].size();
np += (len*(len - 1)) / 2;
} //end-for
// Validate segments
for (int i = 0; i< segments.size(); i++) {
testSegment(i, 0, segments[i].size() - 1);
} //end-for
// clear space
delete[] H;
delete[] grads;
}
//----------------------------------------------------------------------------------
// Resursive validation using half of the pixels as suggested by DMM algorithm
// We take pixels at Nyquist distance, i.e., 2 (as suggested by DMM)
//
void EDColor::testSegment(int i, int index1, int index2)
{
int chainLen = index2 - index1 + 1;
if (chainLen < MIN_PATH_LEN)
return;
// Test from index1 to index2. If OK, then we are done. Otherwise, split into two and
// recursively test the left & right halves
// First find the min. gradient along the segment
int minGrad = 1 << 30;
int minGradIndex;
for (int k = index1; k <= index2; k++) {
int r = segments[i][k].y;
int c = segments[i][k].x;
if (gradImg[r*width + c] < minGrad) { minGrad = gradImg[r*width + c]; minGradIndex = k; }
} //end-for
// Compute nfa
double nfa = NFA(H[minGrad], (int)(chainLen / divForTestSegment));
if (nfa <= EPSILON) {
for (int k = index1; k <= index2; k++) {
int r = segments[i][k].y;
int c = segments[i][k].x;
edgeImg[r*width + c] = 255;
} //end-for
return;
} //end-if
// Split into two halves. We divide at the point where the gradient is the minimum
int end = minGradIndex - 1;
while (end > index1) {
int r = segments[i][end].y;
int c = segments[i][end].x;
if (gradImg[r*width + c] <= minGrad) end--;
else break;
} //end-while
int start = minGradIndex + 1;
while (start < index2) {
int r = segments[i][start].y;
int c = segments[i][start].x;
if (gradImg[r*width + c] <= minGrad) start++;
else break;
} //end-while
testSegment(i, index1, end);
testSegment(i, start, index2);
}
//----------------------------------------------------------------------------------------------
// After the validation of the edge segments, extracts the valid ones
// In other words, updates the valid segments' pixel arrays and their lengths
//
void EDColor::extractNewSegments()
{
vector< vector<Point> > validSegments;
int noSegments = 0;
for (int i = 0; i < segments.size(); i++) {
int start = 0;
while (start < segments[i].size()) {
while (start < segments[i].size()) {
int r = segments[i][start].y;
int c = segments[i][start].x;
if (edgeImg[r*width + c]) break;
start++;
} //end-while
int end = start + 1;
while (end < segments[i].size()) {
int r = segments[i][end].y;
int c = segments[i][end].x;
if (edgeImg[r*width + c] == 0) break;
end++;
} //end-while
int len = end - start;
if (len >= 10) {
// A new segment. Accepted only only long enough (whatever that means)
//segments[noSegments].pixels = &map->segments[i].pixels[start];
//segments[noSegments].noPixels = len;
validSegments.push_back(vector<Point>());
vector<Point> subVec(&segments[i][start], &segments[i][end - 1]);
validSegments[noSegments] = subVec;
noSegments++;
} //end-else
start = end + 1;
} //end-while
} //end-for
// Update
segments = validSegments;
segmentNo = noSegments; // = validSegments.size()
}
double EDColor::NFA(double prob, int len)
{
double nfa = np;
for (int i = 0; i<len && nfa > EPSILON; i++)
nfa *= prob;
return nfa;
}
//---------------------------------------------------------
// Fix edge segments having one or two pixel fluctuations
// An example one pixel problem getting fixed:
// x
// x x --> xxx
//
// An example two pixel problem getting fixed:
// xx
// x x --> xxxx
//
void EDColor::fixEdgeSegments(std::vector<std::vector<cv::Point>> map, int noPixels)
{
/// First fix one pixel problems: There are four cases
for (int i = 0; i < map.size(); i++) {
int cp = map[i].size() - 2; // Current pixel index
int n2 = 0; // next next pixel index
while (n2 < map[i].size()) {
int n1 = cp + 1; // next pixel
cp = cp % map[i].size(); // Roll back to the beginning
n1 = n1 % map[i].size(); // Roll back to the beginning
int r = map[i][cp].y;
int c = map[i][cp].x;
int r1 = map[i][n1].y;
int c1 = map[i][n1].x;
int r2 = map[i][n2].y;
int c2 = map[i][n2].x;
// 4 cases to fix
if (r2 == r - 2 && c2 == c) {
if (c1 != c) {
map[i][n1].x = c;
} //end-if
cp = n2;
n2 += 2;
}
else if (r2 == r + 2 && c2 == c) {
if (c1 != c) {
map[i][n1].x = c;
} //end-if
cp = n2;
n2 += 2;
}
else if (r2 == r && c2 == c - 2) {
if (r1 != r) {
map[i][n1].y = r;
} //end-if
cp = n2;
n2 += 2;
}
else if (r2 == r && c2 == c + 2) {
if (r1 != r) {
map[i][n1].y = r;
} //end-if
cp = n2;
n2 += 2;
}
else {
cp++;
n2++;
} //end-else
} //end-while
} // end-for
}
void EDColor::InitColorEDLib()
{
if (LUT_Initialized)
return;
double inc = 1.0 / LUT_SIZE;
for (int i = 0; i <= LUT_SIZE; i++) {
double d = i * inc;
if (d >= 0.04045) LUT1[i] = pow(((d + 0.055) / 1.055), 2.4);
else LUT1[i] = d / 12.92;
} //end-for
inc = 1.0 / LUT_SIZE;
for (int i = 0; i <= LUT_SIZE; i++) {
double d = i * inc;
if (d > 0.008856) LUT2[i] = pow(d, 1.0 / 3.0);
else LUT2[i] = (7.787*d) + (16.0 / 116.0);
} //end-for
LUT_Initialized = true;
}
bool EDColor::LUT_Initialized = false;
double EDColor::LUT1[LUT_SIZE + 1] = {0};
double EDColor::LUT2[LUT_SIZE + 1] = {0};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,244 @@
#include "EDPF.h"
using namespace cv;
using namespace std;
EDPF::EDPF(Mat srcImage)
:ED(srcImage, PREWITT_OPERATOR, 11, 3)
{
// Validate Edge Segments
sigma /= 2.5;
GaussianBlur(srcImage, smoothImage, Size(), sigma); // calculate kernel from sigma
validateEdgeSegments();
}
EDPF::EDPF(ED obj)
:ED(obj)
{
// Validate Edge Segments
sigma /= 2.5;
GaussianBlur(srcImage, smoothImage, Size(), sigma); // calculate kernel from sigma
validateEdgeSegments();
}
EDPF::EDPF(EDColor obj)
:ED(obj)
{
}
void EDPF::validateEdgeSegments()
{
divForTestSegment = 2.25; // Some magic number :-)
memset(edgeImg, 0, width*height); // clear edge image
H = new double[MAX_GRAD_VALUE];
memset(H, 0, sizeof(double)*MAX_GRAD_VALUE);
gradImg = ComputePrewitt3x3();
// Compute np: # of segment pieces
#if 1
// Does this underestimate the number of pieces of edge segments?
// What's the correct value?
np = 0;
for (int i = 0; i < segmentNos; i++) {
int len = segmentPoints[i].size();
np += (len*(len - 1)) / 2;
} //end-for
// np *= 32;
#elif 0
// This definitely overestimates the number of pieces of edge segments
int np = 0;
for (int i = 0; i < segmentNos; i++) {
np += segmentPoints[i].size();
} //end-for
np = (np*(np - 1)) / 2;
#endif
// Validate segments
for (int i = 0; i< segmentNos; i++) {
TestSegment(i, 0, segmentPoints[i].size() - 1);
} //end-for
ExtractNewSegments();
// clean space
delete[] H;
delete[] gradImg;
}
short * EDPF::ComputePrewitt3x3()
{
short *gradImg = new short[width*height];
memset(gradImg, 0, sizeof(short)*width*height);
int *grads = new int[MAX_GRAD_VALUE];
memset(grads, 0, sizeof(int)*MAX_GRAD_VALUE);
for (int i = 1; i<height - 1; i++) {
for (int j = 1; j<width - 1; j++) {
// Prewitt Operator in horizontal and vertical direction
// A B C
// D x E
// F G H
// gx = (C-A) + (E-D) + (H-F)
// gy = (F-A) + (G-B) + (H-C)
//
// To make this faster:
// com1 = (H-A)
// com2 = (C-F)
// Then: gx = com1 + com2 + (E-D) = (H-A) + (C-F) + (E-D) = (C-A) + (E-D) + (H-F)
// gy = com1 - com2 + (G-B) = (H-A) - (C-F) + (G-B) = (F-A) + (G-B) + (H-C)
//
int com1 = srcImg[(i + 1)*width + j + 1] - srcImg[(i - 1)*width + j - 1];
int com2 = srcImg[(i - 1)*width + j + 1] - srcImg[(i + 1)*width + j - 1];
int gx = abs(com1 + com2 + (srcImg[i*width + j + 1] - srcImg[i*width + j - 1]));
int gy = abs(com1 - com2 + (srcImg[(i + 1)*width + j] - srcImg[(i - 1)*width + j]));
int g = gx + gy;
gradImg[i*width + j] = g;
grads[g]++;
} // end-for
} //end-for
// Compute probability function H
int size = (width - 2)*(height - 2);
for (int i = MAX_GRAD_VALUE - 1; i>0; i--)
grads[i - 1] += grads[i];
for (int i = 0; i < MAX_GRAD_VALUE; i++)
H[i] = (double)grads[i] / ((double)size);
delete[] grads;
return gradImg;
}
//----------------------------------------------------------------------------------
// Resursive validation using half of the pixels as suggested by DMM algorithm
// We take pixels at Nyquist distance, i.e., 2 (as suggested by DMM)
//
void EDPF::TestSegment(int i, int index1, int index2)
{
int chainLen = index2 - index1 + 1;
if (chainLen < minPathLen)
return;
// Test from index1 to index2. If OK, then we are done. Otherwise, split into two and
// recursively test the left & right halves
// First find the min. gradient along the segment
int minGrad = 1 << 30;
int minGradIndex;
for (int k = index1; k <= index2; k++) {
int r = segmentPoints[i][k].y;
int c = segmentPoints[i][k].x;
if (gradImg[r*width + c] < minGrad) { minGrad = gradImg[r*width + c]; minGradIndex = k; }
} //end-for
// Compute nfa
double nfa = NFA(H[minGrad], (int)(chainLen / divForTestSegment));
if (nfa <= EPSILON) {
for (int k = index1; k <= index2; k++) {
int r = segmentPoints[i][k].y;
int c = segmentPoints[i][k].x;
edgeImg[r*width + c] = 255;
} //end-for
return;
} //end-if
// Split into two halves. We divide at the point where the gradient is the minimum
int end = minGradIndex - 1;
while (end > index1) {
int r = segmentPoints[i][end].y;
int c = segmentPoints[i][end].x;
if (gradImg[r*width + c] <= minGrad) end--;
else break;
} //end-while
int start = minGradIndex + 1;
while (start < index2) {
int r = segmentPoints[i][start].y;
int c = segmentPoints[i][start].x;
if (gradImg[r*width + c] <= minGrad) start++;
else break;
} //end-while
TestSegment(i, index1, end);
TestSegment(i, start, index2);
}
//----------------------------------------------------------------------------------------------
// After the validation of the edge segments, extracts the valid ones
// In other words, updates the valid segments' pixel arrays and their lengths
//
void EDPF::ExtractNewSegments()
{
//vector<Point> *segments = &segmentPoints[segmentNos];
vector< vector<Point> > validSegments;
int noSegments = 0;
for (int i = 0; i < segmentNos; i++) {
int start = 0;
while (start < segmentPoints[i].size()) {
while (start < segmentPoints[i].size()) {
int r = segmentPoints[i][start].y;
int c = segmentPoints[i][start].x;
if (edgeImg[r*width + c]) break;
start++;
} //end-while
int end = start + 1;
while (end < segmentPoints[i].size()) {
int r = segmentPoints[i][end].y;
int c = segmentPoints[i][end].x;
if (edgeImg[r*width + c] == 0) break;
end++;
} //end-while
int len = end - start;
if (len >= 10) {
// A new segment. Accepted only only long enough (whatever that means)
//segments[noSegments].pixels = &map->segments[i].pixels[start];
//segments[noSegments].noPixels = len;
validSegments.push_back(vector<Point>());
vector<Point> subVec(&segmentPoints[i][start], &segmentPoints[i][end - 1]);
validSegments[noSegments] = subVec;
noSegments++;
} //end-else
start = end + 1;
} //end-while
} //end-for
// Copy to ed
segmentPoints = validSegments;
segmentNos = noSegments;
}
//---------------------------------------------------------------------------
// Number of false alarms code as suggested by Desolneux, Moisan and Morel (DMM)
//
double EDPF::NFA(double prob, int len)
{
double nfa = np;
for (int i = 0; i<len && nfa > EPSILON; i++)
nfa *= prob;
return nfa;
}

@ -0,0 +1,240 @@
#include "NFA.h"
#include <math.h>
#include <float.h>
//Number of False Alarms
NFALUT::NFALUT(int size, double _prob, double _logNT)
{
LUTSize = size;
LUT = new int[LUTSize];
prob = _prob;
logNT = _logNT;
LUT[0] = 1;
int j = 1;
for (int i = 1; i<LUTSize; i++) {
LUT[i] = LUTSize + 1;
double ret = nfa(i, j);
if (ret < 0) {
while (j < i) {
j++;
ret = nfa(i, j);
if (ret >= 0) break;
} //end-while
if (ret < 0) continue;
} //end-if
LUT[i] = j;
} //end-for
}
NFALUT::~NFALUT()
{
delete[] LUT;
}
bool NFALUT::checkValidationByNFA(int n, int k)
{
if (n >= LUTSize)
return nfa(n, k) >= 0.0;
else
return k >= LUT[n];
}
double NFALUT::myAtan2(double yy, double xx)
{
static double LUT[MAX_LUT_SIZE + 1];
static bool tableInited = false;
if (!tableInited) {
for (int i = 0; i <= MAX_LUT_SIZE; i++) {
LUT[i] = atan((double)i / MAX_LUT_SIZE);
} //end-for
tableInited = true;
} //end-if
double y = fabs(yy);
double x = fabs(xx);
bool invert = false;
if (y > x) {
double t = x;
x = y;
y = t;
invert = true;
} //end-if
double ratio;
if (x == 0) // avoid division error
x = 0.000001;
ratio = y / x;
double angle = LUT[(int)(ratio*MAX_LUT_SIZE)];
if (xx >= 0) {
if (yy >= 0) {
// I. quadrant
if (invert) angle = M_PI / 2 - angle;
}
else {
// IV. quadrant
if (invert == false) angle = M_PI - angle;
else angle = M_PI / 2 + angle;
} //end-else
}
else {
if (yy >= 0) {
/// II. quadrant
if (invert == false) angle = M_PI - angle;
else angle = M_PI / 2 + angle;
}
else {
/// III. quadrant
if (invert) angle = M_PI / 2 - angle;
} //end-else
} //end-else
return angle;
}
double NFALUT::nfa(int n, int k)
{
static double inv[TABSIZE]; /* table to keep computed inverse values */
double tolerance = 0.1; /* an error of 10% in the result is accepted */
double log1term, term, bin_term, mult_term, bin_tail, err, p_term;
int i;
/* check parameters */
if (n<0 || k<0 || k>n || prob <= 0.0 || prob >= 1.0) return -1.0;
/* trivial cases */
if (n == 0 || k == 0) return -logNT;
if (n == k) return -logNT - (double)n * log10(prob);
/* probability term */
p_term = prob / (1.0 - prob);
/* compute the first term of the series */
/*
binomial_tail(n,k,p) = sum_{i=k}^n bincoef(n,i) * p^i * (1-p)^{n-i}
where bincoef(n,i) are the binomial coefficients.
But
bincoef(n,k) = gamma(n+1) / ( gamma(k+1) * gamma(n-k+1) ).
We use this to compute the first term. Actually the log of it.
*/
log1term = log_gamma((double)n + 1.0) - log_gamma((double)k + 1.0)
- log_gamma((double)(n - k) + 1.0)
+ (double)k * log(prob) + (double)(n - k) * log(1.0 - prob);
term = exp(log1term);
/* in some cases no more computations are needed */
if (double_equal(term, 0.0)) { /* the first term is almost zero */
if ((double)k > (double)n * prob) /* at begin or end of the tail? */
return -log1term / M_LN10 - logNT; /* end: use just the first term */
else
return -logNT; /* begin: the tail is roughly 1 */
} //end-if
/* compute more terms if needed */
bin_tail = term;
for (i = k + 1; i <= n; i++) {
/*
As
term_i = bincoef(n,i) * p^i * (1-p)^(n-i)
and
bincoef(n,i)/bincoef(n,i-1) = n-1+1 / i,
then,
term_i / term_i-1 = (n-i+1)/i * p/(1-p)
and
term_i = term_i-1 * (n-i+1)/i * p/(1-p).
1/i is stored in a table as they are computed,
because divisions are expensive.
p/(1-p) is computed only once and stored in 'p_term'.
*/
bin_term = (double)(n - i + 1) * (i<TABSIZE ?
(inv[i] != 0.0 ? inv[i] : (inv[i] = 1.0 / (double)i)) :
1.0 / (double)i);
mult_term = bin_term * p_term;
term *= mult_term;
bin_tail += term;
if (bin_term<1.0) {
/* When bin_term<1 then mult_term_j<mult_term_i for j>i.
Then, the error on the binomial tail when truncated at
the i term can be bounded by a geometric series of form
term_i * sum mult_term_i^j. */
err = term * ((1.0 - pow(mult_term, (double)(n - i + 1))) /
(1.0 - mult_term) - 1.0);
/* One wants an error at most of tolerance*final_result, or:
tolerance * abs(-log10(bin_tail)-logNT).
Now, the error that can be accepted on bin_tail is
given by tolerance*final_result divided by the derivative
of -log10(x) when x=bin_tail. that is:
tolerance * abs(-log10(bin_tail)-logNT) / (1/bin_tail)
Finally, we truncate the tail if the error is less than:
tolerance * abs(-log10(bin_tail)-logNT) * bin_tail */
if (err < tolerance * fabs(-log10(bin_tail) - logNT) * bin_tail) break;
} //end-if
} //end-for
return -log10(bin_tail) - logNT;
}
double NFALUT::log_gamma_lanczos(double x)
{
static double q[7] = { 75122.6331530, 80916.6278952, 36308.2951477,
8687.24529705, 1168.92649479, 83.8676043424,
2.50662827511 };
double a = (x + 0.5) * log(x + 5.5) - (x + 5.5);
double b = 0.0;
int n;
for (n = 0; n<7; n++)
{
a -= log(x + (double)n);
b += q[n] * pow(x, (double)n);
}
return a + log(b);
}
double NFALUT::log_gamma_windschitl(double x)
{
return 0.918938533204673 + (x - 0.5)*log(x) - x
+ 0.5*x*log(x*sinh(1 / x) + 1 / (810.0*pow(x, 6.0)));
}
double NFALUT::log_gamma(double x)
{
return x > 15 ? log_gamma_windschitl(x) : log_gamma_lanczos(x);
}
int NFALUT::double_equal(double a, double b)
{
double abs_diff, aa, bb, abs_max;
/* trivial case */
if (a == b) return TRUE;
abs_diff = fabs(a - b);
aa = fabs(a);
bb = fabs(b);
abs_max = aa > bb ? aa : bb;
/* DBL_MIN is the smallest normalized number, thus, the smallest
number whose relative error is bounded by DBL_EPSILON. For
smaller numbers, the same quantization steps as for DBL_MIN
are used. Then, for smaller numbers, a meaningful "relative"
error should be computed by dividing the difference by DBL_MIN. */
if (abs_max < DBL_MIN) abs_max = DBL_MIN;
/* equal if relative error <= factor x eps */
return (abs_diff / abs_max) <= (RELATIVE_ERROR_FACTOR * DBL_EPSILON);
}

@ -1,4 +1,5 @@
#include "CDetectorEngine.h"
#include "../lpCoreCtrl/QFunctionTransfer.h"
LPBENGINE_EXPORT IDetectorEngine* Lib_Engine_Init(void)
{
@ -21,12 +22,15 @@ LPBENGINE_EXPORT void Lib_Engine_Free(IDetectorEngine* ptr)
CDetectorEngine::CDetectorEngine()
{
QFunctionTransfer::Instance();
m_pThreadPool = std::make_shared<ThreadPool>(3);
m_pThreadPool->init();
}
CDetectorEngine::~CDetectorEngine()
{
m_pThreadPool->stop();
m_pThreadPool->wait();
}
IAlgorithmLibMgr* CDetectorEngine::getAlgorithmLibMgr()
@ -41,45 +45,8 @@ IDetectorSolutionMgr* CDetectorEngine::getSolutionMgr()
bool CDetectorEngine::detect(cv::Mat srcImg, QString modeName, AlgResultCallBack func)
{
QVariantMap rltMap;
QTime mTime;
mTime.start();
IDetectorSolution* pSolution = m_SolutionMgr.GetRunSolution();
if (pSolution)
{
IDetectorTask* pTask = pSolution->GetTaskByName(modeName);
if (pTask)
{
pTask->GetTaskInfo()->detectImg = srcImg;
IDetectorAlgorithm* pAlgo = pTask->GetRunAlgo();
if (pAlgo) {
pAlgo->Exec();
QVariantMap map;
QMap<QString, PLP_ALGORITHM_PARAM> mOutParam = pAlgo->GetAllOutParams();
for (QMap<QString, PLP_ALGORITHM_PARAM>::iterator it = mOutParam.begin(); it != mOutParam.end(); it++)
{
PLP_ALGORITHM_PARAM pOutparam = *it;
if (pOutparam)
{
map.insert(pOutparam->strName, pOutparam->value);
}
}
rltMap.insert("AlgoResult", map);
rltMap.insert("taskName", pTask->GetTaskName());
rltMap.insert("taskID", pTask->GetID());
rltMap.insert("originImage", EngineBase::convMat2QImage(srcImg));
}
}
}
int nTime = mTime.elapsed();
rltMap.insert("tasktime", nTime*1.0/1000);
if (func)
{
func(rltMap);
}
Task task = std::bind(&CDetectorEngine::detectFunc, this, srcImg.clone(), modeName, func);
m_pThreadPool->AddNewTask(task);//将需要检测的图像和参数输入到线程池中 线程内执行算法
return false;
}
@ -124,6 +91,51 @@ bool CDetectorEngine::CheckConfigFolder()
return true;
}
void CDetectorEngine::detectFunc(cv::Mat srcImg, QString modeName, AlgResultCallBack func)
{
QVariantMap rltMap;
QTime mTime;
mTime.start();
IDetectorSolution* pSolution = m_SolutionMgr.GetRunSolution();
if (pSolution)
{
IDetectorTask* pTask = pSolution->GetTaskByName(modeName);
if (pTask)
{
pTask->GetTaskInfo()->detectImg = srcImg;
IDetectorAlgorithm* pAlgo = pTask->GetRunAlgo();
if (pAlgo) {
pAlgo->Exec();
QVariantMap map;
QMap<QString, PLP_ALGORITHM_PARAM> mOutParam = pAlgo->GetAllOutParams();
for (QMap<QString, PLP_ALGORITHM_PARAM>::iterator it = mOutParam.begin(); it != mOutParam.end(); it++)
{
PLP_ALGORITHM_PARAM pOutparam = *it;
if (pOutparam)
{
map.insert(pOutparam->strName, pOutparam->value);
}
}
rltMap.insert("AlgoResult", map);
rltMap.insert("taskName", pTask->GetTaskName());
rltMap.insert("taskID", pTask->GetID());
rltMap.insert("originImage", EngineBase::convMat2QImage(srcImg));
}
}
}
int nTime = mTime.elapsed();
rltMap.insert("tasktime", nTime*1.0 / 1000);
if (func)//算法结果输出
{
QFunctionTransfer::Instance()->execInMain([this, rltMap, func]() {
if(func)
func(rltMap);
});
}
}
bool CDetectorEngine::Initialize()
{
if (!m_SolutionMgr.Initialize(&m_AlgoLibMgr))

@ -4,7 +4,8 @@
#include "lpbengine.h"
#include "SolutionMgr.h"
#include "AlgorithmLibMgr.h"
#include "ThreadPool.hpp"
#include "threadsafe_list.hpp"
class CDetectorEngine:public IDetectorEngine
{
public:
@ -19,9 +20,13 @@ public:
virtual bool Load();
bool CheckConfigFolder();
void detectFunc(cv::Mat srcImg, QString modeName, AlgResultCallBack func);
private:
CDetectorSolutionMgr m_SolutionMgr;
CAlgorithmLibMgr m_AlgoLibMgr;
std::shared_ptr<ThreadPool> m_pThreadPool;
};
#endif // BUSINESSENGINE_H

@ -0,0 +1,32 @@
#ifndef _H_QFUNCTIONTRANSFER_H_
#define _H_QFUNCTIONTRANSFER_H_
#include <QObject>
#include <functional>
class QFunctionTransfer : public QObject
{
Q_OBJECT
public:
explicit QFunctionTransfer(QObject *parent = 0) {
qRegisterMetaType<std::tr1::function<void()>>("std::tr1::function<void()>");
connect(this, &QFunctionTransfer::comming, this, &QFunctionTransfer::exec, Qt::QueuedConnection);
};
void execInMain(std::tr1::function<void()> f) {
emit this->comming(f);
};
static QFunctionTransfer* Instance() {
static QFunctionTransfer ins;
return &ins;
}
signals:
void comming(std::tr1::function<void()> f);
public slots:
void exec(std::tr1::function<void()> f)
{
f();
};
};
#endif

@ -0,0 +1,136 @@
/*!
* \file ThreadPool.hpp
* \date 2018/11/30
*
* \author pan yingdong
* Contact: bob.pan@hzleaper.com
*
*
* \note
*/
#ifndef _STREAMTHREAD_H_
#define _STREAMTHREAD_H_
#include <iostream>
//#include <queue>
#include <list>
#include <functional>
#include <condition_variable>
#include "threadsafe_list.hpp"
#include "thread_group.hpp"
typedef std::function<void(void)> Task;
template<typename T>
class TaskList
{
private:
std::list<T> m_taskList;
std::mutex m_mutex;
std::condition_variable_any m_cond;
int m_maxSize{ 10 };
public:
void ProcFun() {};
void setMaxSize(int size = 10) {
m_maxSize = size;
}
bool push_back(const T& task) {
if (getSize() >= m_maxSize)
return false;
std::unique_lock<std::mutex> lock(m_mutex);
m_taskList.push_back(task);
m_cond.notify_one();
return true;
}
bool pop_front(T& value) {
std::unique_lock<std::mutex> lock(m_mutex);
if (m_taskList.size() <= 0)
{
return false;
}
value = m_taskList.front();
m_taskList.pop_front();
return true;
}
T pop_front() {
std::unique_lock<std::mutex> lock(m_mutex);
if(m_taskList.size()<=0)
{
m_cond.wait(lock);
}
try {
T task = m_taskList.front();
m_taskList.pop_front();
return task;
}
catch (std::exception &e) {
std::cout << "pop task error" << std::endl;
}
T task = std::bind(&TaskList::ProcFun, this);
return task;
}
int getSize()
{
std::unique_lock<std::mutex> lock(m_mutex);
return m_taskList.size();
}
};
class ThreadPool
{
private:
TaskList<Task> m_taskList;
std::thread_group m_threadGroup;
int m_threadNum;
volatile bool is_run;
void run() {
while (is_run) {
if (m_taskList.getSize() > 0)
{
Task task;
if(m_taskList.pop_front(task))
task();
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
}
std::cout << "threadpool run finish" << std::endl;
}
public:
ThreadPool(int num) :m_threadNum(num), is_run(false)//
{
}
~ThreadPool() {
stop();
}
void init()
{
if (m_threadNum <= 0)
return;
is_run = true;
for (int i = 0; i < m_threadNum; i++)
{
m_threadGroup.add_thread(new std::thread(&ThreadPool::run, this));
}
}
void stop()
{
is_run = false;
}
bool AddNewTask(const Task& task) {
m_taskList.push_back(task);
return true;
}
void SetMaxSize(int size) {
m_taskList.setMaxSize(size);
}
void wait()
{
m_threadGroup.join_all();
}
};
#endif

@ -0,0 +1,77 @@
#ifndef __THREAD_GROUP__
#define __THREAD_GROUP__
#include <thread>
#include <mutex>
#include <list>
#include <memory>
namespace std
{
//兼容boost::thread_group
//使用std::thread代替boost::thread,std::mutex代替boost::shared_mutex
class thread_group
{
private:
thread_group(thread_group const&);
thread_group& operator=(thread_group const&);
public:
thread_group() {}
~thread_group()
{
for (auto it = threads.begin(), end = threads.end(); it != end; ++it)
{
delete *it;
}
}
template<typename F>
std::thread* create_thread(F threadfunc)
{
std::lock_guard<std::mutex> guard(m);
std::auto_ptr<std::thread> new_thread(new std::thread(threadfunc));
threads.push_back(new_thread.get());
return new_thread.release();
}
void add_thread(std::thread* thrd)
{
if (thrd)
{
std::lock_guard<std::mutex> guard(m);
threads.push_back(thrd);
}
}
void remove_thread(std::thread* thrd)
{
std::lock_guard<std::mutex> guard(m);
auto it = std::find(threads.begin(), threads.end(), thrd);
if (it != threads.end())
{
threads.erase(it);
}
}
void join_all()
{
std::lock_guard<std::mutex> guard(m);
for (auto it = threads.begin(), end = threads.end(); it != end; ++it)
{
(*it)->join();
}
}
size_t size() const
{
std::lock_guard<std::mutex> guard(m);
return threads.size();
}
private:
std::list<std::thread*> threads;
mutable std::mutex m;
};
}
#endif

@ -0,0 +1,81 @@
/*!
* \file threadsafe_list.hpp
* \date 2018/11/30
*
* \author pan yingdong
* Contact: bob.pan@hzleaper.com
*
*
* \note
*/
#ifndef _THREADSAFE_LIST_H_
#define _THREADSAFE_LIST_H_
#include <exception>
#include <memory>
#include <list>
#include <mutex>
#include <iostream>
struct empty_list :std::exception
{
const char* what() const throw(){ return "empty list"; };
};
template<typename T>
class threadsafe_list
{
private:
std::list<T> dataList;
mutable std::mutex m;
public:
threadsafe_list(){}
threadsafe_list(const threadsafe_list& other)
{
std::lock_guard<std::mutex> guard(m);
dataList = other.dataList;
}
threadsafe_list& operator=(const threadsafe_list&) = delete;
bool push_back(T new_val)
{
std::lock_guard<std::mutex> guard(m);
dataList.push_back(new_val);
return true;
}
std::shared_ptr<T> pop_front()
{
std::lock_guard<std::mutex> guard(m);
if (dataList.empty())
throw empty_list();
std::shared_ptr<T> const res(std::make_shared<T>(dataList.front()));
dataList.pop_front();
return res;
}
bool pop_front(T& value)
{
std::lock_guard<std::mutex> guard(m);
if (dataList.empty())
{
//throw empty_list();
return false;
}
value = dataList.front();
dataList.pop_front();
return true;
}
bool empty() const
{
std::lock_guard<std::mutex> guard(m);
return dataList.empty();
}
int getSize() const
{
std::lock_guard<std::mutex> guard(m);
return dataList.size();
}
void clear() {
std::lock_guard<std::mutex> guard(m);
dataList.clear();
}
};
#endif

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.1585
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EDCircle", "EDCircle\EDCircle.vcxproj", "{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}.Debug|x64.ActiveCfg = Debug|x64
{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}.Debug|x64.Build.0 = Debug|x64
{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}.Debug|x86.ActiveCfg = Debug|Win32
{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}.Debug|x86.Build.0 = Debug|Win32
{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}.Release|x64.ActiveCfg = Release|x64
{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}.Release|x64.Build.0 = Release|x64
{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}.Release|x86.ActiveCfg = Release|Win32
{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B16A4A2-41EE-451E-AF3C-8975C25052BF}
EndGlobalSection
EndGlobal

@ -0,0 +1,201 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\edcircle\include\ED.h" />
<ClInclude Include="..\..\src\edcircle\include\EDCircles.h" />
<ClInclude Include="..\..\src\edcircle\include\EDColor.h" />
<ClInclude Include="..\..\src\edcircle\include\EDLines.h" />
<ClInclude Include="..\..\src\edcircle\include\EDPF.h" />
<ClInclude Include="..\..\src\edcircle\include\NFA.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\edcircle\src\ED.cpp" />
<ClCompile Include="..\..\src\edcircle\src\EDCircles.cpp" />
<ClCompile Include="..\..\src\edcircle\src\EDColor.cpp" />
<ClCompile Include="..\..\src\edcircle\src\EDLines.cpp" />
<ClCompile Include="..\..\src\edcircle\src\EDPF.cpp" />
<ClCompile Include="..\..\src\edcircle\src\NFA.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{1892193F-B7A3-4A27-AC59-FF7F261DBBD5}</ProjectGuid>
<Keyword>Qt4VSv1.0</Keyword>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">
<QtMsBuild>$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<TargetName>$(ProjectName)d</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
</Target>
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
<Import Project="$(QtMsBuild)\qt.props" />
</ImportGroup>
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="Shared" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>UNICODE;WIN32;WIN64;QT_CORE_LIB;EDCIRCLE_LIB;BUILD_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;.\include;.\src;.\..\..\lpopencv\build\include;.\..\..\lpopencv\build\include\opencv;.\..\..\lpopencv\build\include\opencv2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).lib</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>qtmaind.lib;Qt5Cored.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<QtMoc>
<Define>UNICODE;WIN32;WIN64;QT_CORE_LIB;EDCIRCLE_LIB;BUILD_STATIC;%(PreprocessorDefinitions)</Define>
<IncludePath>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;.\include;.\src;.\..\..\lpopencv\build\include;.\..\..\lpopencv\build\include\opencv;.\..\..\lpopencv\build\include\opencv2;%(AdditionalIncludeDirectories)</IncludePath>
</QtMoc>
<Lib>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>UNICODE;WIN32;WIN64;QT_CORE_LIB;EDCIRCLE_LIB;BUILD_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;.\..\..\src\edcircle\include;.\..\..\src\edcircle\src;.\..\..\3part\opencv3.4.1\include;.\..\..\3part\opencv3.4.1\include\opencv;.\..\..\3part\opencv3.4.1\include\opencv2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).lib</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>qtmaind.lib;Qt5Cored.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<QtMoc>
<Define>UNICODE;WIN32;WIN64;QT_CORE_LIB;EDCIRCLE_LIB;BUILD_STATIC;%(PreprocessorDefinitions)</Define>
<IncludePath>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;.\..\..\src\edcircle\include;.\..\..\src\edcircle\src;.\..\..\3part\opencv3.4.1\include;.\..\..\3part\opencv3.4.1\include\opencv;.\..\..\3part\opencv3.4.1\include\opencv2;%(AdditionalIncludeDirectories)</IncludePath>
</QtMoc>
<Lib>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;EDCIRCLE_LIB;BUILD_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;.\include;.\src;.\..\..\lpopencv\openCV2.4.9\build\include;.\..\..\lpopencv\openCV2.4.9\build\include\opencv;.\..\..\lpopencv\openCV2.4.9\build\include\opencv2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat />
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).lib</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>qtmain.lib;Qt5Core.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<QtMoc>
<Define>UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;EDCIRCLE_LIB;BUILD_STATIC;%(PreprocessorDefinitions)</Define>
<IncludePath>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;.\include;.\src;.\..\..\lpopencv\openCV2.4.9\build\include;.\..\..\lpopencv\openCV2.4.9\build\include\opencv;.\..\..\lpopencv\openCV2.4.9\build\include\opencv2;%(AdditionalIncludeDirectories)</IncludePath>
</QtMoc>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;EDCIRCLE_LIB;BUILD_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;.\..\..\src\edcircle\include;.\..\..\src\edcircle\src;.\..\..\3part\opencv3.4.1\include;.\..\..\3part\opencv3.4.1\include\opencv;.\..\..\3part\opencv3.4.1\include\opencv2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>
</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).lib</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>qtmain.lib;Qt5Core.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<QtMoc>
<Define>UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;EDCIRCLE_LIB;BUILD_STATIC;%(PreprocessorDefinitions)</Define>
<IncludePath>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;.\..\..\src\edcircle\include;.\..\..\src\edcircle\src;.\..\..\3part\opencv3.4.1\include;.\..\..\3part\opencv3.4.1\include\opencv;.\..\..\3part\opencv3.4.1\include\opencv2;%(AdditionalIncludeDirectories)</IncludePath>
</QtMoc>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
<Import Project="$(QtMsBuild)\qt.targets" />
</ImportGroup>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties MocDir=".\GeneratedFiles\$(ConfigurationName)" UicDir=".\GeneratedFiles" RccDir=".\GeneratedFiles" lupdateOptions="" lupdateOnBuild="0" lreleaseOptions="" Qt5Version_x0020_Win32="qt5.4.2-msvc2013-x86" Qt5Version_x0020_x64="qt5.9.4-msvc2017-x64" MocOptions="" />
</VisualStudio>
</ProjectExtensions>
</Project>

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
<Extensions>qrc;*</Extensions>
<ParseFiles>false</ParseFiles>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
<Extensions>qrc;*</Extensions>
<ParseFiles>false</ParseFiles>
</Filter>
<Filter Include="Generated Files">
<UniqueIdentifier>{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}</UniqueIdentifier>
<Extensions>moc;h;cpp</Extensions>
<SourceControlFiles>False</SourceControlFiles>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\edcircle\include\ED.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\edcircle\include\EDCircles.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\edcircle\include\EDColor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\edcircle\include\EDLines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\edcircle\include\EDPF.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\edcircle\include\NFA.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\edcircle\src\ED.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\edcircle\src\EDCircles.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\edcircle\src\EDColor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\edcircle\src\EDLines.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\edcircle\src\EDPF.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\edcircle\src\NFA.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

@ -0,0 +1,92 @@
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/opencv_modules.hpp>
#include "ED.h"
#include "EDLines.h"
#include "EDCircles.h"
#include <windows.h>
#include "core.hpp"
using namespace std;
using namespace cv;
int main()
{
Mat SrcImg = imread("F:\\LeaperProject\\1EDCircle\\Source\\NG_223_79_041835877.png", 1); //要注意读入图片的通道数量
if (SrcImg.empty())//要判断是否读取成功
{
printf("Could not load image.");
return -1;
}
if (SrcImg.channels() != 1)//转成灰度图,确保是一张灰度图
cvtColor(SrcImg, SrcImg, COLOR_BGR2GRAY);
int Channel = SrcImg.channels();//当前一个像素是几个通道(字节)
resize(SrcImg, SrcImg,Size(SrcImg.cols / 2,SrcImg.rows/2));
cv::Scalar mu, sigma;
cv::meanStdDev(SrcImg, mu, sigma);
double val = mu.val[0];
double rate = (100 - val)*2.0 / 100;
SrcImg = SrcImg + 1.5 * SrcImg;
cv::meanStdDev(SrcImg, mu, sigma);
double val2 = mu.val[0];
blur(SrcImg, SrcImg, Size(3,3));
// DWORD start_time1 = GetTickCount();
// vector<Vec3f> HoughCircle;
// HoughCircles(SrcImg, HoughCircle, HOUGH_GRADIENT, 1, 50, 150, 120, 0,0);
// DWORD end_time1 = GetTickCount();
// cout << "The HoughCircle run time is:" << (end_time1 - start_time1) << "ms!" << endl;//输出运行时间
// Mat HoughCircleImg(SrcImg.size(), CV_8UC(Channel), Scalar(0));//定义一张画布,用于画圆,颜色初始化为黑
// for (int i = 0; i < HoughCircle.size(); i++)
// {
// Point center(round(HoughCircle[i][0]), round(HoughCircle[i][1]));//提取出圆心坐标
// int radius = round(HoughCircle[i][2]); //提取出圆半径
// circle(HoughCircleImg, center, radius, Scalar(255));
//
// Mat cutMat = SrcImg(Rect(center.x - radius, center.y - radius, 2 * radius, 2 * radius));
// if (cutMat.data != NULL)
// {
// namedWindow("CutImg", WINDOW_AUTOSIZE);
// imshow("CutImg", cutMat);
// }
//
// }
//
// namedWindow("HoughCircleImg", WINDOW_AUTOSIZE);
// imshow("HoughCircleImg", HoughCircleImg);
DWORD start_time2 = GetTickCount();
EDCircles edcircles(SrcImg);
DWORD end_time2 = GetTickCount();
cout << "The EDCircle run time is:" << (end_time2 - start_time2) << "ms!" << endl;//输出运行时间
vector<mCircle> EDCircle = edcircles.getCircles();
Mat EDCircleImg(SrcImg.size(), CV_8UC(Channel),Scalar(0));//定义一张画布,用于画圆,颜色初始化为黑
double maxR = 0;
int nIndex = -1;
for (int i = 0; i < EDCircle.size(); i++)
{
if (EDCircle[i].r > maxR)
{
maxR = EDCircle[i].r;
nIndex = i;
}
circle(EDCircleImg, EDCircle[i].center, EDCircle[i].r, Scalar(255));
}
if (nIndex != -1)
{
Mat cutMat = SrcImg(Rect(EDCircle[nIndex].center.x - EDCircle[nIndex].r, EDCircle[nIndex].center.y - EDCircle[nIndex].r, 2 * EDCircle[nIndex].r, 2 * EDCircle[nIndex].r));
if (cutMat.data != NULL)
{
namedWindow("CutImg", WINDOW_AUTOSIZE);
imshow("CutImg", cutMat);
}
}
namedWindow("EDCircleImg", WINDOW_AUTOSIZE);
imshow("EDCircleImg", EDCircleImg);
waitKey(0);
}

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{4FDC5305-11FB-496A-BEBE-828569051007}</ProjectGuid>
<RootNamespace>My1EDCircle</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>.\..\..\..\lpopencv\build\include;.\..\..\..\lpopencv\build\include\opencv;.\..\..\..\lpopencv\build\include\opencv2;F:\LeaperProject\1EDCircle\srccode\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>.\..\..\..\lpopencv\build\x64\vc15\lib;F:\LeaperProject\1EDCircle\tp_2017\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opencv_world341d.lib;EDCircled.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>.\..\..\lpopencv\build\include;.\..\..\lpopencv\build\include\opencv;.\..\..\lpopencv\build\include\opencv2;.\..\EDCircle\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>opencv_world341.lib;EDCircle.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>.\..\..\lpopencv\build\x64\vc15\lib;.\..\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="1_EDCircle.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="1_EDCircle.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
</Project>

@ -390,6 +390,34 @@
<ClCompile Include="..\..\src\lpbengine\Solution.cpp" />
<ClCompile Include="..\..\src\lpbengine\SolutionMgr.cpp" />
<ClCompile Include="..\..\src\lpbengine\Task.cpp" />
<ClCompile Include="GeneratedFiles\Debug\moc_QFunctionTransfer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_QFunctionTransfer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\lpbengine\QFunctionTransfer.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_CORE_LIB -DLPBENGINE_LIB -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I.\..\..\include" "-I.\..\..\..\Colossus\include\base" "-I.\..\..\..\Colossus\include\lpbengine" "-I.\..\..\..\opencv2.4.9\include" "-I.\..\..\..\opencv2.4.9\include\opencv" "-I.\..\..\..\opencv2.4.9\include\opencv2"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_CORE_LIB -DLPBENGINE_LIB -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I.\..\..\include" "-I.\..\..\..\Colossus\include\base" "-I.\..\..\..\Colossus\include\lpbengine" "-I.\..\..\3part\opencv3.4.1\include" "-I.\..\..\3part\opencv3.4.1\include\opencv" "-I.\..\..\3part\opencv3.4.1\include\opencv2" "-I.\..\..\3part\tadpole\include\tpBase" "-ID:\Valve\3part\tadpole\include\tpBase"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DLPBENGINE_LIB -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I.\..\..\include" "-I.\..\..\..\Colossus\include\base" "-I.\..\..\..\Colossus\include\lpbengine" "-I.\..\..\..\opencv2.4.9\include" "-I.\..\..\..\opencv2.4.9\include\opencv" "-I.\..\..\..\opencv2.4.9\include\opencv2"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DLPBENGINE_LIB -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I.\..\..\include" "-I.\..\..\..\Colossus\include\base" "-I.\..\..\..\Colossus\include\lpbengine" "-I.\..\..\3part\opencv3.4.1\include" "-I.\..\..\3part\opencv3.4.1\include\opencv" "-I.\..\..\3part\opencv3.4.1\include\opencv2" "-I.\..\..\3part\tadpole\include\tpBase" "-ID:\Valve\3part\tadpole\include\tpBase"</Command>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

@ -52,6 +52,12 @@
<ClCompile Include="..\..\src\lpbengine\CDetectorEngine.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_QFunctionTransfer.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_QFunctionTransfer.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\lpbengine\Roi.h">
@ -78,5 +84,8 @@
<CustomBuild Include="..\..\src\lpbengine\CDetectorEngine.h">
<Filter>Header Files</Filter>
</CustomBuild>
<CustomBuild Include="..\..\src\lpbengine\QFunctionTransfer.h">
<Filter>Header Files</Filter>
</CustomBuild>
</ItemGroup>
</Project>

@ -11,7 +11,12 @@ QPLCDevice::QPLCDevice(QObject *parent)
QPLCDevice::~QPLCDevice()
{
if (m_pTask)
{
m_pTask->EndThread();
delete m_pTask;
m_pTask = nullptr;
}
}
void QPLCDevice::onInitDevice()

@ -39,17 +39,16 @@ QSystemSettingDlg::QSystemSettingDlg(QWidget *parent)
readSettingFile();
m_listwidgetItemStr.append(tr("相关设备配置"));
m_listwidgetItemStr.append(tr("检测图像设置"));
m_listwidgetItemStr.append(tr("PLC相关设置"));
m_listwidgetItemStr.append(tr("报警灯测试"));
//m_listwidgetItemStr.append(tr("PLC相关设置"));
m_listwidgetItemStr.append(tr("高级功能"));
{
InitTreeWidget(ui.treeWidget);
addComRoot(ui.treeWidget, m_listwidgetItemStr.at(0));//相关设备配置
addPicRoot(ui.treeWidget, m_listwidgetItemStr.at(1));//检测图像设置
addPLCRoot(ui.treeWidget, m_listwidgetItemStr.at(2));//PLC相关设置
addLightRoot(ui.treeWidget, m_listwidgetItemStr.at(3));//报警灯测试
//addPLCRoot(ui.treeWidget, m_listwidgetItemStr.at(2));//PLC相关设置
//addLightRoot(ui.treeWidget, m_listwidgetItemStr.at(3));//报警灯测试
ui.treeWidget->expandAll();
addSuperRoot(ui.treeWidget, m_listwidgetItemStr.at(4));//高级功能
addSuperRoot(ui.treeWidget, m_listwidgetItemStr.at(2));//高级功能
}
{
@ -64,7 +63,6 @@ QSystemSettingDlg::QSystemSettingDlg(QWidget *parent)
}
connect(ui.listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(onSetCurrentIndex(int)));
}
}
QSystemSettingDlg::~QSystemSettingDlg()
@ -99,11 +97,6 @@ QSystemSettingDlg::~QSystemSettingDlg()
delete pItem;
pItem = NULL;
}
// for (QMap<QString, class QTreeWidgetItem *>::iterator its = m_TreeItemMap.begin(); its != m_TreeItemMap.end(); ++its)
// {
// delete *its;
// *its = NULL;
// }
m_TreeItemMap.clear();
for (int nIndex = 0; nIndex < m_listObj.size(); nIndex++) {
QObject* p = m_listObj.at(nIndex);
@ -128,22 +121,22 @@ void QSystemSettingDlg::onShowWidget(int nLevel)
{
if (nLevel == 9 || DetectState::instance()->m_Debug == 100) {
HidPLCUI(false);
//HidPLCUI(false);
HidDevelopUI(false);
}
else if (nLevel == 5) {
HidDevelopUI(true);
HidPLCUI(true);
//HidPLCUI(true);
}
else if (nLevel == 4) {
ui.treeWidget->setItemHidden(picitems.at(7), true);
HidDevelopUI(true);
HidPLCUI(true);
//HidPLCUI(true);
}
else {
HidDevelopUI(true);
HidPLCUI(true);
//HidPLCUI(true);
}
ui.listWidget->setCurrentRow(0);
}

@ -23,9 +23,9 @@
#include <QProcess>
#include "databasesql.h"
#define VERSION_HUB "3.0.0.2"
#define VERSION_ALG "3.0.0.2"
#define UPDATE_TIME "2021-05-08"
#define VERSION_HUB "3.0.1.2"
#define VERSION_ALG "3.0.1.2"
#define UPDATE_TIME "2021-09-08"
#pragma execution_character_set("utf-8")
@ -1858,7 +1858,6 @@ void lpMainWin::saveImage(Result2Ui* pRes)
void lpMainWin::saveImage(const QPixmap& m_pixmap, QString m_path, QString filename)
{//启动多线程保存图像
return;
SaveImgThread *workTread = new SaveImgThread(this);
workTread->setPixmap(m_pixmap, m_path, filename);
connect(workTread, &SaveImgThread::finished, workTread, &QObject::deleteLater);
@ -1994,7 +1993,6 @@ Q_SLOT void lpMainWin::onSlotDelOldModel(QString strName)
*/
void lpMainWin::onSaveValveResult(ValueResult &rlt)
{
return;
QString strModeName = rlt.strModel;//型号名
QDir testDir;
bool IsTestDir = testDir.exists(DetectState::instance()->m_SaveImgDirPath);

Loading…
Cancel
Save