Commit c3f277b7 authored by Vladislav Vinogradov's avatar Vladislav Vinogradov

gpu version of HoughCircles

parent e60a50c4
......@@ -893,7 +893,7 @@ Finds lines in a binary image using the classical Hough transform.
.. ocv:function:: void gpu::HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096)
.. ocv:function:: void gpu::HoughLines(const GpuMat& src, GpuMat& lines, GpuMat& accum, GpuMat& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096)
.. ocv:function:: void gpu::HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096)
:param src: 8-bit, single-channel binary source image.
......@@ -909,70 +909,70 @@ Finds lines in a binary image using the classical Hough transform.
:param maxLines: Maximum number of output lines.
:param accum: Optional buffer for accumulator to avoid extra memory allocations (for many calls with the same sizes).
:param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes).
.. seealso:: :ocv:func:`HoughLines`
gpu::HoughLinesTransform
------------------------
Performs classical Hough transform for line detection.
gpu::HoughLinesDownload
-----------------------
Downloads results from :ocv:func:`gpu::HoughLines` to host memory.
.. ocv:function:: void gpu::HoughLinesTransform(const GpuMat& src, GpuMat& accum, GpuMat& buf, float rho, float theta)
.. ocv:function:: void gpu::HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines, OutputArray h_votes = noArray())
:param src: 8-bit, single-channel binary source image.
:param d_lines: Result of :ocv:func:`gpu::HoughLines` .
:param accum: Output accumulator array.
:param h_lines: Output host array.
:param buf: Buffer to avoid extra memory allocations (for many calls with the same sizes).
:param h_votes: Optional output array for line's votes.
:param rho: Distance resolution of the accumulator in pixels.
.. seealso:: :ocv:func:`gpu::HoughLines`
:param theta: Angle resolution of the accumulator in radians.
:param threshold: Accumulator threshold parameter. Only those lines are returned that get enough votes ( :math:`>\texttt{threshold}` ).
.. seealso:: :ocv:func:`gpu::HoughLines`
gpu::HoughCircles
-----------------
Finds circles in a grayscale image using the Hough transform.
.. ocv:function:: void gpu::HoughCircles(const GpuMat& src, GpuMat& circles, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096)
.. ocv:function:: void gpu::HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096)
gpu::HoughLinesGet
------------------
Finds lines in Hough space.
:param src: 8-bit, single-channel grayscale input image.
.. ocv:function:: void gpu::HoughLinesGet(const GpuMat& accum, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096)
:param circles: Output vector of found circles. Each vector is encoded as a 3-element floating-point vector :math:`(x, y, radius)` .
:param accum: Accumulator array.
:param method: Detection method to use. Currently, the only implemented method is ``CV_HOUGH_GRADIENT`` , which is basically *21HT* , described in [Yuen90]_.
:param lines: Output vector of lines. Each line is represented by a two-element vector :math:`(\rho, \theta)` . :math:`\rho` is the distance from the coordinate origin :math:`(0,0)` (top-left corner of the image). :math:`\theta` is the line rotation angle in radians ( :math:`0 \sim \textrm{vertical line}, \pi/2 \sim \textrm{horizontal line}` ).
:param dp: Inverse ratio of the accumulator resolution to the image resolution. For example, if ``dp=1`` , the accumulator has the same resolution as the input image. If ``dp=2`` , the accumulator has half as big width and height.
:param rho: Distance resolution of the accumulator in pixels.
:param minDist: Minimum distance between the centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed.
:param theta: Angle resolution of the accumulator in radians.
:param cannyThreshold: The higher threshold of the two passed to the :ocv:func:`gpu::Canny` edge detector (the lower one is twice smaller).
:param threshold: Accumulator threshold parameter. Only those lines are returned that get enough votes ( :math:`>\texttt{threshold}` ).
:param votesThreshold: The accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected.
:param doSort: Performs lines sort by votes.
:param minRadius: Minimum circle radius.
:param maxLines: Maximum number of output lines.
:param maxRadius: Maximum circle radius.
.. seealso:: :ocv:func:`gpu::HoughLines`
:param maxCircles: Maximum number of output circles.
:param buf: Optional buffer to avoid extra memory allocations (for many calls with the same sizes).
.. seealso:: :ocv:func:`HoughCircles`
gpu::HoughLinesDownload
-----------------------
Downloads results from :ocv:func:`gpu::HoughLines` to host memory.
.. ocv:function:: void gpu::HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines, OutputArray h_votes = noArray())
:param d_lines: Result of :ocv:func:`gpu::HoughLines` .
gpu::HoughCirclesDownload
-------------------------
Downloads results from :ocv:func:`gpu::HoughCircles` to host memory.
:param h_lines: Output host array.
.. ocv:function:: void gpu::HoughCirclesDownload(const GpuMat& d_circles, OutputArray h_circles)
:param h_votes: Optional output array for line's votes.
:param d_circles: Result of :ocv:func:`gpu::HoughCircles` .
.. seealso:: :ocv:func:`gpu::HoughLines`
:param h_circles: Output host array.
.. seealso:: :ocv:func:`gpu::HoughCircles`
......@@ -821,12 +821,31 @@ private:
};
//! HoughLines
struct HoughLinesBuf
{
GpuMat accum;
GpuMat list;
};
CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096);
CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, GpuMat& accum, GpuMat& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096);
CV_EXPORTS void HoughLinesTransform(const GpuMat& src, GpuMat& accum, GpuMat& buf, float rho, float theta);
CV_EXPORTS void HoughLinesGet(const GpuMat& accum, GpuMat& lines, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096);
CV_EXPORTS void HoughLines(const GpuMat& src, GpuMat& lines, HoughLinesBuf& buf, float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096);
CV_EXPORTS void HoughLinesDownload(const GpuMat& d_lines, OutputArray h_lines, OutputArray h_votes = noArray());
//! HoughCircles
struct HoughCirclesBuf
{
GpuMat edges;
GpuMat accum;
GpuMat list;
CannyBuf cannyBuf;
};
CV_EXPORTS void HoughCircles(const GpuMat& src, GpuMat& circles, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096);
CV_EXPORTS void HoughCircles(const GpuMat& src, GpuMat& circles, HoughCirclesBuf& buf, int method, float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096);
CV_EXPORTS void HoughCirclesDownload(const GpuMat& d_circles, OutputArray h_circles);
////////////////////////////// Matrix reductions //////////////////////////////
//! computes mean value and standard deviation of all or selected array elements
......
......@@ -1609,14 +1609,11 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidGetLayer, Combine(GPU_TYPICAL_MAT_S
//////////////////////////////////////////////////////////////////////
// HoughLines
DEF_PARAM_TEST(Sz_DoSort, cv::Size, bool);
PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool()))
PERF_TEST_P(Sz, ImgProc_HoughLines, GPU_TYPICAL_MAT_SIZES)
{
declare.time(30.0);
const cv::Size size = GET_PARAM(0);
const bool doSort = GET_PARAM(1);
const cv::Size size = GetParam();
const float rho = 1.0f;
const float theta = static_cast<float>(CV_PI / 180.0);
......@@ -1638,14 +1635,13 @@ PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool()
{
cv::gpu::GpuMat d_src(src);
cv::gpu::GpuMat d_lines;
cv::gpu::GpuMat d_accum;
cv::gpu::GpuMat d_buf;
cv::gpu::HoughLinesBuf d_buf;
cv::gpu::HoughLines(d_src, d_lines, d_accum, d_buf, rho, theta, threshold, doSort);
cv::gpu::HoughLines(d_src, d_lines, d_buf, rho, theta, threshold);
TEST_CYCLE()
{
cv::gpu::HoughLines(d_src, d_lines, d_accum, d_buf, rho, theta, threshold, doSort);
cv::gpu::HoughLines(d_src, d_lines, d_buf, rho, theta, threshold);
}
}
else
......@@ -1660,4 +1656,61 @@ PERF_TEST_P(Sz_DoSort, ImgProc_HoughLines, Combine(GPU_TYPICAL_MAT_SIZES, Bool()
}
}
//////////////////////////////////////////////////////////////////////
// HoughCircles
DEF_PARAM_TEST(Sz_Dp_MinDist, cv::Size, float, float);
PERF_TEST_P(Sz_Dp_MinDist, ImgProc_HoughCircles, Combine(GPU_TYPICAL_MAT_SIZES, Values(1.0f, 2.0f, 4.0f), Values(1.0f, 10.0f)))
{
declare.time(30.0);
const cv::Size size = GET_PARAM(0);
const float dp = GET_PARAM(1);
const float minDist = GET_PARAM(2);
const int minRadius = 10;
const int maxRadius = 30;
const int cannyThreshold = 100;
const int votesThreshold = 15;
cv::RNG rng(123456789);
cv::Mat src(size, CV_8UC1, cv::Scalar::all(0));
const int numCircles = rng.uniform(50, 100);
for (int i = 0; i < numCircles; ++i)
{
cv::Point center(rng.uniform(0, src.cols), rng.uniform(0, src.rows));
const int radius = rng.uniform(minRadius, maxRadius + 1);
cv::circle(src, center, radius, cv::Scalar::all(255), -1);
}
if (runOnGpu)
{
cv::gpu::GpuMat d_src(src);
cv::gpu::GpuMat d_circles;
cv::gpu::HoughCirclesBuf d_buf;
cv::gpu::HoughCircles(d_src, d_circles, d_buf, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius);
TEST_CYCLE()
{
cv::gpu::HoughCircles(d_src, d_circles, d_buf, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius);
}
}
else
{
std::vector<cv::Vec3f> circles;
cv::HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius);
TEST_CYCLE()
{
cv::HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius);
}
}
}
} // namespace
......@@ -40,6 +40,6 @@ typedef perf::Size_MatType Sz_Type;
DEF_PARAM_TEST(Sz_Depth, cv::Size, MatDepth);
DEF_PARAM_TEST(Sz_Depth_Cn, cv::Size, MatDepth, int);
#define GPU_TYPICAL_MAT_SIZES testing::Values(perf::szSXGA, perf::sz720p, perf::sz1080p)
#define GPU_TYPICAL_MAT_SIZES testing::Values(perf::sz720p, perf::szSXGA, perf::sz1080p)
#endif // __OPENCV_PERF_GPU_UTILITY_HPP__
This diff is collapsed.
This diff is collapsed.
......@@ -1131,7 +1131,7 @@ INSTANTIATE_TEST_CASE_P(GPU_ImgProc, CornerMinEigen, testing::Combine(
PARAM_TEST_CASE(HoughLines, cv::gpu::DeviceInfo, cv::Size, UseRoi)
{
void generateLines(cv::Mat& img)
static void generateLines(cv::Mat& img)
{
img.setTo(cv::Scalar::all(0));
......@@ -1141,7 +1141,7 @@ PARAM_TEST_CASE(HoughLines, cv::gpu::DeviceInfo, cv::Size, UseRoi)
cv::line(img, cv::Point(img.cols, 0), cv::Point(0, img.rows), cv::Scalar::all(255));
}
void drawLines(cv::Mat& dst, const std::vector<cv::Vec2f>& lines)
static void drawLines(cv::Mat& dst, const std::vector<cv::Vec2f>& lines)
{
dst.setTo(cv::Scalar::all(0));
......@@ -1191,6 +1191,77 @@ INSTANTIATE_TEST_CASE_P(GPU_ImgProc, HoughLines, testing::Combine(
DIFFERENT_SIZES,
WHOLE_SUBMAT));
///////////////////////////////////////////////////////////////////////////////////////////////////////
// HoughCircles
PARAM_TEST_CASE(HoughCircles, cv::gpu::DeviceInfo, cv::Size, UseRoi)
{
static void drawCircles(cv::Mat& dst, const std::vector<cv::Vec3f>& circles, bool fill)
{
dst.setTo(cv::Scalar::all(0));
for (size_t i = 0; i < circles.size(); ++i)
cv::circle(dst, cv::Point(circles[i][0], circles[i][1]), circles[i][2], cv::Scalar::all(255), fill ? -1 : 1);
}
};
TEST_P(HoughCircles, Accuracy)
{
const cv::gpu::DeviceInfo devInfo = GET_PARAM(0);
cv::gpu::setDevice(devInfo.deviceID());
const cv::Size size = GET_PARAM(1);
const bool useRoi = GET_PARAM(2);
const float dp = 2.0f;
const float minDist = 10.0f;
const int minRadius = 10;
const int maxRadius = 20;
const int cannyThreshold = 100;
const int votesThreshold = 20;
std::vector<cv::Vec3f> circles_gold(4);
circles_gold[0] = cv::Vec3f(20, 20, minRadius);
circles_gold[1] = cv::Vec3f(90, 87, minRadius + 3);
circles_gold[2] = cv::Vec3f(30, 70, minRadius + 8);
circles_gold[3] = cv::Vec3f(80, 10, maxRadius);
cv::Mat src(size, CV_8UC1);
drawCircles(src, circles_gold, true);
cv::gpu::GpuMat d_circles;
cv::gpu::HoughCircles(loadMat(src, useRoi), d_circles, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius);
std::vector<cv::Vec3f> circles;
cv::gpu::HoughCirclesDownload(d_circles, circles);
ASSERT_FALSE(circles.empty());
for (size_t i = 0; i < circles.size(); ++i)
{
cv::Vec3f cur = circles[i];
bool found = false;
for (size_t j = 0; j < circles_gold.size(); ++j)
{
cv::Vec3f gold = circles_gold[j];
if (std::fabs(cur[0] - gold[0]) < minDist && std::fabs(cur[1] - gold[1]) < minDist && std::fabs(cur[2] - gold[2]) < minDist)
{
found = true;
break;
}
}
ASSERT_TRUE(found);
}
}
INSTANTIATE_TEST_CASE_P(GPU_ImgProc, HoughCircles, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES,
WHOLE_SUBMAT));
} // namespace
#endif // HAVE_CUDA
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment