Merge pull request #892 from spacetrain:fast_line_detector
commit
a2582d43b5
8 changed files with 1092 additions and 7 deletions
After Width: | Height: | Size: 517 KiB |
@ -0,0 +1,81 @@ |
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
|
||||||
|
#ifndef __OPENCV_FAST_LINE_DETECTOR_HPP__ |
||||||
|
#define __OPENCV_FAST_LINE_DETECTOR_HPP__ |
||||||
|
|
||||||
|
#include <opencv2/core.hpp> |
||||||
|
|
||||||
|
namespace cv |
||||||
|
{ |
||||||
|
namespace ximgproc |
||||||
|
{ |
||||||
|
|
||||||
|
//! @addtogroup ximgproc_feature
|
||||||
|
//! @{
|
||||||
|
|
||||||
|
/** @brief Class implementing the FLD (Fast Line Detector) algorithm described
|
||||||
|
in @cite Lee14 . |
||||||
|
*/ |
||||||
|
|
||||||
|
//! @include samples/fld_lines.cpp
|
||||||
|
|
||||||
|
class CV_EXPORTS_W FastLineDetector : public Algorithm |
||||||
|
{ |
||||||
|
public: |
||||||
|
/** @example fld_lines.cpp
|
||||||
|
An example using the FastLineDetector |
||||||
|
*/ |
||||||
|
/** @brief Finds lines in the input image.
|
||||||
|
This is the output of the default parameters of the algorithm on the above |
||||||
|
shown image. |
||||||
|
|
||||||
|
 |
||||||
|
|
||||||
|
@param _image A grayscale (CV_8UC1) input image. If only a roi needs to be |
||||||
|
selected, use: `fld_ptr-\>detect(image(roi), lines, ...); |
||||||
|
lines += Scalar(roi.x, roi.y, roi.x, roi.y);` |
||||||
|
@param _lines A vector of Vec4f elements specifying the beginning |
||||||
|
and ending point of a line. Where Vec4f is (x1, y1, x2, y2), point |
||||||
|
1 is the start, point 2 - end. Returned lines are directed so that the |
||||||
|
brighter side is on their left. |
||||||
|
*/ |
||||||
|
CV_WRAP virtual void detect(InputArray _image, OutputArray _lines) = 0; |
||||||
|
|
||||||
|
/** @brief Draws the line segments on a given image.
|
||||||
|
@param _image The image, where the lines will be drawn. Should be bigger |
||||||
|
or equal to the image, where the lines were found. |
||||||
|
@param lines A vector of the lines that needed to be drawn. |
||||||
|
@param draw_arrow If true, arrow heads will be drawn. |
||||||
|
*/ |
||||||
|
CV_WRAP virtual void drawSegments(InputOutputArray _image, InputArray lines, |
||||||
|
bool draw_arrow = false) = 0; |
||||||
|
|
||||||
|
virtual ~FastLineDetector() { } |
||||||
|
}; |
||||||
|
|
||||||
|
/** @brief Creates a smart pointer to a FastLineDetector object and initializes it
|
||||||
|
|
||||||
|
@param _length_threshold 10 - Segment shorter than this will be discarded |
||||||
|
@param _distance_threshold 1.41421356 - A point placed from a hypothesis line |
||||||
|
segment farther than this will be |
||||||
|
regarded as an outlier |
||||||
|
@param _canny_th1 50 - First threshold for |
||||||
|
hysteresis procedure in Canny() |
||||||
|
@param _canny_th2 50 - Second threshold for |
||||||
|
hysteresis procedure in Canny() |
||||||
|
@param _canny_aperture_size 3 - Aperturesize for the sobel |
||||||
|
operator in Canny() |
||||||
|
@param _do_merge false - If true, incremental merging of segments |
||||||
|
will be perfomred |
||||||
|
*/ |
||||||
|
CV_EXPORTS_W Ptr<FastLineDetector> createFastLineDetector( |
||||||
|
int _length_threshold = 10, float _distance_threshold = 1.414213562f, |
||||||
|
double _canny_th1 = 50.0, double _canny_th2 = 50.0, int _canny_aperture_size = 3, |
||||||
|
bool _do_merge = false); |
||||||
|
|
||||||
|
//! @} ximgproc_feature
|
||||||
|
} |
||||||
|
} |
||||||
|
#endif |
@ -0,0 +1,91 @@ |
|||||||
|
#include <iostream> |
||||||
|
|
||||||
|
#include "opencv2/imgproc.hpp" |
||||||
|
#include "opencv2/ximgproc.hpp" |
||||||
|
#include "opencv2/imgcodecs.hpp" |
||||||
|
#include "opencv2/highgui.hpp" |
||||||
|
|
||||||
|
using namespace std; |
||||||
|
using namespace cv; |
||||||
|
using namespace cv::ximgproc; |
||||||
|
|
||||||
|
int main(int argc, char** argv) |
||||||
|
{ |
||||||
|
std::string in; |
||||||
|
cv::CommandLineParser parser(argc, argv, "{@input|../samples/data/corridor.jpg|input image}{help h||show help message}"); |
||||||
|
if (parser.has("help")) |
||||||
|
{ |
||||||
|
parser.printMessage(); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
in = parser.get<string>("@input"); |
||||||
|
|
||||||
|
Mat image = imread(in, IMREAD_GRAYSCALE); |
||||||
|
|
||||||
|
if( image.empty() ) |
||||||
|
{ |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
// Create LSD detector
|
||||||
|
Ptr<LineSegmentDetector> lsd = createLineSegmentDetector(); |
||||||
|
vector<Vec4f> lines_lsd; |
||||||
|
|
||||||
|
// Create FLD detector
|
||||||
|
// Param Default value Description
|
||||||
|
// length_threshold 10 - Segments shorter than this will be discarded
|
||||||
|
// distance_threshold 1.41421356 - A point placed from a hypothesis line
|
||||||
|
// segment farther than this will be
|
||||||
|
// regarded as an outlier
|
||||||
|
// canny_th1 50 - First threshold for
|
||||||
|
// hysteresis procedure in Canny()
|
||||||
|
// canny_th2 50 - Second threshold for
|
||||||
|
// hysteresis procedure in Canny()
|
||||||
|
// canny_aperture_size 3 - Aperturesize for the sobel
|
||||||
|
// operator in Canny()
|
||||||
|
// do_merge false - If true, incremental merging of segments
|
||||||
|
// will be perfomred
|
||||||
|
int length_threshold = 10; |
||||||
|
float distance_threshold = 1.41421356f; |
||||||
|
double canny_th1 = 50.0; |
||||||
|
double canny_th2 = 50.0; |
||||||
|
int canny_aperture_size = 3; |
||||||
|
bool do_merge = false; |
||||||
|
Ptr<FastLineDetector> fld = createFastLineDetector(length_threshold, |
||||||
|
distance_threshold, canny_th1, canny_th2, canny_aperture_size, |
||||||
|
do_merge); |
||||||
|
vector<Vec4f> lines_fld; |
||||||
|
|
||||||
|
// Because of some CPU's power strategy, it seems that the first running of
|
||||||
|
// an algorithm takes much longer. So here we run both of the algorithmes 10
|
||||||
|
// times to see each algorithm's processing time with sufficiently warmed-up
|
||||||
|
// CPU performance.
|
||||||
|
for(int run_count = 0; run_count < 10; run_count++) { |
||||||
|
lines_lsd.clear(); |
||||||
|
int64 start_lsd = getTickCount(); |
||||||
|
lsd->detect(image, lines_lsd); |
||||||
|
// Detect the lines with LSD
|
||||||
|
double freq = getTickFrequency(); |
||||||
|
double duration_ms_lsd = double(getTickCount() - start_lsd) * 1000 / freq; |
||||||
|
std::cout << "Elapsed time for LSD: " << duration_ms_lsd << " ms." << std::endl; |
||||||
|
|
||||||
|
lines_fld.clear(); |
||||||
|
int64 start = getTickCount(); |
||||||
|
// Detect the lines with FLD
|
||||||
|
fld->detect(image, lines_fld); |
||||||
|
double duration_ms = double(getTickCount() - start) * 1000 / freq; |
||||||
|
std::cout << "Ealpsed time for FLD " << duration_ms << " ms." << std::endl; |
||||||
|
} |
||||||
|
// Show found lines with LSD
|
||||||
|
Mat line_image_lsd(image); |
||||||
|
lsd->drawSegments(line_image_lsd, lines_lsd); |
||||||
|
imshow("LSD result", line_image_lsd); |
||||||
|
|
||||||
|
// Show found lines with FLD
|
||||||
|
Mat line_image_fld(image); |
||||||
|
fld->drawSegments(line_image_fld, lines_fld); |
||||||
|
imshow("FLD result", line_image_fld); |
||||||
|
|
||||||
|
waitKey(); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,730 @@ |
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
|
||||||
|
#include "precomp.hpp" |
||||||
|
#include <vector> |
||||||
|
#include <iostream> |
||||||
|
|
||||||
|
struct SEGMENT |
||||||
|
{ |
||||||
|
float x1, y1, x2, y2, angle; |
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace cv{ |
||||||
|
namespace ximgproc{ |
||||||
|
|
||||||
|
class FastLineDetectorImpl : public FastLineDetector |
||||||
|
{ |
||||||
|
public: |
||||||
|
/**
|
||||||
|
* @param _length_threshold 10 - Segment shorter than this will be discarded |
||||||
|
* @param _distance_threshold 1.41421356 - A point placed from a hypothesis line segment |
||||||
|
* farther than this will be regarded as an outlier |
||||||
|
* @param _canny_th1 50 - First threshold for |
||||||
|
* _ hysteresis procedure in Canny() |
||||||
|
* @param _canny_th2 50 - Second threshold for |
||||||
|
* _ hysteresis procedure in Canny() |
||||||
|
* @param _canny_aperture_size 3 - Aperturesize for the sobel |
||||||
|
* _ operator in Canny() |
||||||
|
* @param _do_merge false - If true, incremental merging of segments |
||||||
|
will be perfomred |
||||||
|
*/ |
||||||
|
FastLineDetectorImpl(int _length_threshold = 10, float _distance_threshold = 1.414213562f, |
||||||
|
double _canny_th1 = 50.0, double _canny_th2 = 50.0, int _canny_aperture_size = 3, |
||||||
|
bool _do_merge = false); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect lines in the input image. |
||||||
|
* |
||||||
|
* @param _image A grayscale(CV_8UC1) input image. |
||||||
|
* If only a roi needs to be selected, use |
||||||
|
* lsd_ptr->detect(image(roi), ..., lines); |
||||||
|
* lines += Scalar(roi.x, roi.y, roi.x, roi.y); |
||||||
|
* @param _lines Return: A vector of Vec4f elements specifying the beginning and ending point of |
||||||
|
* a line. Where Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 is the end. |
||||||
|
* Returned lines are directed so that the brighter side is placed on left. |
||||||
|
*/ |
||||||
|
void detect(InputArray _image, OutputArray _lines); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw lines on the given canvas. |
||||||
|
* |
||||||
|
* @param image The image, where lines will be drawn |
||||||
|
* Should have the size of the image, where the lines were found |
||||||
|
* @param lines The lines that need to be drawn |
||||||
|
* @param draw_arrow If true, arrow heads will be drawn |
||||||
|
*/ |
||||||
|
void drawSegments(InputOutputArray _image, InputArray lines, bool draw_arrow = false); |
||||||
|
|
||||||
|
private: |
||||||
|
int imagewidth, imageheight, threshold_length; |
||||||
|
float threshold_dist; |
||||||
|
double canny_th1, canny_th2; |
||||||
|
int canny_aperture_size; |
||||||
|
bool do_merge; |
||||||
|
|
||||||
|
FastLineDetectorImpl& operator= (const FastLineDetectorImpl&); // to quiet MSVC
|
||||||
|
template<class T> |
||||||
|
void incidentPoint(const Mat& l, T& pt); |
||||||
|
|
||||||
|
void mergeLines(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged); |
||||||
|
|
||||||
|
bool mergeSegments(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged); |
||||||
|
|
||||||
|
bool getPointChain(const Mat& img, Point pt, Point& chained_pt, float& direction, int step); |
||||||
|
|
||||||
|
double distPointLine(const Mat& p, Mat& l); |
||||||
|
|
||||||
|
void extractSegments(const std::vector<Point2i>& points, std::vector<SEGMENT>& segments ); |
||||||
|
|
||||||
|
void lineDetection(const Mat& src, std::vector<SEGMENT>& segments_all); |
||||||
|
|
||||||
|
void pointInboardTest(const Mat& src, Point2i& pt); |
||||||
|
|
||||||
|
inline void getAngle(SEGMENT& seg); |
||||||
|
|
||||||
|
void additionalOperationsOnSegment(const Mat& src, SEGMENT& seg); |
||||||
|
|
||||||
|
void drawSegment(Mat& mat, const SEGMENT& seg, Scalar bgr = Scalar(0,255,0), |
||||||
|
int thickness = 1, bool directed = true); |
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
CV_EXPORTS Ptr<FastLineDetector> createFastLineDetector( |
||||||
|
int _length_threshold, float _distance_threshold, |
||||||
|
double _canny_th1, double _canny_th2, int _canny_aperture_size, bool _do_merge) |
||||||
|
{ |
||||||
|
return makePtr<FastLineDetectorImpl>( |
||||||
|
_length_threshold, _distance_threshold, |
||||||
|
_canny_th1, _canny_th2, _canny_aperture_size, _do_merge); |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FastLineDetectorImpl::FastLineDetectorImpl(int _length_threshold, float _distance_threshold, |
||||||
|
double _canny_th1, double _canny_th2, int _canny_aperture_size, bool _do_merge) |
||||||
|
:threshold_length(_length_threshold), threshold_dist(_distance_threshold), |
||||||
|
canny_th1(_canny_th1), canny_th2(_canny_th2), canny_aperture_size(_canny_aperture_size), do_merge(_do_merge) |
||||||
|
{ |
||||||
|
CV_Assert(_length_threshold > 0 && _distance_threshold > 0 && |
||||||
|
_canny_th1 > 0 && _canny_th2 > 0 && _canny_aperture_size > 0); |
||||||
|
} |
||||||
|
|
||||||
|
void FastLineDetectorImpl::detect(InputArray _image, OutputArray _lines) |
||||||
|
{ |
||||||
|
CV_INSTRUMENT_REGION(); |
||||||
|
|
||||||
|
Mat image = _image.getMat(); |
||||||
|
CV_Assert(!image.empty() && image.type() == CV_8UC1); |
||||||
|
|
||||||
|
std::vector<Vec4f> lines; |
||||||
|
std::vector<SEGMENT> segments; |
||||||
|
lineDetection(image, segments); |
||||||
|
for(size_t i = 0; i < segments.size(); ++i) |
||||||
|
{ |
||||||
|
const SEGMENT seg = segments[i]; |
||||||
|
Vec4f line(seg.x1, seg.y1, seg.x2, seg.y2); |
||||||
|
lines.push_back(line); |
||||||
|
} |
||||||
|
Mat(lines).copyTo(_lines); |
||||||
|
} |
||||||
|
|
||||||
|
void FastLineDetectorImpl::drawSegments(InputOutputArray _image, InputArray lines, bool draw_arrow) |
||||||
|
{ |
||||||
|
CV_INSTRUMENT_REGION(); |
||||||
|
|
||||||
|
CV_Assert(!_image.empty() && (_image.channels() == 1 || _image.channels() == 3)); |
||||||
|
|
||||||
|
Mat gray; |
||||||
|
if (_image.channels() == 1) |
||||||
|
{ |
||||||
|
gray = _image.getMatRef(); |
||||||
|
} |
||||||
|
else if (_image.channels() == 3) |
||||||
|
{ |
||||||
|
cvtColor(_image, gray, COLOR_BGR2GRAY); |
||||||
|
} |
||||||
|
|
||||||
|
// Create a 3 channel image in order to draw colored lines
|
||||||
|
std::vector<Mat> planes; |
||||||
|
planes.push_back(gray); |
||||||
|
planes.push_back(gray); |
||||||
|
planes.push_back(gray); |
||||||
|
|
||||||
|
merge(planes, _image); |
||||||
|
|
||||||
|
double gap = 10.0; |
||||||
|
double arrow_angle = 30.0; |
||||||
|
|
||||||
|
Mat _lines; |
||||||
|
_lines = lines.getMat(); |
||||||
|
int N = _lines.checkVector(4); |
||||||
|
// Draw segments
|
||||||
|
for(int i = 0; i < N; ++i) |
||||||
|
{ |
||||||
|
const Vec4f& v = _lines.at<Vec4f>(i); |
||||||
|
Point2f b(v[0], v[1]); |
||||||
|
Point2f e(v[2], v[3]); |
||||||
|
line(_image.getMatRef(), b, e, Scalar(0, 0, 255), 1); |
||||||
|
if(draw_arrow) |
||||||
|
{ |
||||||
|
SEGMENT seg; |
||||||
|
seg.x1 = b.x; |
||||||
|
seg.y1 = b.y; |
||||||
|
seg.x2 = e.x; |
||||||
|
seg.y2 = e.y; |
||||||
|
getAngle(seg); |
||||||
|
double ang = (double)seg.angle; |
||||||
|
Point2i p1; |
||||||
|
p1.x = (int)round(seg.x2 - gap*cos(arrow_angle * CV_PI / 180.0 + ang)); |
||||||
|
p1.y = (int)round(seg.y2 - gap*sin(arrow_angle * CV_PI / 180.0 + ang)); |
||||||
|
pointInboardTest(_image.getMatRef(), p1); |
||||||
|
line(_image.getMatRef(), Point((int)round(seg.x2), (int)round(seg.y2)), p1, Scalar(0,0,255), 1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void FastLineDetectorImpl::mergeLines(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged) |
||||||
|
{ |
||||||
|
double xg = 0.0, yg = 0.0; |
||||||
|
double delta1x = 0.0, delta1y = 0.0, delta2x = 0.0, delta2y = 0.0; |
||||||
|
float ax = 0, bx = 0, cx = 0, dx = 0; |
||||||
|
float ay = 0, by = 0, cy = 0, dy = 0; |
||||||
|
double li = 0.0, lj = 0.0; |
||||||
|
double thi = 0.0, thj = 0.0, thr = 0.0; |
||||||
|
double axg = 0.0, bxg = 0.0, cxg = 0.0, dxg = 0.0, delta1xg = 0.0, delta2xg = 0.0; |
||||||
|
|
||||||
|
ax = seg1.x1; |
||||||
|
ay = seg1.y1; |
||||||
|
|
||||||
|
bx = seg1.x2; |
||||||
|
by = seg1.y2; |
||||||
|
cx = seg2.x1; |
||||||
|
cy = seg2.y1; |
||||||
|
|
||||||
|
dx = seg2.x2; |
||||||
|
dy = seg2.y2; |
||||||
|
|
||||||
|
float dlix = (bx - ax); |
||||||
|
float dliy = (by - ay); |
||||||
|
float dljx = (dx - cx); |
||||||
|
float dljy = (dy - cy); |
||||||
|
|
||||||
|
li = sqrt((double) (dlix * dlix) + (double) (dliy * dliy)); |
||||||
|
lj = sqrt((double) (dljx * dljx) + (double) (dljy * dljy)); |
||||||
|
|
||||||
|
xg = (li * (double) (ax + bx) + lj * (double) (cx + dx)) |
||||||
|
/ (double) (2.0 * (li + lj)); |
||||||
|
yg = (li * (double) (ay + by) + lj * (double) (cy + dy)) |
||||||
|
/ (double) (2.0 * (li + lj)); |
||||||
|
|
||||||
|
if(dlix == 0.0f) thi = CV_PI / 2.0; |
||||||
|
else thi = atan(dliy / dlix); |
||||||
|
|
||||||
|
if(dljx == 0.0f) thj = CV_PI / 2.0; |
||||||
|
else thj = atan(dljy / dljx); |
||||||
|
|
||||||
|
if (fabs(thi - thj) <= CV_PI / 2.0) |
||||||
|
{ |
||||||
|
thr = (li * thi + lj * thj) / (li + lj); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
double tmp = thj - CV_PI * (thj / fabs(thj)); |
||||||
|
thr = li * thi + lj * tmp; |
||||||
|
thr /= (li + lj); |
||||||
|
} |
||||||
|
|
||||||
|
axg = ((double) ay - yg) * sin(thr) + ((double) ax - xg) * cos(thr); |
||||||
|
bxg = ((double) by - yg) * sin(thr) + ((double) bx - xg) * cos(thr); |
||||||
|
cxg = ((double) cy - yg) * sin(thr) + ((double) cx - xg) * cos(thr); |
||||||
|
dxg = ((double) dy - yg) * sin(thr) + ((double) dx - xg) * cos(thr); |
||||||
|
|
||||||
|
delta1xg = min(axg,min(bxg,min(cxg,dxg))); |
||||||
|
delta2xg = max(axg,max(bxg,max(cxg,dxg))); |
||||||
|
|
||||||
|
delta1x = delta1xg * cos(thr) + xg; |
||||||
|
delta1y = delta1xg * sin(thr) + yg; |
||||||
|
delta2x = delta2xg * cos(thr) + xg; |
||||||
|
delta2y = delta2xg * sin(thr) + yg; |
||||||
|
|
||||||
|
seg_merged.x1 = (float)delta1x; |
||||||
|
seg_merged.y1 = (float)delta1y; |
||||||
|
seg_merged.x2 = (float)delta2x; |
||||||
|
seg_merged.y2 = (float)delta2y; |
||||||
|
} |
||||||
|
|
||||||
|
double FastLineDetectorImpl::distPointLine(const Mat& p, Mat& l) |
||||||
|
{ |
||||||
|
double x = l.at<double>(0,0); |
||||||
|
double y = l.at<double>(1,0); |
||||||
|
double w = sqrt(x*x+y*y); |
||||||
|
|
||||||
|
l.at<double>(0,0) = x / w; |
||||||
|
l.at<double>(1,0) = y / w; |
||||||
|
l.at<double>(2,0) = l.at<double>(2,0) / w; |
||||||
|
|
||||||
|
return l.dot(p); |
||||||
|
} |
||||||
|
|
||||||
|
bool FastLineDetectorImpl::mergeSegments(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged) |
||||||
|
{ |
||||||
|
double o[] = { 0.0, 0.0, 1.0 }; |
||||||
|
double a[] = { 0.0, 0.0, 1.0 }; |
||||||
|
double b[] = { 0.0, 0.0, 1.0 }; |
||||||
|
double c[3]; |
||||||
|
|
||||||
|
o[0] = ( seg2.x1 + seg2.x2 ) / 2.0; |
||||||
|
o[1] = ( seg2.y1 + seg2.y2 ) / 2.0; |
||||||
|
|
||||||
|
a[0] = seg1.x1; |
||||||
|
a[1] = seg1.y1; |
||||||
|
b[0] = seg1.x2; |
||||||
|
b[1] = seg1.y2; |
||||||
|
|
||||||
|
Mat ori = Mat(3, 1, CV_64FC1, o).clone(); |
||||||
|
Mat p1 = Mat(3, 1, CV_64FC1, a).clone(); |
||||||
|
Mat p2 = Mat(3, 1, CV_64FC1, b).clone(); |
||||||
|
Mat l1 = Mat(3, 1, CV_64FC1, c).clone(); |
||||||
|
|
||||||
|
l1 = p1.cross(p2); |
||||||
|
|
||||||
|
Point2f seg1mid, seg2mid; |
||||||
|
seg1mid.x = (seg1.x1 + seg1.x2) /2.0f; |
||||||
|
seg1mid.y = (seg1.y1 + seg1.y2) /2.0f; |
||||||
|
seg2mid.x = (seg2.x1 + seg2.x2) /2.0f; |
||||||
|
seg2mid.y = (seg2.y1 + seg2.y2) /2.0f; |
||||||
|
|
||||||
|
float seg1len = sqrt((seg1.x1 - seg1.x2)*(seg1.x1 - seg1.x2)+(seg1.y1 - seg1.y2)*(seg1.y1 - seg1.y2)); |
||||||
|
float seg2len = sqrt((seg2.x1 - seg2.x2)*(seg2.x1 - seg2.x2)+(seg2.y1 - seg2.y2)*(seg2.y1 - seg2.y2)); |
||||||
|
float middist = sqrt((seg1mid.x - seg2mid.x)*(seg1mid.x - seg2mid.x) + (seg1mid.y - seg2mid.y)*(seg1mid.y - seg2mid.y)); |
||||||
|
float angdiff = fabs(seg1.angle - seg2.angle); |
||||||
|
|
||||||
|
float dist = (float)distPointLine(ori, l1); |
||||||
|
|
||||||
|
if ( fabs( dist ) <= threshold_dist * 2.0f && middist <= seg1len / 2.0f + seg2len / 2.0f + 20.0f |
||||||
|
&& angdiff <= CV_PI / 180.0f * 5.0f) |
||||||
|
{ |
||||||
|
mergeLines(seg1, seg2, seg_merged); |
||||||
|
return true; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
template<class T> |
||||||
|
void FastLineDetectorImpl::incidentPoint(const Mat& l, T& pt) |
||||||
|
{ |
||||||
|
double a[] = { (double)pt.x, (double)pt.y, 1.0 }; |
||||||
|
double b[] = { l.at<double>(0,0), l.at<double>(1,0), 0.0 }; |
||||||
|
double c[3]; |
||||||
|
|
||||||
|
Mat xk = Mat(3, 1, CV_64FC1, a).clone(); |
||||||
|
Mat lh = Mat(3, 1, CV_64FC1, b).clone(); |
||||||
|
Mat lk = Mat(3, 1, CV_64FC1, c).clone(); |
||||||
|
|
||||||
|
lk = xk.cross(lh); |
||||||
|
xk = lk.cross(l); |
||||||
|
|
||||||
|
xk.convertTo(xk, -1, 1.0 / xk.at<double>(2,0)); |
||||||
|
|
||||||
|
Point2f pt_tmp; |
||||||
|
pt_tmp.x = (float)xk.at<double>(0,0) < 0.0f ? 0.0f : (float)xk.at<double>(0,0) |
||||||
|
>= (imagewidth - 1.0f) ? (imagewidth - 1.0f) : (float)xk.at<double>(0,0); |
||||||
|
pt_tmp.y = (float)xk.at<double>(1,0) < 0.0f ? 0.0f : (float)xk.at<double>(1,0) |
||||||
|
>= (imageheight - 1.0f) ? (imageheight - 1.0f) : (float)xk.at<double>(1,0); |
||||||
|
pt = T(pt_tmp); |
||||||
|
} |
||||||
|
|
||||||
|
void FastLineDetectorImpl::extractSegments(const std::vector<Point2i>& points, std::vector<SEGMENT>& segments ) |
||||||
|
{ |
||||||
|
bool is_line; |
||||||
|
|
||||||
|
int i, j; |
||||||
|
SEGMENT seg; |
||||||
|
Point2i ps, pe, pt; |
||||||
|
|
||||||
|
std::vector<Point2i> l_points; |
||||||
|
|
||||||
|
int total = (int)points.size(); |
||||||
|
|
||||||
|
for ( i = 0; i + threshold_length < total; i++ ) |
||||||
|
{ |
||||||
|
ps = points[i]; |
||||||
|
pe = points[i + threshold_length]; |
||||||
|
|
||||||
|
double a[] = { (double)ps.x, (double)ps.y, 1 }; |
||||||
|
double b[] = { (double)pe.x, (double)pe.y, 1 }; |
||||||
|
double c[3], d[3]; |
||||||
|
|
||||||
|
Mat p1 = Mat(3, 1, CV_64FC1, a).clone(); |
||||||
|
Mat p2 = Mat(3, 1, CV_64FC1, b).clone(); |
||||||
|
Mat p = Mat(3, 1, CV_64FC1, c).clone(); |
||||||
|
Mat l = Mat(3, 1, CV_64FC1, d).clone(); |
||||||
|
l = p1.cross(p2); |
||||||
|
|
||||||
|
is_line = true; |
||||||
|
|
||||||
|
l_points.clear(); |
||||||
|
l_points.push_back(ps); |
||||||
|
|
||||||
|
for ( j = 1; j < threshold_length; j++ ) |
||||||
|
{ |
||||||
|
pt.x = points[i+j].x; |
||||||
|
pt.y = points[i+j].y; |
||||||
|
|
||||||
|
p.at<double>(0,0) = (double)pt.x; |
||||||
|
p.at<double>(1,0) = (double)pt.y; |
||||||
|
p.at<double>(2,0) = 1.0; |
||||||
|
|
||||||
|
double dist = distPointLine(p, l); |
||||||
|
|
||||||
|
if ( fabs( dist ) > threshold_dist ) |
||||||
|
{ |
||||||
|
is_line = false; |
||||||
|
break; |
||||||
|
} |
||||||
|
l_points.push_back(pt); |
||||||
|
} |
||||||
|
|
||||||
|
// Line check fail, test next point
|
||||||
|
if ( is_line == false ) |
||||||
|
continue; |
||||||
|
|
||||||
|
l_points.push_back(pe); |
||||||
|
|
||||||
|
Vec4f line; |
||||||
|
fitLine( Mat(l_points), line, DIST_L2, 0, 0.01, 0.01); |
||||||
|
a[0] = line[2]; |
||||||
|
a[1] = line[3]; |
||||||
|
b[0] = line[2] + line[0]; |
||||||
|
b[1] = line[3] + line[1]; |
||||||
|
|
||||||
|
p1 = Mat(3, 1, CV_64FC1, a).clone(); |
||||||
|
p2 = Mat(3, 1, CV_64FC1, b).clone(); |
||||||
|
|
||||||
|
l = p1.cross(p2); |
||||||
|
|
||||||
|
incidentPoint(l, ps); |
||||||
|
|
||||||
|
// Extending line
|
||||||
|
for ( j = threshold_length + 1; i + j < total; j++ ) |
||||||
|
{ |
||||||
|
pt.x = points[i+j].x; |
||||||
|
pt.y = points[i+j].y; |
||||||
|
|
||||||
|
p.at<double>(0,0) = (double)pt.x; |
||||||
|
p.at<double>(1,0) = (double)pt.y; |
||||||
|
p.at<double>(2,0) = 1.0; |
||||||
|
|
||||||
|
double dist = distPointLine(p, l); |
||||||
|
if ( fabs( dist ) > threshold_dist ) |
||||||
|
{ |
||||||
|
fitLine( Mat(l_points), line, DIST_L2, 0, 0.01, 0.01); |
||||||
|
a[0] = line[2]; |
||||||
|
a[1] = line[3]; |
||||||
|
b[0] = line[2] + line[0]; |
||||||
|
b[1] = line[3] + line[1]; |
||||||
|
|
||||||
|
p1 = Mat(3, 1, CV_64FC1, a).clone(); |
||||||
|
p2 = Mat(3, 1, CV_64FC1, b).clone(); |
||||||
|
|
||||||
|
l = p1.cross(p2); |
||||||
|
dist = distPointLine(p, l); |
||||||
|
if ( fabs( dist ) > threshold_dist ) { |
||||||
|
j--; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
pe = pt; |
||||||
|
l_points.push_back(pt); |
||||||
|
} |
||||||
|
fitLine( Mat(l_points), line, DIST_L2, 0, 0.01, 0.01); |
||||||
|
a[0] = line[2]; |
||||||
|
a[1] = line[3]; |
||||||
|
b[0] = line[2] + line[0]; |
||||||
|
b[1] = line[3] + line[1]; |
||||||
|
|
||||||
|
p1 = Mat(3, 1, CV_64FC1, a).clone(); |
||||||
|
p2 = Mat(3, 1, CV_64FC1, b).clone(); |
||||||
|
|
||||||
|
l = p1.cross(p2); |
||||||
|
|
||||||
|
Point2f e1, e2; |
||||||
|
e1.x = (float)ps.x; |
||||||
|
e1.y = (float)ps.y; |
||||||
|
e2.x = (float)pe.x; |
||||||
|
e2.y = (float)pe.y; |
||||||
|
|
||||||
|
incidentPoint(l, e1); |
||||||
|
incidentPoint(l, e2); |
||||||
|
seg.x1 = e1.x; |
||||||
|
seg.y1 = e1.y; |
||||||
|
seg.x2 = e2.x; |
||||||
|
seg.y2 = e2.y; |
||||||
|
|
||||||
|
segments.push_back(seg); |
||||||
|
i = i + j; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void FastLineDetectorImpl::pointInboardTest(const Mat& src, Point2i& pt) |
||||||
|
{ |
||||||
|
pt.x = pt.x <= 5 ? 5 : pt.x >= src.cols - 5 ? src.cols - 5 : pt.x; |
||||||
|
pt.y = pt.y <= 5 ? 5 : pt.y >= src.rows - 5 ? src.rows - 5 : pt.y; |
||||||
|
} |
||||||
|
|
||||||
|
bool FastLineDetectorImpl::getPointChain(const Mat& img, Point pt, |
||||||
|
Point& chained_pt, float& direction, int step) |
||||||
|
{ |
||||||
|
int ri, ci; |
||||||
|
int indices[8][2] = { {1,1}, {1,0}, {1,-1}, {0,-1}, |
||||||
|
{-1,-1},{-1,0}, {-1,1}, {0,1} }; |
||||||
|
|
||||||
|
float min_dir_diff = 7.0f; |
||||||
|
Point consistent_pt; |
||||||
|
int consistent_direction = 0; |
||||||
|
for ( int i = 0; i < 8; i++ ) |
||||||
|
{ |
||||||
|
ci = pt.x + indices[i][1]; |
||||||
|
ri = pt.y + indices[i][0]; |
||||||
|
|
||||||
|
if ( ri < 0 || ri == img.rows || ci < 0 || ci == img.cols ) |
||||||
|
continue; |
||||||
|
|
||||||
|
if ( img.at<unsigned char>(ri, ci) == 0 ) |
||||||
|
continue; |
||||||
|
|
||||||
|
if(step == 0) |
||||||
|
{ |
||||||
|
chained_pt.x = ci; |
||||||
|
chained_pt.y = ri; |
||||||
|
// direction = (float)i;
|
||||||
|
direction = i > 4 ? (float)(i - 8) : (float)i; |
||||||
|
return true; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
float curr_dir = i > 4 ? (float)(i - 8) : (float)i; |
||||||
|
float dir_diff = abs(curr_dir - direction); |
||||||
|
dir_diff = dir_diff > 4.0f ? 8.0f - dir_diff : dir_diff; |
||||||
|
if(dir_diff <= min_dir_diff) |
||||||
|
{ |
||||||
|
min_dir_diff = dir_diff; |
||||||
|
consistent_pt.x = ci; |
||||||
|
consistent_pt.y = ri; |
||||||
|
consistent_direction = i > 4 ? i - 8 : i; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if(min_dir_diff < 2.0f) |
||||||
|
{ |
||||||
|
chained_pt.x = consistent_pt.x; |
||||||
|
chained_pt.y = consistent_pt.y; |
||||||
|
direction = (direction * (float)step + (float)consistent_direction) |
||||||
|
/ (float)(step + 1); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void FastLineDetectorImpl::lineDetection(const Mat& src, std::vector<SEGMENT>& segments_all) |
||||||
|
{ |
||||||
|
int r, c; |
||||||
|
imageheight=src.rows; imagewidth=src.cols; |
||||||
|
|
||||||
|
std::vector<Point2i> points; |
||||||
|
std::vector<SEGMENT> segments, segments_tmp; |
||||||
|
Mat canny; |
||||||
|
Canny(src, canny, canny_th1, canny_th2, canny_aperture_size); |
||||||
|
|
||||||
|
canny.colRange(0,6).rowRange(0,6) = 0; |
||||||
|
canny.colRange(src.cols-5,src.cols).rowRange(src.rows-5,src.rows) = 0; |
||||||
|
|
||||||
|
SEGMENT seg, seg1, seg2; |
||||||
|
|
||||||
|
for ( r = 0; r < imageheight; r++ ) |
||||||
|
{ |
||||||
|
for ( c = 0; c < imagewidth; c++ ) |
||||||
|
{ |
||||||
|
// Find seeds - skip for non-seeds
|
||||||
|
if ( canny.at<unsigned char>(r,c) == 0 ) |
||||||
|
continue; |
||||||
|
|
||||||
|
// Found seeds
|
||||||
|
Point2i pt = Point2i(c,r); |
||||||
|
|
||||||
|
points.push_back(pt); |
||||||
|
canny.at<unsigned char>(pt.y, pt.x) = 0; |
||||||
|
|
||||||
|
float direction = 0.0f; |
||||||
|
int step = 0; |
||||||
|
while(getPointChain(canny, pt, pt, direction, step)) |
||||||
|
{ |
||||||
|
points.push_back(pt); |
||||||
|
step++; |
||||||
|
canny.at<unsigned char>(pt.y, pt.x) = 0; |
||||||
|
} |
||||||
|
|
||||||
|
if ( points.size() < (unsigned int)threshold_length + 1 ) |
||||||
|
{ |
||||||
|
points.clear(); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
extractSegments(points, segments); |
||||||
|
|
||||||
|
if ( segments.size() == 0 ) |
||||||
|
{ |
||||||
|
points.clear(); |
||||||
|
continue; |
||||||
|
} |
||||||
|
for ( int i = 0; i < (int)segments.size(); i++ ) |
||||||
|
{ |
||||||
|
seg = segments[i]; |
||||||
|
float length = sqrt((seg.x1 - seg.x2)*(seg.x1 - seg.x2) + |
||||||
|
(seg.y1 - seg.y2)*(seg.y1 - seg.y2)); |
||||||
|
if(length < threshold_length) |
||||||
|
continue; |
||||||
|
if( (seg.x1 <= 5.0f && seg.x2 <= 5.0f) || |
||||||
|
(seg.y1 <= 5.0f && seg.y2 <= 5.0f) || |
||||||
|
(seg.x1 >= imagewidth - 5.0f && seg.x2 >= imagewidth - 5.0f) || |
||||||
|
(seg.y1 >= imageheight - 5.0f && seg.y2 >= imageheight - 5.0f) ) |
||||||
|
continue; |
||||||
|
additionalOperationsOnSegment(src, seg); |
||||||
|
if(!do_merge) |
||||||
|
segments_all.push_back(seg); |
||||||
|
segments_tmp.push_back(seg); |
||||||
|
} |
||||||
|
points.clear(); |
||||||
|
segments.clear(); |
||||||
|
} |
||||||
|
} |
||||||
|
if(!do_merge) |
||||||
|
return; |
||||||
|
|
||||||
|
bool is_merged = false; |
||||||
|
int ith = (int)segments_tmp.size() - 1; |
||||||
|
int jth = ith - 1; |
||||||
|
while(ith > 1 || jth > 0) |
||||||
|
{ |
||||||
|
seg1 = segments_tmp[ith]; |
||||||
|
seg2 = segments_tmp[jth]; |
||||||
|
SEGMENT seg_merged; |
||||||
|
is_merged = mergeSegments(seg1, seg2, seg_merged); |
||||||
|
if(is_merged == true) |
||||||
|
{ |
||||||
|
seg2 = seg_merged; |
||||||
|
additionalOperationsOnSegment(src, seg2); |
||||||
|
std::vector<SEGMENT>::iterator it = segments_tmp.begin() + ith; |
||||||
|
*it = seg2; |
||||||
|
segments_tmp.erase(segments_tmp.begin()+jth); |
||||||
|
ith--; |
||||||
|
jth = ith - 1; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
jth--; |
||||||
|
} |
||||||
|
if(jth < 0) { |
||||||
|
ith--; |
||||||
|
jth = ith - 1; |
||||||
|
} |
||||||
|
} |
||||||
|
segments_all = segments_tmp; |
||||||
|
} |
||||||
|
|
||||||
|
inline void FastLineDetectorImpl::getAngle(SEGMENT& seg) |
||||||
|
{ |
||||||
|
seg.angle = (float)(fastAtan2(seg.y2 - seg.y1, seg.x2 - seg.x1) / 180.0f * CV_PI); |
||||||
|
} |
||||||
|
|
||||||
|
void FastLineDetectorImpl::additionalOperationsOnSegment(const Mat& src, SEGMENT& seg) |
||||||
|
{ |
||||||
|
if(seg.x1 == 0.0f && seg.x2 == 0.0f && seg.y1 == 0.0f && seg.y2 == 0.0f) |
||||||
|
return; |
||||||
|
|
||||||
|
getAngle(seg); |
||||||
|
double ang = (double)seg.angle; |
||||||
|
|
||||||
|
Point2f start = Point2f(seg.x1, seg.y1); |
||||||
|
Point2f end = Point2f(seg.x2, seg.y2); |
||||||
|
|
||||||
|
double dx = 0.0, dy = 0.0; |
||||||
|
dx = (double) end.x - (double) start.x; |
||||||
|
dy = (double) end.y - (double) start.y; |
||||||
|
|
||||||
|
int num_points = 10; |
||||||
|
Point2f *points = new Point2f[num_points]; |
||||||
|
|
||||||
|
points[0] = start; |
||||||
|
points[num_points - 1] = end; |
||||||
|
for (int i = 0; i < num_points; i++) |
||||||
|
{ |
||||||
|
if (i == 0 || i == num_points - 1) |
||||||
|
continue; |
||||||
|
points[i].x = points[0].x + ((float)dx / float(num_points - 1) * (float) i); |
||||||
|
points[i].y = points[0].y + ((float)dy / float(num_points - 1) * (float) i); |
||||||
|
} |
||||||
|
|
||||||
|
Point2i *points_right = new Point2i[num_points]; |
||||||
|
Point2i *points_left = new Point2i[num_points]; |
||||||
|
double gap = 1.0; |
||||||
|
|
||||||
|
for(int i = 0; i < num_points; i++) |
||||||
|
{ |
||||||
|
points_right[i].x = cvRound(points[i].x + gap*cos(90.0 * CV_PI / 180.0 + ang)); |
||||||
|
points_right[i].y = cvRound(points[i].y + gap*sin(90.0 * CV_PI / 180.0 + ang)); |
||||||
|
points_left[i].x = cvRound(points[i].x - gap*cos(90.0 * CV_PI / 180.0 + ang)); |
||||||
|
points_left[i].y = cvRound(points[i].y - gap*sin(90.0 * CV_PI / 180.0 + ang)); |
||||||
|
pointInboardTest(src, points_right[i]); |
||||||
|
pointInboardTest(src, points_left[i]); |
||||||
|
} |
||||||
|
|
||||||
|
int iR = 0, iL = 0; |
||||||
|
for(int i = 0; i < num_points; i++) |
||||||
|
{ |
||||||
|
iR += src.at<unsigned char>(points_right[i].y, points_right[i].x); |
||||||
|
iL += src.at<unsigned char>(points_left[i].y, points_left[i].x); |
||||||
|
} |
||||||
|
|
||||||
|
if(iR > iL) |
||||||
|
{ |
||||||
|
std::swap(seg.x1, seg.x2); |
||||||
|
std::swap(seg.y1, seg.y2); |
||||||
|
getAngle(seg); |
||||||
|
} |
||||||
|
|
||||||
|
delete[] points; |
||||||
|
delete[] points_right; |
||||||
|
delete[] points_left; |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
void FastLineDetectorImpl::drawSegment(Mat& mat, const SEGMENT& seg, Scalar bgr, int thickness, bool directed) |
||||||
|
{ |
||||||
|
double gap = 10.0; |
||||||
|
double ang = (double)seg.angle; |
||||||
|
double arrow_angle = 30.0; |
||||||
|
|
||||||
|
Point2i p1; |
||||||
|
p1.x = (int)round(seg.x2 - gap*cos(arrow_angle * CV_PI / 180.0 + ang)); |
||||||
|
p1.y = (int)round(seg.y2 - gap*sin(arrow_angle * CV_PI / 180.0 + ang)); |
||||||
|
pointInboardTest(mat, p1); |
||||||
|
|
||||||
|
line(mat, Point((int)round(seg.x1), (int)round(seg.y1)), |
||||||
|
Point((int)round(seg.x2), (int)round(seg.y2)), bgr, thickness, 1); |
||||||
|
if(directed) |
||||||
|
line(mat, Point((int)round(seg.x2), (int)round(seg.y2)), p1, bgr, thickness, 1); |
||||||
|
} |
||||||
|
} // namespace cv
|
||||||
|
} // namespace ximgproc
|
@ -0,0 +1,173 @@ |
|||||||
|
#include "test_precomp.hpp" |
||||||
|
|
||||||
|
#include <vector> |
||||||
|
|
||||||
|
using namespace cv; |
||||||
|
using namespace cv::ximgproc; |
||||||
|
using namespace std; |
||||||
|
|
||||||
|
const Size img_size(640, 480); |
||||||
|
const int FLD_TEST_SEED = 0x134679; |
||||||
|
const int EPOCHS = 20; |
||||||
|
|
||||||
|
class FLDBase : public testing::Test |
||||||
|
{ |
||||||
|
public: |
||||||
|
FLDBase() { } |
||||||
|
|
||||||
|
protected: |
||||||
|
Mat test_image; |
||||||
|
vector<Vec4f> lines; |
||||||
|
RNG rng; |
||||||
|
int passedtests; |
||||||
|
|
||||||
|
void GenerateWhiteNoise(Mat& image); |
||||||
|
void GenerateConstColor(Mat& image); |
||||||
|
void GenerateLines(Mat& image, const unsigned int numLines); |
||||||
|
void GenerateBrokenLines(Mat& image, const unsigned int numLines); |
||||||
|
void GenerateRotatedRect(Mat& image); |
||||||
|
virtual void SetUp(); |
||||||
|
}; |
||||||
|
|
||||||
|
class ximgproc_FLD: public FLDBase |
||||||
|
{ |
||||||
|
public: |
||||||
|
ximgproc_FLD() { } |
||||||
|
protected: |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
void FLDBase::GenerateWhiteNoise(Mat& image) |
||||||
|
{ |
||||||
|
image = Mat(img_size, CV_8UC1); |
||||||
|
rng.fill(image, RNG::UNIFORM, 0, 256); |
||||||
|
} |
||||||
|
|
||||||
|
void FLDBase::GenerateConstColor(Mat& image) |
||||||
|
{ |
||||||
|
image = Mat(img_size, CV_8UC1, Scalar::all(rng.uniform(0, 256))); |
||||||
|
} |
||||||
|
|
||||||
|
void FLDBase::GenerateLines(Mat& image, const unsigned int numLines) |
||||||
|
{ |
||||||
|
image = Mat(img_size, CV_8UC1, Scalar::all(rng.uniform(0, 128))); |
||||||
|
|
||||||
|
for(unsigned int i = 0; i < numLines; ++i) |
||||||
|
{ |
||||||
|
int y = rng.uniform(10, img_size.width - 10); |
||||||
|
Point p1(y, 10); |
||||||
|
Point p2(y, img_size.height - 10); |
||||||
|
line(image, p1, p2, Scalar(255), 2); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void FLDBase::GenerateBrokenLines(Mat& image, const unsigned int numLines) |
||||||
|
{ |
||||||
|
image = Mat(img_size, CV_8UC1, Scalar::all(rng.uniform(0, 128))); |
||||||
|
|
||||||
|
for(unsigned int i = 0; i < numLines; ++i) |
||||||
|
{ |
||||||
|
int y = rng.uniform(10, img_size.width - 10); |
||||||
|
Point p1(y, 10); |
||||||
|
Point p2(y, img_size.height/2); |
||||||
|
line(image, p1, p2, Scalar(255), 2); |
||||||
|
p1 = Point2i(y, img_size.height/2 + 3); |
||||||
|
p2 = Point2i(y, img_size.height - 10); |
||||||
|
line(image, p1, p2, Scalar(255), 2); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void FLDBase::GenerateRotatedRect(Mat& image) |
||||||
|
{ |
||||||
|
image = Mat::zeros(img_size, CV_8UC1); |
||||||
|
|
||||||
|
Point center(rng.uniform(img_size.width/4, img_size.width*3/4), |
||||||
|
rng.uniform(img_size.height/4, img_size.height*3/4)); |
||||||
|
Size rect_size(rng.uniform(img_size.width/8, img_size.width/6), |
||||||
|
rng.uniform(img_size.height/8, img_size.height/6)); |
||||||
|
float angle = rng.uniform(0.f, 360.f); |
||||||
|
|
||||||
|
Point2f vertices[4]; |
||||||
|
|
||||||
|
RotatedRect rRect = RotatedRect(center, rect_size, angle); |
||||||
|
|
||||||
|
rRect.points(vertices); |
||||||
|
for (int i = 0; i < 4; i++) |
||||||
|
{ |
||||||
|
line(image, vertices[i], vertices[(i + 1) % 4], Scalar(255), 3); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void FLDBase::SetUp() |
||||||
|
{ |
||||||
|
lines.clear(); |
||||||
|
test_image = Mat(); |
||||||
|
rng = RNG(FLD_TEST_SEED); |
||||||
|
passedtests = 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
TEST_F(ximgproc_FLD, whiteNoise) |
||||||
|
{ |
||||||
|
for (int i = 0; i < EPOCHS; ++i) |
||||||
|
{ |
||||||
|
GenerateWhiteNoise(test_image); |
||||||
|
Ptr<FastLineDetector> detector = createFastLineDetector(20); |
||||||
|
detector->detect(test_image, lines); |
||||||
|
|
||||||
|
if(40u >= lines.size()) ++passedtests; |
||||||
|
} |
||||||
|
ASSERT_EQ(EPOCHS, passedtests); |
||||||
|
} |
||||||
|
|
||||||
|
TEST_F(ximgproc_FLD, constColor) |
||||||
|
{ |
||||||
|
for (int i = 0; i < EPOCHS; ++i) |
||||||
|
{ |
||||||
|
GenerateConstColor(test_image); |
||||||
|
Ptr<FastLineDetector> detector = createFastLineDetector(); |
||||||
|
detector->detect(test_image, lines); |
||||||
|
|
||||||
|
if(0u == lines.size()) ++passedtests; |
||||||
|
} |
||||||
|
ASSERT_EQ(EPOCHS, passedtests); |
||||||
|
} |
||||||
|
|
||||||
|
TEST_F(ximgproc_FLD, lines) |
||||||
|
{ |
||||||
|
for (int i = 0; i < EPOCHS; ++i) |
||||||
|
{ |
||||||
|
const unsigned int numOfLines = 1; |
||||||
|
GenerateLines(test_image, numOfLines); |
||||||
|
Ptr<FastLineDetector> detector = createFastLineDetector(); |
||||||
|
detector->detect(test_image, lines); |
||||||
|
if(numOfLines * 2 == lines.size()) ++passedtests; // * 2 because of Gibbs effect
|
||||||
|
} |
||||||
|
ASSERT_EQ(EPOCHS, passedtests); |
||||||
|
} |
||||||
|
|
||||||
|
TEST_F(ximgproc_FLD, mergeLines) |
||||||
|
{ |
||||||
|
for (int i = 0; i < EPOCHS; ++i) |
||||||
|
{ |
||||||
|
const unsigned int numOfLines = 1; |
||||||
|
GenerateBrokenLines(test_image, numOfLines); |
||||||
|
Ptr<FastLineDetector> detector = createFastLineDetector(10, 1.414213562f, true); |
||||||
|
detector->detect(test_image, lines); |
||||||
|
if(numOfLines * 2 == lines.size()) ++passedtests; // * 2 because of Gibbs effect
|
||||||
|
} |
||||||
|
ASSERT_EQ(EPOCHS, passedtests); |
||||||
|
} |
||||||
|
|
||||||
|
TEST_F(ximgproc_FLD, rotatedRect) |
||||||
|
{ |
||||||
|
for (int i = 0; i < EPOCHS; ++i) |
||||||
|
{ |
||||||
|
GenerateRotatedRect(test_image); |
||||||
|
Ptr<FastLineDetector> detector = createFastLineDetector(); |
||||||
|
detector->detect(test_image, lines); |
||||||
|
|
||||||
|
if(2u <= lines.size()) ++passedtests; |
||||||
|
} |
||||||
|
ASSERT_EQ(EPOCHS, passedtests); |
||||||
|
} |
After Width: | Height: | Size: 225 KiB |
Loading…
Reference in new issue