mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 07:43:03 +04:00
Merge pull request #11108 from take1014:hough_4303
* Added accumulator value to the output of HoughLines and HoughCircles * imgproc: refactor Hough patch - eliminate code duplication - fix type handling, fix OpenCL code - fix test data generation - re-generated test data in debug mode via plain CPU code path
This commit is contained in:
committed by
Alexander Alekhin
parent
2d5d98ec0f
commit
ed207d79e7
+130
-45
@@ -105,48 +105,56 @@ array of (rho, theta) pairs. linesMax is the buffer size (number of pairs).
|
||||
Functions return the actual number of found lines.
|
||||
*/
|
||||
static void
|
||||
HoughLinesStandard( const Mat& img, float rho, float theta,
|
||||
int threshold, std::vector<Vec2f>& lines, int linesMax,
|
||||
HoughLinesStandard( InputArray src, OutputArray lines, int type,
|
||||
float rho, float theta,
|
||||
int threshold, int linesMax,
|
||||
double min_theta, double max_theta )
|
||||
{
|
||||
CV_CheckType(type, type == CV_32FC2 || type == CV_32FC3, "Internal error");
|
||||
|
||||
Mat img = src.getMat();
|
||||
|
||||
int i, j;
|
||||
float irho = 1 / rho;
|
||||
|
||||
CV_Assert( img.type() == CV_8UC1 );
|
||||
CV_Assert( linesMax > 0 );
|
||||
|
||||
const uchar* image = img.ptr();
|
||||
int step = (int)img.step;
|
||||
int width = img.cols;
|
||||
int height = img.rows;
|
||||
|
||||
if (max_theta < min_theta ) {
|
||||
CV_Error( CV_StsBadArg, "max_theta must be greater than min_theta" );
|
||||
}
|
||||
int max_rho = width + height;
|
||||
int min_rho = -max_rho;
|
||||
|
||||
CV_CheckGE(max_theta, min_theta, "max_theta must be greater than min_theta");
|
||||
|
||||
int numangle = cvRound((max_theta - min_theta) / theta);
|
||||
int numrho = cvRound(((width + height) * 2 + 1) / rho);
|
||||
int numrho = cvRound(((max_rho - min_rho) + 1) / rho);
|
||||
|
||||
#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_HOUGH
|
||||
CV_IPP_CHECK()
|
||||
if (type == CV_32FC2 && CV_IPP_CHECK_COND)
|
||||
{
|
||||
IppiSize srcSize = { width, height };
|
||||
IppPointPolar delta = { rho, theta };
|
||||
IppPointPolar dstRoi[2] = {{(Ipp32f) -(width + height), (Ipp32f) min_theta},{(Ipp32f) (width + height), (Ipp32f) max_theta}};
|
||||
IppPointPolar dstRoi[2] = {{(Ipp32f) min_rho, (Ipp32f) min_theta},{(Ipp32f) max_rho, (Ipp32f) max_theta}};
|
||||
int bufferSize;
|
||||
int nz = countNonZero(img);
|
||||
int ipp_linesMax = std::min(linesMax, nz*numangle/threshold);
|
||||
int linesCount = 0;
|
||||
lines.resize(ipp_linesMax);
|
||||
std::vector<Vec2f> _lines(ipp_linesMax);
|
||||
IppStatus ok = ippiHoughLineGetSize_8u_C1R(srcSize, delta, ipp_linesMax, &bufferSize);
|
||||
Ipp8u* buffer = ippsMalloc_8u_L(bufferSize);
|
||||
if (ok >= 0) {ok = CV_INSTRUMENT_FUN_IPP(ippiHoughLine_Region_8u32f_C1R, image, step, srcSize, (IppPointPolar*) &lines[0], dstRoi, ipp_linesMax, &linesCount, delta, threshold, buffer);};
|
||||
if (ok >= 0) {ok = CV_INSTRUMENT_FUN_IPP(ippiHoughLine_Region_8u32f_C1R, image, step, srcSize, (IppPointPolar*) &_lines[0], dstRoi, ipp_linesMax, &linesCount, delta, threshold, buffer);};
|
||||
ippsFree(buffer);
|
||||
if (ok >= 0)
|
||||
{
|
||||
lines.resize(linesCount);
|
||||
lines.create(linesCount, 1, CV_32FC2);
|
||||
Mat(linesCount, 1, CV_32FC2, &_lines[0]).copyTo(lines);
|
||||
CV_IMPL_ADD(CV_IMPL_IPP);
|
||||
return;
|
||||
}
|
||||
lines.clear();
|
||||
setIppErrorStatus();
|
||||
}
|
||||
#endif
|
||||
@@ -185,6 +193,9 @@ HoughLinesStandard( const Mat& img, float rho, float theta,
|
||||
// stage 4. store the first min(total,linesMax) lines to the output buffer
|
||||
linesMax = std::min(linesMax, (int)_sort_buf.size());
|
||||
double scale = 1./(numrho+2);
|
||||
|
||||
lines.create(linesMax, 1, type);
|
||||
Mat _lines = lines.getMat();
|
||||
for( i = 0; i < linesMax; i++ )
|
||||
{
|
||||
LinePolar line;
|
||||
@@ -193,7 +204,15 @@ HoughLinesStandard( const Mat& img, float rho, float theta,
|
||||
int r = idx - (n+1)*(numrho+2) - 1;
|
||||
line.rho = (r - (numrho - 1)*0.5f) * rho;
|
||||
line.angle = static_cast<float>(min_theta) + n * theta;
|
||||
lines.push_back(Vec2f(line.rho, line.angle));
|
||||
if (type == CV_32FC2)
|
||||
{
|
||||
_lines.at<Vec2f>(i) = Vec2f(line.rho, line.angle);
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_DbgAssert(type == CV_32FC3);
|
||||
_lines.at<Vec3f>(i) = Vec3f(line.rho, line.angle, (float)accum[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,15 +231,17 @@ struct hough_index
|
||||
|
||||
|
||||
static void
|
||||
HoughLinesSDiv( const Mat& img,
|
||||
HoughLinesSDiv( InputArray image, OutputArray lines, int type,
|
||||
float rho, float theta, int threshold,
|
||||
int srn, int stn,
|
||||
std::vector<Vec2f>& lines, int linesMax,
|
||||
int srn, int stn, int linesMax,
|
||||
double min_theta, double max_theta )
|
||||
{
|
||||
CV_CheckType(type, type == CV_32FC2 || type == CV_32FC3, "Internal error");
|
||||
|
||||
#define _POINT(row, column)\
|
||||
(image_src[(row)*step+(column)])
|
||||
|
||||
Mat img = image.getMat();
|
||||
int index, i;
|
||||
int ri, ti, ti1, ti0;
|
||||
int row, col;
|
||||
@@ -343,7 +364,7 @@ HoughLinesSDiv( const Mat& img,
|
||||
|
||||
if( count * 100 > rn * tn )
|
||||
{
|
||||
HoughLinesStandard( img, rho, theta, threshold, lines, linesMax, min_theta, max_theta );
|
||||
HoughLinesStandard( image, lines, type, rho, theta, threshold, linesMax, min_theta, max_theta );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -415,11 +436,21 @@ HoughLinesSDiv( const Mat& img,
|
||||
}
|
||||
}
|
||||
|
||||
lines.create((int)lst.size(), 1, type);
|
||||
Mat _lines = lines.getMat();
|
||||
for( size_t idx = 0; idx < lst.size(); idx++ )
|
||||
{
|
||||
if( lst[idx].rho < 0 )
|
||||
continue;
|
||||
lines.push_back(Vec2f(lst[idx].rho, lst[idx].theta));
|
||||
if (type == CV_32FC2)
|
||||
{
|
||||
_lines.at<Vec2f>((int)idx) = Vec2f(lst[idx].rho, lst[idx].theta);
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_DbgAssert(type == CV_32FC3);
|
||||
_lines.at<Vec3f>((int)idx) = Vec3f(lst[idx].rho, lst[idx].theta, (float)lst[idx].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -861,24 +892,26 @@ static bool ocl_HoughLinesP(InputArray _src, OutputArray _lines, double rho, dou
|
||||
|
||||
#endif /* HAVE_OPENCL */
|
||||
|
||||
void HoughLines( InputArray _image, OutputArray _lines,
|
||||
void HoughLines( InputArray _image, OutputArray lines,
|
||||
double rho, double theta, int threshold,
|
||||
double srn, double stn, double min_theta, double max_theta )
|
||||
{
|
||||
CV_INSTRUMENT_REGION()
|
||||
|
||||
CV_OCL_RUN(srn == 0 && stn == 0 && _image.isUMat() && _lines.isUMat(),
|
||||
ocl_HoughLines(_image, _lines, rho, theta, threshold, min_theta, max_theta));
|
||||
int type = CV_32FC2;
|
||||
if (lines.fixedType())
|
||||
{
|
||||
type = lines.type();
|
||||
CV_CheckType(type, type == CV_32FC2 || type == CV_32FC3, "Wrong type of output lines");
|
||||
}
|
||||
|
||||
Mat image = _image.getMat();
|
||||
std::vector<Vec2f> lines;
|
||||
CV_OCL_RUN(srn == 0 && stn == 0 && _image.isUMat() && lines.isUMat() && type == CV_32FC2,
|
||||
ocl_HoughLines(_image, lines, rho, theta, threshold, min_theta, max_theta));
|
||||
|
||||
if( srn == 0 && stn == 0 )
|
||||
HoughLinesStandard(image, (float)rho, (float)theta, threshold, lines, INT_MAX, min_theta, max_theta );
|
||||
HoughLinesStandard(_image, lines, type, (float)rho, (float)theta, threshold, INT_MAX, min_theta, max_theta );
|
||||
else
|
||||
HoughLinesSDiv(image, (float)rho, (float)theta, threshold, cvRound(srn), cvRound(stn), lines, INT_MAX, min_theta, max_theta);
|
||||
|
||||
Mat(lines).copyTo(_lines);
|
||||
HoughLinesSDiv(_image, lines, type, (float)rho, (float)theta, threshold, cvRound(srn), cvRound(stn), INT_MAX, min_theta, max_theta);
|
||||
}
|
||||
|
||||
|
||||
@@ -1007,11 +1040,16 @@ static bool cmpAccum(const EstimatedCircle& left, const EstimatedCircle& right)
|
||||
return false;
|
||||
}
|
||||
|
||||
inline Vec3f GetCircle(const EstimatedCircle& est)
|
||||
static inline Vec3f GetCircle(const EstimatedCircle& est)
|
||||
{
|
||||
return est.c;
|
||||
}
|
||||
|
||||
static inline Vec4f GetCircle4f(const EstimatedCircle& est)
|
||||
{
|
||||
return Vec4f(est.c[0], est.c[1], est.c[2], (float)est.accum);
|
||||
}
|
||||
|
||||
class NZPointList : public std::vector<Point>
|
||||
{
|
||||
private:
|
||||
@@ -1264,12 +1302,13 @@ private:
|
||||
Mutex& _lock;
|
||||
};
|
||||
|
||||
static bool CheckDistance(const std::vector<Vec3f> &circles, size_t endIdx, const Vec3f& circle, float minDist2)
|
||||
template<typename T>
|
||||
static bool CheckDistance(const std::vector<T> &circles, size_t endIdx, const T& circle, float minDist2)
|
||||
{
|
||||
bool goodPoint = true;
|
||||
for (uint j = 0; j < endIdx; ++j)
|
||||
{
|
||||
Vec3f pt = circles[j];
|
||||
T pt = circles[j];
|
||||
float distX = circle[0] - pt[0], distY = circle[1] - pt[1];
|
||||
if (distX * distX + distY * distY < minDist2)
|
||||
{
|
||||
@@ -1297,13 +1336,31 @@ static void GetCircleCenters(const std::vector<int> ¢ers, std::vector<Vec3f>
|
||||
}
|
||||
}
|
||||
|
||||
static void RemoveOverlaps(std::vector<Vec3f>& circles, float minDist)
|
||||
static void GetCircleCenters(const std::vector<int> ¢ers, std::vector<Vec4f> &circles, int acols, float minDist, float dr)
|
||||
{
|
||||
size_t centerCnt = centers.size();
|
||||
float minDist2 = minDist * minDist;
|
||||
for (size_t i = 0; i < centerCnt; ++i)
|
||||
{
|
||||
int center = centers[i];
|
||||
int y = center / acols;
|
||||
int x = center - y * acols;
|
||||
Vec4f circle = Vec4f((x + 0.5f) * dr, (y + 0.5f) * dr, 0, (float)center);
|
||||
|
||||
bool goodPoint = CheckDistance(circles, circles.size(), circle, minDist2);
|
||||
if (goodPoint)
|
||||
circles.push_back(circle);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void RemoveOverlaps(std::vector<T>& circles, float minDist)
|
||||
{
|
||||
float minDist2 = minDist * minDist;
|
||||
size_t endIdx = 1;
|
||||
for (size_t i = 1; i < circles.size(); ++i)
|
||||
{
|
||||
Vec3f circle = circles[i];
|
||||
T circle = circles[i];
|
||||
if (CheckDistance(circles, endIdx, circle, minDist2))
|
||||
{
|
||||
circles[endIdx] = circle;
|
||||
@@ -1313,6 +1370,16 @@ static void RemoveOverlaps(std::vector<Vec3f>& circles, float minDist)
|
||||
circles.resize(endIdx);
|
||||
}
|
||||
|
||||
static void CreateCircles(const std::vector<EstimatedCircle>& circlesEst, std::vector<Vec3f>& circles)
|
||||
{
|
||||
std::transform(circlesEst.begin(), circlesEst.end(), std::back_inserter(circles), GetCircle);
|
||||
}
|
||||
|
||||
static void CreateCircles(const std::vector<EstimatedCircle>& circlesEst, std::vector<Vec4f>& circles)
|
||||
{
|
||||
std::transform(circlesEst.begin(), circlesEst.end(), std::back_inserter(circles), GetCircle4f);
|
||||
}
|
||||
|
||||
template<class NZPoints>
|
||||
class HoughCircleEstimateRadiusInvoker : public ParallelLoopBody
|
||||
{
|
||||
@@ -1556,11 +1623,14 @@ inline int HoughCircleEstimateRadiusInvoker<NZPointSet>::filterCircles(const Poi
|
||||
return nzCount;
|
||||
}
|
||||
|
||||
static void HoughCirclesGradient(InputArray _image, OutputArray _circles, float dp, float minDist,
|
||||
template <typename CircleType>
|
||||
static void HoughCirclesGradient(InputArray _image, OutputArray _circles,
|
||||
float dp, float minDist,
|
||||
int minRadius, int maxRadius, int cannyThreshold,
|
||||
int accThreshold, int maxCircles, int kernelSize, bool centersOnly)
|
||||
{
|
||||
CV_Assert(kernelSize == -1 || kernelSize == 3 || kernelSize == 5 || kernelSize == 7);
|
||||
|
||||
dp = max(dp, 1.f);
|
||||
float idp = 1.f/dp;
|
||||
|
||||
@@ -1602,7 +1672,7 @@ static void HoughCirclesGradient(InputArray _image, OutputArray _circles, float
|
||||
|
||||
std::sort(centers.begin(), centers.end(), hough_cmp_gt(accum.ptr<int>()));
|
||||
|
||||
std::vector<Vec3f> circles;
|
||||
std::vector<CircleType> circles;
|
||||
circles.reserve(256);
|
||||
if (centersOnly)
|
||||
{
|
||||
@@ -1635,15 +1705,16 @@ static void HoughCirclesGradient(InputArray _image, OutputArray _circles, float
|
||||
|
||||
// Sort by accumulator value
|
||||
std::sort(circlesEst.begin(), circlesEst.end(), cmpAccum);
|
||||
std::transform(circlesEst.begin(), circlesEst.end(), std::back_inserter(circles), GetCircle);
|
||||
|
||||
// Create Circles
|
||||
CreateCircles(circlesEst, circles);
|
||||
RemoveOverlaps(circles, minDist);
|
||||
}
|
||||
|
||||
if(circles.size() > 0)
|
||||
if (circles.size() > 0)
|
||||
{
|
||||
int numCircles = std::min(maxCircles, int(circles.size()));
|
||||
_circles.create(1, numCircles, CV_32FC3);
|
||||
Mat(1, numCircles, CV_32FC3, &circles[0]).copyTo(_circles.getMat());
|
||||
Mat(1, numCircles, cv::traits::Type<CircleType>::value, &circles[0]).copyTo(_circles);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1656,6 +1727,13 @@ static void HoughCircles( InputArray _image, OutputArray _circles,
|
||||
{
|
||||
CV_INSTRUMENT_REGION()
|
||||
|
||||
int type = CV_32FC3;
|
||||
if( _circles.fixedType() )
|
||||
{
|
||||
type = _circles.type();
|
||||
CV_CheckType(type, type == CV_32FC3 || type == CV_32FC4, "Wrong type of output circles");
|
||||
}
|
||||
|
||||
CV_Assert(!_image.empty() && _image.type() == CV_8UC1 && (_image.isMat() || _image.isUMat()));
|
||||
CV_Assert(_circles.isMat() || _circles.isVector());
|
||||
|
||||
@@ -1679,9 +1757,16 @@ static void HoughCircles( InputArray _image, OutputArray _circles,
|
||||
switch( method )
|
||||
{
|
||||
case CV_HOUGH_GRADIENT:
|
||||
HoughCirclesGradient(_image, _circles, (float)dp, (float)minDist,
|
||||
minRadius, maxRadius, cannyThresh,
|
||||
accThresh, maxCircles, kernelSize, centersOnly);
|
||||
if (type == CV_32FC3)
|
||||
HoughCirclesGradient<Vec3f>(_image, _circles, (float)dp, (float)minDist,
|
||||
minRadius, maxRadius, cannyThresh,
|
||||
accThresh, maxCircles, kernelSize, centersOnly);
|
||||
else if (type == CV_32FC4)
|
||||
HoughCirclesGradient<Vec4f>(_image, _circles, (float)dp, (float)minDist,
|
||||
minRadius, maxRadius, cannyThresh,
|
||||
accThresh, maxCircles, kernelSize, centersOnly);
|
||||
else
|
||||
CV_Error(Error::StsError, "Internal error");
|
||||
break;
|
||||
default:
|
||||
CV_Error( Error::StsBadArg, "Unrecognized method id. Actually only CV_HOUGH_GRADIENT is supported." );
|
||||
@@ -1764,12 +1849,12 @@ cvHoughLines2( CvArr* src_image, void* lineStorage, int method,
|
||||
switch( method )
|
||||
{
|
||||
case CV_HOUGH_STANDARD:
|
||||
HoughLinesStandard( image, (float)rho,
|
||||
(float)theta, threshold, l2, linesMax, min_theta, max_theta );
|
||||
HoughLinesStandard( image, l2, CV_32FC2, (float)rho,
|
||||
(float)theta, threshold, linesMax, min_theta, max_theta );
|
||||
break;
|
||||
case CV_HOUGH_MULTI_SCALE:
|
||||
HoughLinesSDiv( image, (float)rho, (float)theta,
|
||||
threshold, iparam1, iparam2, l2, linesMax, min_theta, max_theta );
|
||||
HoughLinesSDiv( image, l2, CV_32FC2, (float)rho, (float)theta,
|
||||
threshold, iparam1, iparam2, linesMax, min_theta, max_theta );
|
||||
break;
|
||||
case CV_HOUGH_PROBABILISTIC:
|
||||
HoughLinesProbabilistic( image, (float)rho, (float)theta,
|
||||
|
||||
Reference in New Issue
Block a user