|
|
|
@ -69,12 +69,6 @@ const double DEG_TO_RADS = CV_PI / 180; |
|
|
|
|
|
|
|
|
|
#define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x)) |
|
|
|
|
|
|
|
|
|
struct edge |
|
|
|
|
{ |
|
|
|
|
cv::Point p; |
|
|
|
|
bool taken; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
inline double distSq(const double x1, const double y1, |
|
|
|
@ -120,10 +114,20 @@ inline bool double_equal(const double& a, const double& b) |
|
|
|
|
return (abs_diff / abs_max) <= (RELATIVE_ERROR_FACTOR * DBL_EPSILON); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline bool AsmallerB_XoverY(const edge& a, const edge& b) |
|
|
|
|
{ |
|
|
|
|
if (a.p.x == b.p.x) return a.p.y < b.p.y; |
|
|
|
|
else return a.p.x < b.p.x; |
|
|
|
|
// function to sort points by y and then by x
|
|
|
|
|
inline bool AsmallerB_YoverX(const cv::Point2d &a, const cv::Point2d &b) { |
|
|
|
|
if (a.y == b.y) return a.x < b.x; |
|
|
|
|
else return a.y < b.y; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// function to get the slope of the rectangle for a specific row
|
|
|
|
|
inline double get_slope(cv::Point2d p1, cv::Point2d p2) { |
|
|
|
|
return ((int) ceil(p2.y) != (int) ceil(p1.y)) ? (p2.x - p1.x) / (p2.y - p1.y) : 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// function to get the limit of the rectangle for a specific row
|
|
|
|
|
inline double get_limit(cv::Point2d p, int row, double slope) { |
|
|
|
|
return p.x + (row - p.y) * slope; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -945,105 +949,53 @@ double LineSegmentDetectorImpl::rect_nfa(const rect& rec) const |
|
|
|
|
double dyhw = rec.dy * half_width; |
|
|
|
|
double dxhw = rec.dx * half_width; |
|
|
|
|
|
|
|
|
|
edge ordered_x[4]; |
|
|
|
|
edge* min_y = &ordered_x[0]; |
|
|
|
|
edge* max_y = &ordered_x[0]; // Will be used for loop range
|
|
|
|
|
|
|
|
|
|
ordered_x[0].p.x = int(rec.x1 - dyhw); ordered_x[0].p.y = int(rec.y1 + dxhw); ordered_x[0].taken = false; |
|
|
|
|
ordered_x[1].p.x = int(rec.x2 - dyhw); ordered_x[1].p.y = int(rec.y2 + dxhw); ordered_x[1].taken = false; |
|
|
|
|
ordered_x[2].p.x = int(rec.x2 + dyhw); ordered_x[2].p.y = int(rec.y2 - dxhw); ordered_x[2].taken = false; |
|
|
|
|
ordered_x[3].p.x = int(rec.x1 + dyhw); ordered_x[3].p.y = int(rec.y1 - dxhw); ordered_x[3].taken = false; |
|
|
|
|
|
|
|
|
|
std::sort(ordered_x, ordered_x + 4, AsmallerB_XoverY); |
|
|
|
|
|
|
|
|
|
// Find min y. And mark as taken. find max y.
|
|
|
|
|
for(unsigned int i = 1; i < 4; ++i) |
|
|
|
|
{ |
|
|
|
|
if(min_y->p.y > ordered_x[i].p.y) {min_y = &ordered_x[i]; } |
|
|
|
|
if(max_y->p.y < ordered_x[i].p.y) {max_y = &ordered_x[i]; } |
|
|
|
|
} |
|
|
|
|
min_y->taken = true; |
|
|
|
|
|
|
|
|
|
// Find leftmost untaken point;
|
|
|
|
|
edge* leftmost = 0; |
|
|
|
|
for(unsigned int i = 0; i < 4; ++i) |
|
|
|
|
{ |
|
|
|
|
if(!ordered_x[i].taken) |
|
|
|
|
{ |
|
|
|
|
if(!leftmost) // if uninitialized
|
|
|
|
|
{ |
|
|
|
|
leftmost = &ordered_x[i]; |
|
|
|
|
} |
|
|
|
|
else if (leftmost->p.x > ordered_x[i].p.x) |
|
|
|
|
{ |
|
|
|
|
leftmost = &ordered_x[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
CV_Assert(leftmost != NULL); |
|
|
|
|
leftmost->taken = true; |
|
|
|
|
|
|
|
|
|
// Find rightmost untaken point;
|
|
|
|
|
edge* rightmost = 0; |
|
|
|
|
for(unsigned int i = 0; i < 4; ++i) |
|
|
|
|
{ |
|
|
|
|
if(!ordered_x[i].taken) |
|
|
|
|
{ |
|
|
|
|
if(!rightmost) // if uninitialized
|
|
|
|
|
{ |
|
|
|
|
rightmost = &ordered_x[i]; |
|
|
|
|
} |
|
|
|
|
else if (rightmost->p.x < ordered_x[i].p.x) |
|
|
|
|
{ |
|
|
|
|
rightmost = &ordered_x[i]; |
|
|
|
|
} |
|
|
|
|
cv::Point2d v_tmp[4]; |
|
|
|
|
v_tmp[0] = cv::Point2d(rec.x1 - dyhw, rec.y1 + dxhw); |
|
|
|
|
v_tmp[1] = cv::Point2d(rec.x2 - dyhw, rec.y2 + dxhw); |
|
|
|
|
v_tmp[2] = cv::Point2d(rec.x2 + dyhw, rec.y2 - dxhw); |
|
|
|
|
v_tmp[3] = cv::Point2d(rec.x1 + dyhw, rec.y1 - dxhw); |
|
|
|
|
|
|
|
|
|
// Find the vertex with the smallest y coordinate (or the smallest x if there is a tie).
|
|
|
|
|
int offset = 0; |
|
|
|
|
for (int i = 1; i < 4; ++i) { |
|
|
|
|
if (AsmallerB_YoverX(v_tmp[i], v_tmp[offset])){ |
|
|
|
|
offset = i; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
CV_Assert(rightmost != NULL); |
|
|
|
|
rightmost->taken = true; |
|
|
|
|
|
|
|
|
|
// Find last untaken point;
|
|
|
|
|
edge* tailp = 0; |
|
|
|
|
for(unsigned int i = 0; i < 4; ++i) |
|
|
|
|
{ |
|
|
|
|
if(!ordered_x[i].taken) |
|
|
|
|
{ |
|
|
|
|
if(!tailp) // if uninitialized
|
|
|
|
|
{ |
|
|
|
|
tailp = &ordered_x[i]; |
|
|
|
|
} |
|
|
|
|
else if (tailp->p.x > ordered_x[i].p.x) |
|
|
|
|
{ |
|
|
|
|
tailp = &ordered_x[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Rotate the vertices so that the first one is the one with the smallest y coordinate (or the smallest x if there is a tie).
|
|
|
|
|
// The rest will be then ordered counterclockwise.
|
|
|
|
|
cv::Point2d ordered_y[4]; |
|
|
|
|
for (int i = 0; i < 4; ++i) { |
|
|
|
|
ordered_y[i] = v_tmp[(i + offset) % 4]; |
|
|
|
|
} |
|
|
|
|
CV_Assert(tailp != NULL); |
|
|
|
|
tailp->taken = true; |
|
|
|
|
|
|
|
|
|
double flstep = (min_y->p.y != leftmost->p.y) ? |
|
|
|
|
(min_y->p.x - leftmost->p.x) / (min_y->p.y - leftmost->p.y) : 0; //first left step
|
|
|
|
|
double slstep = (leftmost->p.y != tailp->p.x) ? |
|
|
|
|
(leftmost->p.x - tailp->p.x) / (leftmost->p.y - tailp->p.x) : 0; //second left step
|
|
|
|
|
|
|
|
|
|
double frstep = (min_y->p.y != rightmost->p.y) ? |
|
|
|
|
(min_y->p.x - rightmost->p.x) / (min_y->p.y - rightmost->p.y) : 0; //first right step
|
|
|
|
|
double srstep = (rightmost->p.y != tailp->p.x) ? |
|
|
|
|
(rightmost->p.x - tailp->p.x) / (rightmost->p.y - tailp->p.x) : 0; //second right step
|
|
|
|
|
double flstep = get_slope(ordered_y[0], ordered_y[1]); //first left step
|
|
|
|
|
double slstep = get_slope(ordered_y[1], ordered_y[2]); //second left step
|
|
|
|
|
|
|
|
|
|
double lstep = flstep, rstep = frstep; |
|
|
|
|
double frstep = get_slope(ordered_y[0], ordered_y[3]); //first right step
|
|
|
|
|
double srstep = get_slope(ordered_y[3], ordered_y[2]); //second right step
|
|
|
|
|
|
|
|
|
|
double left_x = min_y->p.x, right_x = min_y->p.x; |
|
|
|
|
double top_y = ordered_y[0].y, bottom_y = ordered_y[2].y; |
|
|
|
|
|
|
|
|
|
// Loop around all points in the region and count those that are aligned.
|
|
|
|
|
int min_iter = min_y->p.y; |
|
|
|
|
int max_iter = max_y->p.y; |
|
|
|
|
for(int y = min_iter; y <= max_iter; ++y) |
|
|
|
|
std::vector<cv::Point> points; |
|
|
|
|
double left_limit, right_limit; |
|
|
|
|
for(int y = (int) ceil(top_y); y <= (int) ceil(bottom_y); ++y) |
|
|
|
|
{ |
|
|
|
|
if (y < 0 || y >= img_height) continue; |
|
|
|
|
|
|
|
|
|
for(int x = int(left_x); x <= int(right_x); ++x) |
|
|
|
|
{ |
|
|
|
|
if(y <= int(ceil(ordered_y[1].y))) |
|
|
|
|
left_limit = get_limit(ordered_y[0], y, flstep); |
|
|
|
|
else |
|
|
|
|
left_limit = get_limit(ordered_y[1], y, slstep); |
|
|
|
|
|
|
|
|
|
if(y < int(ceil(ordered_y[3].y))) |
|
|
|
|
right_limit = get_limit(ordered_y[0], y, frstep); |
|
|
|
|
else |
|
|
|
|
right_limit = get_limit(ordered_y[3], y, srstep); |
|
|
|
|
|
|
|
|
|
for(int x = (int) ceil(left_limit); x <= (int)(right_limit); ++x) { |
|
|
|
|
if (x < 0 || x >= img_width) continue; |
|
|
|
|
|
|
|
|
|
++total_pts; |
|
|
|
@ -1052,12 +1004,6 @@ double LineSegmentDetectorImpl::rect_nfa(const rect& rec) const |
|
|
|
|
++alg_pts; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(y >= leftmost->p.y) { lstep = slstep; } |
|
|
|
|
if(y >= rightmost->p.y) { rstep = srstep; } |
|
|
|
|
|
|
|
|
|
left_x += lstep; |
|
|
|
|
right_x += rstep; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nfa(total_pts, alg_pts, rec.p); |
|
|
|
@ -1071,7 +1017,7 @@ double LineSegmentDetectorImpl::nfa(const int& n, const int& k, const double& p) |
|
|
|
|
|
|
|
|
|
double p_term = p / (1 - p); |
|
|
|
|
|
|
|
|
|
double log1term = (double(n) + 1) - log_gamma(double(k) + 1) |
|
|
|
|
double log1term = log_gamma(double(n) + 1) - log_gamma(double(k) + 1) |
|
|
|
|
- log_gamma(double(n-k) + 1) |
|
|
|
|
+ double(k) * log(p) + double(n-k) * log(1.0 - p); |
|
|
|
|
double term = exp(log1term); |
|
|
|
|