mirror of
https://github.com/opencv/opencv.git
synced 2024-11-24 11:10:21 +08:00
Merge pull request #10646 from take1014:master
* Add a new interface for hough transform * Fixed warning code * Fix HoughLinesUsingSetOfPoints based on HoughLinesStandard * Delete memset * Rename HoughLinesUsingSetOfPoints and add common function * Fix test error * Change static function name * Change using CV_Assert instead of if-block and add integer test case * I solve the conflict and delete 'std :: tr1' and changed it to use 'tuple' * I deleted std::tr1::get and changed int to use 'get' * Fixed sample code * revert test_main.cpp * Delete sample code in comment and add snippets * Change file name * Delete static function * Fixed build error
This commit is contained in:
parent
d56b2b56fb
commit
03407a9da0
@ -2072,6 +2072,27 @@ CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines,
|
||||
double rho, double theta, int threshold,
|
||||
double minLineLength = 0, double maxLineGap = 0 );
|
||||
|
||||
/** @brief Finds lines in a set of points using the standard Hough transform.
|
||||
|
||||
The function finds lines in a set of points using a modification of the Hough transform.
|
||||
@include snippets/imgproc_HoughLinesPointSet.cpp
|
||||
@param _point Input vector of points. Each vector must be encoded as a Point vector \f$(x,y)\f$. Type must be CV_32FC2 or CV_32SC2.
|
||||
@param _lines Output vector of found lines. Each vector is encoded as a vector<Vec3d> \f$(votes, rho, theta)\f$.
|
||||
The larger the value of 'votes', the higher the reliability of the Hough line.
|
||||
@param lines_max Max count of hough lines.
|
||||
@param threshold Accumulator threshold parameter. Only those lines are returned that get enough
|
||||
votes ( \f$>\texttt{threshold}\f$ )
|
||||
@param min_rho Minimum Distance value of the accumulator in pixels.
|
||||
@param max_rho Maximum Distance value of the accumulator in pixels.
|
||||
@param rho_step Distance resolution of the accumulator in pixels.
|
||||
@param min_theta Minimum angle value of the accumulator in radians.
|
||||
@param max_theta Maximum angle value of the accumulator in radians.
|
||||
@param theta_step Angle resolution of the accumulator in radians.
|
||||
*/
|
||||
CV_EXPORTS_W void HoughLinesPointSet( InputArray _point, OutputArray _lines, int lines_max, int threshold,
|
||||
double min_rho, double max_rho, double rho_step,
|
||||
double min_theta, double max_theta, double theta_step );
|
||||
|
||||
/** @example houghcircles.cpp
|
||||
An example using the Hough circle detector
|
||||
*/
|
||||
|
@ -68,6 +68,32 @@ struct hough_cmp_gt
|
||||
const int* aux;
|
||||
};
|
||||
|
||||
static void
|
||||
createTrigTable( int numangle, double min_theta, double theta_step,
|
||||
float irho, float *tabSin, float *tabCos )
|
||||
{
|
||||
float ang = static_cast<float>(min_theta);
|
||||
for(int n = 0; n < numangle; ang += (float)theta_step, n++ )
|
||||
{
|
||||
tabSin[n] = (float)(sin((double)ang) * irho);
|
||||
tabCos[n] = (float)(cos((double)ang) * irho);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
findLocalMaximums( int numrho, int numangle, int threshold,
|
||||
const int *accum, std::vector<int>& sort_buf )
|
||||
{
|
||||
for(int r = 0; r < numrho; r++ )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int base = (n+1) * (numrho+2) + r+1;
|
||||
if( accum[base] > threshold &&
|
||||
accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
|
||||
accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
|
||||
sort_buf.push_back(base);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Here image is an input raster;
|
||||
@ -125,21 +151,17 @@ HoughLinesStandard( const Mat& img, float rho, float theta,
|
||||
}
|
||||
#endif
|
||||
|
||||
AutoBuffer<int> _accum((numangle+2) * (numrho+2));
|
||||
|
||||
Mat _accum = Mat::zeros( (numangle+2), (numrho+2), CV_32SC1 );
|
||||
std::vector<int> _sort_buf;
|
||||
AutoBuffer<float> _tabSin(numangle);
|
||||
AutoBuffer<float> _tabCos(numangle);
|
||||
int *accum = _accum;
|
||||
int *accum = _accum.ptr<int>();
|
||||
float *tabSin = _tabSin, *tabCos = _tabCos;
|
||||
|
||||
memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
|
||||
|
||||
float ang = static_cast<float>(min_theta);
|
||||
for(int n = 0; n < numangle; ang += theta, n++ )
|
||||
{
|
||||
tabSin[n] = (float)(sin((double)ang) * irho);
|
||||
tabCos[n] = (float)(cos((double)ang) * irho);
|
||||
}
|
||||
// create sin and cos table
|
||||
createTrigTable( numangle, min_theta, theta,
|
||||
irho, tabSin, tabCos );
|
||||
|
||||
// stage 1. fill accumulator
|
||||
for( i = 0; i < height; i++ )
|
||||
@ -155,15 +177,7 @@ HoughLinesStandard( const Mat& img, float rho, float theta,
|
||||
}
|
||||
|
||||
// stage 2. find local maximums
|
||||
for(int r = 0; r < numrho; r++ )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int base = (n+1) * (numrho+2) + r+1;
|
||||
if( accum[base] > threshold &&
|
||||
accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
|
||||
accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
|
||||
_sort_buf.push_back(base);
|
||||
}
|
||||
findLocalMaximums( numrho, numangle, threshold, accum, _sort_buf );
|
||||
|
||||
// stage 3. sort the detected lines by accumulator value
|
||||
std::sort(_sort_buf.begin(), _sort_buf.end(), hough_cmp_gt(accum));
|
||||
@ -883,6 +897,76 @@ void HoughLinesP(InputArray _image, OutputArray _lines,
|
||||
Mat(lines).copyTo(_lines);
|
||||
}
|
||||
|
||||
void HoughLinesPointSet( InputArray _point, OutputArray _lines, int lines_max, int threshold,
|
||||
double min_rho, double max_rho, double rho_step,
|
||||
double min_theta, double max_theta, double theta_step )
|
||||
{
|
||||
std::vector<Vec3d> lines;
|
||||
std::vector<Point2f> point;
|
||||
_point.copyTo(point);
|
||||
|
||||
CV_Assert( _point.type() == CV_32FC2 || _point.type() == CV_32SC2 );
|
||||
if( lines_max <= 0 ) {
|
||||
CV_Error( Error::StsBadArg, "lines_max must be greater than 0" );
|
||||
}
|
||||
if( threshold < 0) {
|
||||
CV_Error( Error::StsBadArg, "threshold must be greater than 0" );
|
||||
}
|
||||
if( ((max_rho - min_rho) <= 0) || ((max_theta - min_theta) <= 0) ) {
|
||||
CV_Error( Error::StsBadArg, "max must be greater than min" );
|
||||
}
|
||||
if( ((rho_step <= 0)) || ((theta_step <= 0)) ) {
|
||||
CV_Error( Error::StsBadArg, "step must be greater than 0" );
|
||||
}
|
||||
|
||||
int i;
|
||||
float irho = 1 / (float)rho_step;
|
||||
float irho_min = ((float)min_rho * irho);
|
||||
int numangle = cvRound((max_theta - min_theta) / theta_step);
|
||||
int numrho = cvRound((max_rho - min_rho + 1) / rho_step);
|
||||
|
||||
Mat _accum = Mat::zeros( (numangle+2), (numrho+2), CV_32SC1 );
|
||||
std::vector<int> _sort_buf;
|
||||
AutoBuffer<float> _tabSin(numangle);
|
||||
AutoBuffer<float> _tabCos(numangle);
|
||||
int *accum = _accum.ptr<int>();
|
||||
float *tabSin = _tabSin, *tabCos = _tabCos;
|
||||
|
||||
// create sin and cos table
|
||||
createTrigTable( numangle, min_theta, theta_step,
|
||||
irho, tabSin, tabCos );
|
||||
|
||||
// stage 1. fill accumlator
|
||||
for( i = 0; i < (int)point.size(); i++ )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int r = cvRound( point.at(i).x * tabCos[n] + point.at(i).y * tabSin[n] - irho_min);
|
||||
accum[(n+1) * (numrho+2) + r+1]++;
|
||||
}
|
||||
|
||||
// stage 2. find local maximums
|
||||
findLocalMaximums( numrho, numangle, threshold, accum, _sort_buf );
|
||||
|
||||
// stage 3. sort the detected lines by accumulator value
|
||||
std::sort(_sort_buf.begin(), _sort_buf.end(), hough_cmp_gt(accum));
|
||||
|
||||
// stage 4. store the first min(total,linesMax) lines to the output buffer
|
||||
lines_max = std::min(lines_max, (int)_sort_buf.size());
|
||||
double scale = 1./(numrho+2);
|
||||
for( i = 0; i < lines_max; i++ )
|
||||
{
|
||||
LinePolar line;
|
||||
int idx = _sort_buf[i];
|
||||
int n = cvFloor(idx*scale) - 1;
|
||||
int r = idx - (n+1)*(numrho+2) - 1;
|
||||
line.rho = static_cast<float>(min_rho) + r * (float)rho_step;
|
||||
line.angle = static_cast<float>(min_theta) + n * (float)theta_step;
|
||||
lines.push_back(Vec3d((double)accum[idx], (double)line.rho, (double)line.angle));
|
||||
}
|
||||
|
||||
Mat(lines).copyTo(_lines);
|
||||
}
|
||||
|
||||
/****************************************************************************************\
|
||||
* Circle Detection *
|
||||
\****************************************************************************************/
|
||||
@ -1611,7 +1695,6 @@ void HoughCircles( InputArray _image, OutputArray _circles,
|
||||
{
|
||||
HoughCircles(_image, _circles, method, dp, minDist, param1, param2, minRadius, maxRadius, -1, 3);
|
||||
}
|
||||
|
||||
} // \namespace cv
|
||||
|
||||
|
||||
|
@ -139,6 +139,29 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
typedef tuple<double, double, double, double> HoughLinesPointSetInput_t;
|
||||
class HoughLinesPointSetTest : public testing::TestWithParam<HoughLinesPointSetInput_t>
|
||||
{
|
||||
protected:
|
||||
void run_test();
|
||||
double Rho;
|
||||
double Theta;
|
||||
double rhoMin, rhoMax, rhoStep;
|
||||
double thetaMin, thetaMax, thetaStep;
|
||||
public:
|
||||
HoughLinesPointSetTest()
|
||||
{
|
||||
rhoMin = get<0>(GetParam());
|
||||
rhoMax = get<1>(GetParam());
|
||||
rhoStep = (rhoMax - rhoMin) / 360.0f;
|
||||
thetaMin = get<2>(GetParam());
|
||||
thetaMax = get<3>(GetParam());
|
||||
thetaStep = CV_PI / 180.0f;
|
||||
Rho = 320.00000;
|
||||
Theta = 1.04719;
|
||||
}
|
||||
};
|
||||
|
||||
void BaseHoughLineTest::run_test(int type)
|
||||
{
|
||||
string filename = cvtest::TS::ptr()->get_data_path() + picture_name;
|
||||
@ -195,6 +218,50 @@ void BaseHoughLineTest::run_test(int type)
|
||||
#endif
|
||||
}
|
||||
|
||||
void HoughLinesPointSetTest::run_test(void)
|
||||
{
|
||||
Mat lines_f, lines_i;
|
||||
vector<Point2f> pointf;
|
||||
vector<Point2i> pointi;
|
||||
vector<Vec3d> line_polar_f, line_polar_i;
|
||||
const float Points[20][2] = {
|
||||
{ 0.0f, 369.0f }, { 10.0f, 364.0f }, { 20.0f, 358.0f }, { 30.0f, 352.0f },
|
||||
{ 40.0f, 346.0f }, { 50.0f, 341.0f }, { 60.0f, 335.0f }, { 70.0f, 329.0f },
|
||||
{ 80.0f, 323.0f }, { 90.0f, 318.0f }, { 100.0f, 312.0f }, { 110.0f, 306.0f },
|
||||
{ 120.0f, 300.0f }, { 130.0f, 295.0f }, { 140.0f, 289.0f }, { 150.0f, 284.0f },
|
||||
{ 160.0f, 277.0f }, { 170.0f, 271.0f }, { 180.0f, 266.0f }, { 190.0f, 260.0f }
|
||||
};
|
||||
|
||||
// Float
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
pointf.push_back(Point2f(Points[i][0],Points[i][1]));
|
||||
}
|
||||
|
||||
HoughLinesPointSet(pointf, lines_f, 20, 1,
|
||||
rhoMin, rhoMax, rhoStep,
|
||||
thetaMin, thetaMax, thetaStep);
|
||||
|
||||
lines_f.copyTo( line_polar_f );
|
||||
|
||||
// Integer
|
||||
for( int i = 0; i < 20; i++ )
|
||||
{
|
||||
pointi.push_back( Point2i( (int)Points[i][0], (int)Points[i][1] ) );
|
||||
}
|
||||
|
||||
HoughLinesPointSet( pointi, lines_i, 20, 1,
|
||||
rhoMin, rhoMax, rhoStep,
|
||||
thetaMin, thetaMax, thetaStep );
|
||||
|
||||
lines_i.copyTo( line_polar_i );
|
||||
|
||||
EXPECT_EQ((int)(line_polar_f.at(0).val[1] * 100000.0f), (int)(Rho * 100000.0f));
|
||||
EXPECT_EQ((int)(line_polar_f.at(0).val[2] * 100000.0f), (int)(Theta * 100000.0f));
|
||||
EXPECT_EQ((int)(line_polar_i.at(0).val[1] * 100000.0f), (int)(Rho * 100000.0f));
|
||||
EXPECT_EQ((int)(line_polar_i.at(0).val[2] * 100000.0f), (int)(Theta * 100000.0f));
|
||||
}
|
||||
|
||||
TEST_P(StandartHoughLinesTest, regression)
|
||||
{
|
||||
run_test(STANDART);
|
||||
@ -205,6 +272,11 @@ TEST_P(ProbabilisticHoughLinesTest, regression)
|
||||
run_test(PROBABILISTIC);
|
||||
}
|
||||
|
||||
TEST_P(HoughLinesPointSetTest, regression)
|
||||
{
|
||||
run_test();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P( ImgProc, StandartHoughLinesTest, testing::Combine(testing::Values( "shared/pic5.png", "../stitching/a1.png" ),
|
||||
testing::Values( 1, 10 ),
|
||||
testing::Values( 0.05, 0.1 ),
|
||||
@ -219,4 +291,10 @@ INSTANTIATE_TEST_CASE_P( ImgProc, ProbabilisticHoughLinesTest, testing::Combine(
|
||||
testing::Values( 0, 4 )
|
||||
));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P( Imgproc, HoughLinesPointSetTest, testing::Combine(testing::Values( 0.0f, 120.0f ),
|
||||
testing::Values( 360.0f, 480.0f ),
|
||||
testing::Values( 0.0f, (CV_PI / 18.0f) ),
|
||||
testing::Values( (CV_PI / 2.0f), (CV_PI * 5.0f / 12.0f) )
|
||||
));
|
||||
|
||||
}} // namespace
|
||||
|
@ -0,0 +1,33 @@
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
int main()
|
||||
{
|
||||
Mat lines;
|
||||
vector<Vec3d> line3d;
|
||||
vector<Point2f> point;
|
||||
const static float Points[20][2] = {
|
||||
{ 0.0f, 369.0f }, { 10.0f, 364.0f }, { 20.0f, 358.0f }, { 30.0f, 352.0f },
|
||||
{ 40.0f, 346.0f }, { 50.0f, 341.0f }, { 60.0f, 335.0f }, { 70.0f, 329.0f },
|
||||
{ 80.0f, 323.0f }, { 90.0f, 318.0f }, { 100.0f, 312.0f }, { 110.0f, 306.0f },
|
||||
{ 120.0f, 300.0f }, { 130.0f, 295.0f }, { 140.0f, 289.0f }, { 150.0f, 284.0f },
|
||||
{ 160.0f, 277.0f }, { 170.0f, 271.0f }, { 180.0f, 266.0f }, { 190.0f, 260.0f }
|
||||
};
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
point.push_back(Point2f(Points[i][0],Points[i][1]));
|
||||
}
|
||||
|
||||
double rhoMin = 0.0f, rhoMax = 360.0f, rhoStep = 1;
|
||||
double thetaMin = 0.0f, thetaMax = CV_PI / 2.0f, thetaStep = CV_PI / 180.0f;
|
||||
|
||||
HoughLinesPointSet(point, lines, 20, 1,
|
||||
rhoMin, rhoMax, rhoStep,
|
||||
thetaMin, thetaMax, thetaStep);
|
||||
|
||||
lines.copyTo(line3d);
|
||||
printf("votes:%d, rho:%.7f, theta:%.7f\n",(int)line3d.at(0).val[0], line3d.at(0).val[1], line3d.at(0).val[2]);
|
||||
}
|
Loading…
Reference in New Issue
Block a user