refactored generalized hough (both CPU and GPU):
removed set/get methods from Algorithm (implement owns) removed GHT_* enumeration
This commit is contained in:
parent
4b234fa0a5
commit
7b87d72d80
@ -213,98 +213,19 @@ Creates implementation for :ocv:class:`gpu::HoughCirclesDetector` .
|
||||
|
||||
|
||||
|
||||
gpu::GeneralizedHough
|
||||
---------------------
|
||||
.. ocv:class:: gpu::GeneralizedHough : public Algorithm
|
||||
|
||||
Base class for generalized hough transform. ::
|
||||
|
||||
class CV_EXPORTS GeneralizedHough : public Algorithm
|
||||
{
|
||||
public:
|
||||
static Ptr<GeneralizedHough> create(int method);
|
||||
|
||||
virtual void setTemplate(InputArray templ, int cannyThreshold = 100, Point templCenter = Point(-1, -1)) = 0;
|
||||
virtual void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1)) = 0;
|
||||
|
||||
virtual void detect(InputArray image, OutputArray positions, int cannyThreshold = 100) = 0;
|
||||
virtual void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions) = 0;
|
||||
|
||||
virtual void downloadResults(InputArray d_positions, OutputArray h_positions, OutputArray h_votes = noArray()) = 0;
|
||||
};
|
||||
|
||||
|
||||
Finds arbitrary template in the grayscale image using Generalized Hough Transform.
|
||||
|
||||
|
||||
|
||||
gpu::GeneralizedHough::create
|
||||
-----------------------------
|
||||
Creates implementation for :ocv:class:`gpu::GeneralizedHough` .
|
||||
|
||||
.. ocv:function:: Ptr<GeneralizedHough> gpu::GeneralizedHough::create(int method)
|
||||
|
||||
:param method: Combination of flags ( ``cv::GeneralizedHough::GHT_POSITION`` , ``cv::GeneralizedHough::GHT_SCALE`` , ``cv::GeneralizedHough::GHT_ROTATION`` ) specifying transformation to find.
|
||||
|
||||
For full affine transformations (move + scale + rotation) [Guil1999]_ algorithm is used, otherwise [Ballard1981]_ algorithm is used.
|
||||
|
||||
|
||||
|
||||
gpu::GeneralizedHough::setTemplate
|
||||
gpu::createGeneralizedHoughBallard
|
||||
----------------------------------
|
||||
Set template to search.
|
||||
Creates implementation for generalized hough transform from [Ballard1981]_ .
|
||||
|
||||
.. ocv:function:: void gpu::GeneralizedHough::setTemplate(InputArray templ, int cannyThreshold = 100, Point templCenter = Point(-1, -1))
|
||||
|
||||
.. ocv:function:: void gpu::GeneralizedHough::setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1))
|
||||
|
||||
:param templ: Template image. Canny edge detector will be applied to extract template edges.
|
||||
|
||||
:param cannyThreshold: Threshold value for Canny edge detector.
|
||||
|
||||
:param templCenter: Center for rotation. By default image center will be used.
|
||||
|
||||
:param edges: Edge map for template image.
|
||||
|
||||
:param dx: First derivative of template image in the vertical direction. Support only ``CV_32S`` type.
|
||||
|
||||
:param dy: First derivative of template image in the horizontal direction. Support only ``CV_32S`` type.
|
||||
.. ocv:function:: Ptr<GeneralizedHoughBallard> gpu::createGeneralizedHoughBallard()
|
||||
|
||||
|
||||
|
||||
gpu::GeneralizedHough::detect
|
||||
-----------------------------
|
||||
Finds template (set by :ocv:func:`gpu::GeneralizedHough::setTemplate` ) in the grayscale image.
|
||||
gpu::createGeneralizedHoughGuil
|
||||
-------------------------------
|
||||
Creates implementation for generalized hough transform from [Guil1999]_ .
|
||||
|
||||
.. ocv:function:: void gpu::GeneralizedHough::detect(InputArray image, OutputArray positions, int cannyThreshold = 100)
|
||||
|
||||
.. ocv:function:: void gpu::GeneralizedHough::detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions)
|
||||
|
||||
:param templ: Input image. Canny edge detector will be applied to extract template edges.
|
||||
|
||||
:param positions: Output vector of found objects. Each vector is encoded as a 4-element floating-point vector :math:`(x, y, scale, angle)` .
|
||||
|
||||
:param cannyThreshold: Threshold value for Canny edge detector.
|
||||
|
||||
:param edges: Edge map for input image.
|
||||
|
||||
:param dx: First derivative of input image in the vertical direction. Support only ``CV_32S`` type.
|
||||
|
||||
:param dy: First derivative of input image in the horizontal direction. Support only ``CV_32S`` type.
|
||||
|
||||
|
||||
|
||||
gpu::GeneralizedHough::downloadResults
|
||||
--------------------------------------
|
||||
Downloads results from :ocv:func:`gpu::GeneralizedHough::detect` to host memory.
|
||||
|
||||
.. ocv:function:: void gpu::GeneralizedHough::downloadResult(InputArray d_positions, OutputArray h_positions, OutputArray h_votes = noArray())
|
||||
|
||||
:param d_lines: Result of :ocv:func:`gpu::GeneralizedHough::detect` .
|
||||
|
||||
:param h_lines: Output host array.
|
||||
|
||||
:param h_votes: Optional output array for votes. Each vector is encoded as a 3-element integer-point vector :math:`(position_votes, scale_votes, angle_votes)` .
|
||||
.. ocv:function:: Ptr<GeneralizedHoughGuil> gpu::createGeneralizedHoughGuil()
|
||||
|
||||
|
||||
|
||||
|
@ -283,24 +283,13 @@ CV_EXPORTS Ptr<HoughCirclesDetector> createHoughCirclesDetector(float dp, float
|
||||
//////////////////////////////////////
|
||||
// GeneralizedHough
|
||||
|
||||
//! finds arbitrary template in the grayscale image using Generalized Hough Transform
|
||||
//! Ballard, D.H. (1981). Generalizing the Hough transform to detect arbitrary shapes. Pattern Recognition 13 (2): 111-122.
|
||||
//! Detects position only without traslation and rotation
|
||||
CV_EXPORTS Ptr<GeneralizedHoughBallard> createGeneralizedHoughBallard();
|
||||
|
||||
//! Guil, N., González-Linares, J.M. and Zapata, E.L. (1999). Bidimensional shape detection using an invariant approach. Pattern Recognition 32 (6): 1025-1038.
|
||||
class CV_EXPORTS GeneralizedHough : public Algorithm
|
||||
{
|
||||
public:
|
||||
static Ptr<GeneralizedHough> create(int method);
|
||||
|
||||
//! set template to search
|
||||
virtual void setTemplate(InputArray templ, int cannyThreshold = 100, Point templCenter = Point(-1, -1)) = 0;
|
||||
virtual void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1)) = 0;
|
||||
|
||||
//! find template on image
|
||||
virtual void detect(InputArray image, OutputArray positions, int cannyThreshold = 100) = 0;
|
||||
virtual void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions) = 0;
|
||||
|
||||
virtual void downloadResults(InputArray d_positions, OutputArray h_positions, OutputArray h_votes = noArray()) = 0;
|
||||
};
|
||||
//! Detects position, traslation and rotation
|
||||
CV_EXPORTS Ptr<GeneralizedHoughGuil> createGeneralizedHoughGuil();
|
||||
|
||||
////////////////////////// Corners Detection ///////////////////////////
|
||||
|
||||
|
@ -227,23 +227,59 @@ PERF_TEST_P(Sz_Dp_MinDist, HoughCircles,
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// GeneralizedHough
|
||||
|
||||
enum { GHT_POSITION = cv::GeneralizedHough::GHT_POSITION,
|
||||
GHT_SCALE = cv::GeneralizedHough::GHT_SCALE,
|
||||
GHT_ROTATION = cv::GeneralizedHough::GHT_ROTATION
|
||||
};
|
||||
|
||||
CV_FLAGS(GHMethod, GHT_POSITION, GHT_SCALE, GHT_ROTATION);
|
||||
|
||||
DEF_PARAM_TEST(Method_Sz, GHMethod, cv::Size);
|
||||
|
||||
PERF_TEST_P(Method_Sz, GeneralizedHough,
|
||||
Combine(Values(GHMethod(GHT_POSITION), GHMethod(GHT_POSITION | GHT_SCALE), GHMethod(GHT_POSITION | GHT_ROTATION), GHMethod(GHT_POSITION | GHT_SCALE | GHT_ROTATION)),
|
||||
GPU_TYPICAL_MAT_SIZES))
|
||||
PERF_TEST_P(Sz, GeneralizedHoughBallard, GPU_TYPICAL_MAT_SIZES)
|
||||
{
|
||||
declare.time(10);
|
||||
|
||||
const int method = GET_PARAM(0);
|
||||
const cv::Size imageSize = GET_PARAM(1);
|
||||
const cv::Size imageSize = GetParam();
|
||||
|
||||
const cv::Mat templ = readImage("cv/shared/templ.png", cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(templ.empty());
|
||||
|
||||
cv::Mat image(imageSize, CV_8UC1, cv::Scalar::all(0));
|
||||
templ.copyTo(image(cv::Rect(50, 50, templ.cols, templ.rows)));
|
||||
|
||||
cv::Mat edges;
|
||||
cv::Canny(image, edges, 50, 100);
|
||||
|
||||
cv::Mat dx, dy;
|
||||
cv::Sobel(image, dx, CV_32F, 1, 0);
|
||||
cv::Sobel(image, dy, CV_32F, 0, 1);
|
||||
|
||||
if (PERF_RUN_GPU())
|
||||
{
|
||||
cv::Ptr<cv::GeneralizedHoughBallard> alg = cv::gpu::createGeneralizedHoughBallard();
|
||||
|
||||
const cv::gpu::GpuMat d_edges(edges);
|
||||
const cv::gpu::GpuMat d_dx(dx);
|
||||
const cv::gpu::GpuMat d_dy(dy);
|
||||
cv::gpu::GpuMat positions;
|
||||
|
||||
alg->setTemplate(cv::gpu::GpuMat(templ));
|
||||
|
||||
TEST_CYCLE() alg->detect(d_edges, d_dx, d_dy, positions);
|
||||
|
||||
GPU_SANITY_CHECK(positions);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::Ptr<cv::GeneralizedHoughBallard> alg = cv::createGeneralizedHoughBallard();
|
||||
|
||||
cv::Mat positions;
|
||||
|
||||
alg->setTemplate(templ);
|
||||
|
||||
TEST_CYCLE() alg->detect(edges, dx, dy, positions);
|
||||
|
||||
CPU_SANITY_CHECK(positions);
|
||||
}
|
||||
}
|
||||
|
||||
PERF_TEST_P(Sz, GeneralizedHoughGuil, GPU_TYPICAL_MAT_SIZES)
|
||||
{
|
||||
declare.time(10);
|
||||
|
||||
const cv::Size imageSize = GetParam();
|
||||
|
||||
const cv::Mat templ = readImage("cv/shared/templ.png", cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(templ.empty());
|
||||
@ -281,39 +317,32 @@ PERF_TEST_P(Method_Sz, GeneralizedHough,
|
||||
|
||||
if (PERF_RUN_GPU())
|
||||
{
|
||||
cv::Ptr<cv::GeneralizedHoughGuil> alg = cv::gpu::createGeneralizedHoughGuil();
|
||||
alg->setMaxAngle(90.0);
|
||||
alg->setAngleStep(2.0);
|
||||
|
||||
const cv::gpu::GpuMat d_edges(edges);
|
||||
const cv::gpu::GpuMat d_dx(dx);
|
||||
const cv::gpu::GpuMat d_dy(dy);
|
||||
cv::gpu::GpuMat posAndVotes;
|
||||
cv::gpu::GpuMat positions;
|
||||
|
||||
cv::Ptr<cv::gpu::GeneralizedHough> d_hough = cv::gpu::GeneralizedHough::create(method);
|
||||
if (method & GHT_ROTATION)
|
||||
{
|
||||
d_hough->set("maxAngle", 90.0);
|
||||
d_hough->set("angleStep", 2.0);
|
||||
}
|
||||
alg->setTemplate(cv::gpu::GpuMat(templ));
|
||||
|
||||
d_hough->setTemplate(cv::gpu::GpuMat(templ));
|
||||
TEST_CYCLE() alg->detect(d_edges, d_dx, d_dy, positions);
|
||||
|
||||
TEST_CYCLE() d_hough->detect(d_edges, d_dx, d_dy, posAndVotes);
|
||||
|
||||
const cv::gpu::GpuMat positions(1, posAndVotes.cols, CV_32FC4, posAndVotes.data);
|
||||
GPU_SANITY_CHECK(positions);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::Ptr<cv::GeneralizedHoughGuil> alg = cv::createGeneralizedHoughGuil();
|
||||
alg->setMaxAngle(90.0);
|
||||
alg->setAngleStep(2.0);
|
||||
|
||||
cv::Mat positions;
|
||||
|
||||
cv::Ptr<cv::GeneralizedHough> hough = cv::GeneralizedHough::create(method);
|
||||
if (method & GHT_ROTATION)
|
||||
{
|
||||
hough->set("maxAngle", 90.0);
|
||||
hough->set("angleStep", 2.0);
|
||||
}
|
||||
alg->setTemplate(templ);
|
||||
|
||||
hough->setTemplate(templ);
|
||||
|
||||
TEST_CYCLE() hough->detect(edges, dx, dy, positions);
|
||||
TEST_CYCLE() alg->detect(edges, dx, dy, positions);
|
||||
|
||||
CPU_SANITY_CHECK(positions);
|
||||
}
|
||||
|
@ -307,268 +307,6 @@ namespace cv { namespace gpu { namespace cudev
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Ballard_PosScale
|
||||
|
||||
__global__ void Ballard_PosScale_calcHist(const unsigned int* coordList, const float* thetaList,
|
||||
PtrStep<short2> r_table, const int* r_sizes,
|
||||
PtrStepi hist, const int rows, const int cols,
|
||||
const float minScale, const float scaleStep, const int scaleRange,
|
||||
const float idp, const float thetaScale)
|
||||
{
|
||||
const unsigned int coord = coordList[blockIdx.x];
|
||||
float2 p;
|
||||
p.x = (coord & 0xFFFF);
|
||||
p.y = (coord >> 16) & 0xFFFF;
|
||||
|
||||
const float theta = thetaList[blockIdx.x];
|
||||
const int n = __float2int_rn(theta * thetaScale);
|
||||
|
||||
const short2* r_row = r_table.ptr(n);
|
||||
const int r_row_size = r_sizes[n];
|
||||
|
||||
for (int j = 0; j < r_row_size; ++j)
|
||||
{
|
||||
const float2 d = saturate_cast<float2>(r_row[j]);
|
||||
|
||||
for (int s = threadIdx.x; s < scaleRange; s += blockDim.x)
|
||||
{
|
||||
const float scale = minScale + s * scaleStep;
|
||||
|
||||
float2 c = p - scale * d;
|
||||
|
||||
c.x *= idp;
|
||||
c.y *= idp;
|
||||
|
||||
if (c.x >= 0 && c.x < cols && c.y >= 0 && c.y < rows)
|
||||
::atomicAdd(hist.ptr((s + 1) * (rows + 2) + __float2int_rn(c.y + 1)) + __float2int_rn(c.x + 1), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ballard_PosScale_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
|
||||
PtrStepSz<short2> r_table, const int* r_sizes,
|
||||
PtrStepi hist, int rows, int cols,
|
||||
float minScale, float scaleStep, int scaleRange,
|
||||
float dp, int levels)
|
||||
{
|
||||
const dim3 block(256);
|
||||
const dim3 grid(pointsCount);
|
||||
|
||||
const float idp = 1.0f / dp;
|
||||
const float thetaScale = levels / (2.0f * CV_PI_F);
|
||||
|
||||
Ballard_PosScale_calcHist<<<grid, block>>>(coordList, thetaList,
|
||||
r_table, r_sizes,
|
||||
hist, rows, cols,
|
||||
minScale, scaleStep, scaleRange,
|
||||
idp, thetaScale);
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
cudaSafeCall( cudaDeviceSynchronize() );
|
||||
}
|
||||
|
||||
__global__ void Ballard_PosScale_findPosInHist(const PtrStepi hist, const int rows, const int cols, const int scaleRange,
|
||||
float4* out, int3* votes, const int maxSize,
|
||||
const float minScale, const float scaleStep, const float dp, const int threshold)
|
||||
{
|
||||
const int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
const int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
|
||||
if (x >= cols || y >= rows)
|
||||
return;
|
||||
|
||||
for (int s = 0; s < scaleRange; ++s)
|
||||
{
|
||||
const float scale = minScale + s * scaleStep;
|
||||
|
||||
const int prevScaleIdx = (s) * (rows + 2);
|
||||
const int curScaleIdx = (s + 1) * (rows + 2);
|
||||
const int nextScaleIdx = (s + 2) * (rows + 2);
|
||||
|
||||
const int curVotes = hist(curScaleIdx + y + 1, x + 1);
|
||||
|
||||
if (curVotes > threshold &&
|
||||
curVotes > hist(curScaleIdx + y + 1, x) &&
|
||||
curVotes >= hist(curScaleIdx + y + 1, x + 2) &&
|
||||
curVotes > hist(curScaleIdx + y, x + 1) &&
|
||||
curVotes >= hist(curScaleIdx + y + 2, x + 1) &&
|
||||
curVotes > hist(prevScaleIdx + y + 1, x + 1) &&
|
||||
curVotes >= hist(nextScaleIdx + y + 1, x + 1))
|
||||
{
|
||||
const int ind = ::atomicAdd(&g_counter, 1);
|
||||
|
||||
if (ind < maxSize)
|
||||
{
|
||||
out[ind] = make_float4(x * dp, y * dp, scale, 0.0f);
|
||||
votes[ind] = make_int3(curVotes, curVotes, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Ballard_PosScale_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int scaleRange, float4* out, int3* votes, int maxSize,
|
||||
float minScale, float scaleStep, float dp, int threshold)
|
||||
{
|
||||
void* counterPtr;
|
||||
cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) );
|
||||
|
||||
cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) );
|
||||
|
||||
const dim3 block(32, 8);
|
||||
const dim3 grid(divUp(cols, block.x), divUp(rows, block.y));
|
||||
|
||||
cudaSafeCall( cudaFuncSetCacheConfig(Ballard_PosScale_findPosInHist, cudaFuncCachePreferL1) );
|
||||
|
||||
Ballard_PosScale_findPosInHist<<<grid, block>>>(hist, rows, cols, scaleRange, out, votes,
|
||||
maxSize, minScale, scaleStep, dp, threshold);
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
cudaSafeCall( cudaDeviceSynchronize() );
|
||||
|
||||
int totalCount;
|
||||
cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) );
|
||||
|
||||
totalCount = ::min(totalCount, maxSize);
|
||||
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Ballard_PosRotation
|
||||
|
||||
__global__ void Ballard_PosRotation_calcHist(const unsigned int* coordList, const float* thetaList,
|
||||
PtrStep<short2> r_table, const int* r_sizes,
|
||||
PtrStepi hist, const int rows, const int cols,
|
||||
const float minAngle, const float angleStep, const int angleRange,
|
||||
const float idp, const float thetaScale)
|
||||
{
|
||||
const unsigned int coord = coordList[blockIdx.x];
|
||||
float2 p;
|
||||
p.x = (coord & 0xFFFF);
|
||||
p.y = (coord >> 16) & 0xFFFF;
|
||||
|
||||
const float thetaVal = thetaList[blockIdx.x];
|
||||
|
||||
for (int a = threadIdx.x; a < angleRange; a += blockDim.x)
|
||||
{
|
||||
const float angle = (minAngle + a * angleStep) * (CV_PI_F / 180.0f);
|
||||
float sinA, cosA;
|
||||
sincosf(angle, &sinA, &cosA);
|
||||
|
||||
float theta = thetaVal - angle;
|
||||
if (theta < 0)
|
||||
theta += 2.0f * CV_PI_F;
|
||||
|
||||
const int n = __float2int_rn(theta * thetaScale);
|
||||
|
||||
const short2* r_row = r_table.ptr(n);
|
||||
const int r_row_size = r_sizes[n];
|
||||
|
||||
for (int j = 0; j < r_row_size; ++j)
|
||||
{
|
||||
const float2 d = saturate_cast<float2>(r_row[j]);
|
||||
|
||||
const float2 dr = make_float2(d.x * cosA - d.y * sinA, d.x * sinA + d.y * cosA);
|
||||
|
||||
float2 c = make_float2(p.x - dr.x, p.y - dr.y);
|
||||
c.x *= idp;
|
||||
c.y *= idp;
|
||||
|
||||
if (c.x >= 0 && c.x < cols && c.y >= 0 && c.y < rows)
|
||||
::atomicAdd(hist.ptr((a + 1) * (rows + 2) + __float2int_rn(c.y + 1)) + __float2int_rn(c.x + 1), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ballard_PosRotation_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
|
||||
PtrStepSz<short2> r_table, const int* r_sizes,
|
||||
PtrStepi hist, int rows, int cols,
|
||||
float minAngle, float angleStep, int angleRange,
|
||||
float dp, int levels)
|
||||
{
|
||||
const dim3 block(256);
|
||||
const dim3 grid(pointsCount);
|
||||
|
||||
const float idp = 1.0f / dp;
|
||||
const float thetaScale = levels / (2.0f * CV_PI_F);
|
||||
|
||||
Ballard_PosRotation_calcHist<<<grid, block>>>(coordList, thetaList,
|
||||
r_table, r_sizes,
|
||||
hist, rows, cols,
|
||||
minAngle, angleStep, angleRange,
|
||||
idp, thetaScale);
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
cudaSafeCall( cudaDeviceSynchronize() );
|
||||
}
|
||||
|
||||
__global__ void Ballard_PosRotation_findPosInHist(const PtrStepi hist, const int rows, const int cols, const int angleRange,
|
||||
float4* out, int3* votes, const int maxSize,
|
||||
const float minAngle, const float angleStep, const float dp, const int threshold)
|
||||
{
|
||||
const int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
const int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
|
||||
if (x >= cols || y >= rows)
|
||||
return;
|
||||
|
||||
for (int a = 0; a < angleRange; ++a)
|
||||
{
|
||||
const float angle = minAngle + a * angleStep;
|
||||
|
||||
const int prevAngleIdx = (a) * (rows + 2);
|
||||
const int curAngleIdx = (a + 1) * (rows + 2);
|
||||
const int nextAngleIdx = (a + 2) * (rows + 2);
|
||||
|
||||
const int curVotes = hist(curAngleIdx + y + 1, x + 1);
|
||||
|
||||
if (curVotes > threshold &&
|
||||
curVotes > hist(curAngleIdx + y + 1, x) &&
|
||||
curVotes >= hist(curAngleIdx + y + 1, x + 2) &&
|
||||
curVotes > hist(curAngleIdx + y, x + 1) &&
|
||||
curVotes >= hist(curAngleIdx + y + 2, x + 1) &&
|
||||
curVotes > hist(prevAngleIdx + y + 1, x + 1) &&
|
||||
curVotes >= hist(nextAngleIdx + y + 1, x + 1))
|
||||
{
|
||||
const int ind = ::atomicAdd(&g_counter, 1);
|
||||
|
||||
if (ind < maxSize)
|
||||
{
|
||||
out[ind] = make_float4(x * dp, y * dp, 1.0f, angle);
|
||||
votes[ind] = make_int3(curVotes, 0, curVotes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Ballard_PosRotation_findPosInHist_gpu(PtrStepi hist, int rows, int cols, int angleRange, float4* out, int3* votes, int maxSize,
|
||||
float minAngle, float angleStep, float dp, int threshold)
|
||||
{
|
||||
void* counterPtr;
|
||||
cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) );
|
||||
|
||||
cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) );
|
||||
|
||||
const dim3 block(32, 8);
|
||||
const dim3 grid(divUp(cols, block.x), divUp(rows, block.y));
|
||||
|
||||
cudaSafeCall( cudaFuncSetCacheConfig(Ballard_PosRotation_findPosInHist, cudaFuncCachePreferL1) );
|
||||
|
||||
Ballard_PosRotation_findPosInHist<<<grid, block>>>(hist, rows, cols, angleRange, out, votes,
|
||||
maxSize, minAngle, angleStep, dp, threshold);
|
||||
cudaSafeCall( cudaGetLastError() );
|
||||
|
||||
cudaSafeCall( cudaDeviceSynchronize() );
|
||||
|
||||
int totalCount;
|
||||
cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) );
|
||||
|
||||
totalCount = ::min(totalCount, maxSize);
|
||||
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Guil_Full
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -193,7 +193,7 @@ PARAM_TEST_CASE(GeneralizedHough, cv::gpu::DeviceInfo, UseRoi)
|
||||
{
|
||||
};
|
||||
|
||||
GPU_TEST_P(GeneralizedHough, POSITION)
|
||||
GPU_TEST_P(GeneralizedHough, Ballard)
|
||||
{
|
||||
const cv::gpu::DeviceInfo devInfo = GET_PARAM(0);
|
||||
cv::gpu::setDevice(devInfo.deviceID());
|
||||
@ -218,16 +218,16 @@ GPU_TEST_P(GeneralizedHough, POSITION)
|
||||
templ.copyTo(imageROI);
|
||||
}
|
||||
|
||||
cv::Ptr<cv::gpu::GeneralizedHough> hough = cv::gpu::GeneralizedHough::create(cv::GeneralizedHough::GHT_POSITION);
|
||||
hough->set("votesThreshold", 200);
|
||||
cv::Ptr<cv::GeneralizedHoughBallard> alg = cv::gpu::createGeneralizedHoughBallard();
|
||||
alg->setVotesThreshold(200);
|
||||
|
||||
hough->setTemplate(loadMat(templ, useRoi));
|
||||
alg->setTemplate(loadMat(templ, useRoi));
|
||||
|
||||
cv::gpu::GpuMat d_pos;
|
||||
hough->detect(loadMat(image, useRoi), d_pos);
|
||||
alg->detect(loadMat(image, useRoi), d_pos);
|
||||
|
||||
std::vector<cv::Vec4f> pos;
|
||||
hough->downloadResults(d_pos, pos);
|
||||
d_pos.download(pos);
|
||||
|
||||
ASSERT_EQ(gold_count, pos.size());
|
||||
|
||||
|
@ -688,39 +688,104 @@ public:
|
||||
|
||||
|
||||
//! finds arbitrary template in the grayscale image using Generalized Hough Transform
|
||||
//! Ballard, D.H. (1981). Generalizing the Hough transform to detect arbitrary shapes. Pattern Recognition 13 (2): 111-122.
|
||||
//! Guil, N., González-Linares, J.M. and Zapata, E.L. (1999). Bidimensional shape detection using an invariant approach. Pattern Recognition 32 (6): 1025-1038.
|
||||
class CV_EXPORTS GeneralizedHough : public Algorithm
|
||||
{
|
||||
public:
|
||||
enum { GHT_POSITION = 0,
|
||||
GHT_SCALE = 1,
|
||||
GHT_ROTATION = 2
|
||||
};
|
||||
|
||||
static Ptr<GeneralizedHough> create(int method);
|
||||
|
||||
virtual ~GeneralizedHough();
|
||||
|
||||
//! set template to search
|
||||
void setTemplate(InputArray templ, int cannyThreshold = 100, Point templCenter = Point(-1, -1));
|
||||
void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1));
|
||||
virtual void setTemplate(InputArray templ, Point templCenter = Point(-1, -1)) = 0;
|
||||
virtual void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter = Point(-1, -1)) = 0;
|
||||
|
||||
//! find template on image
|
||||
void detect(InputArray image, OutputArray positions, OutputArray votes = cv::noArray(), int cannyThreshold = 100);
|
||||
void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes = cv::noArray());
|
||||
virtual void detect(InputArray image, OutputArray positions, OutputArray votes = noArray()) = 0;
|
||||
virtual void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes = noArray()) = 0;
|
||||
|
||||
void release();
|
||||
//! Canny low threshold.
|
||||
virtual void setCannyLowThresh(int cannyLowThresh) = 0;
|
||||
virtual int getCannyLowThresh() const = 0;
|
||||
|
||||
protected:
|
||||
virtual void setTemplateImpl(const Mat& edges, const Mat& dx, const Mat& dy, Point templCenter) = 0;
|
||||
virtual void detectImpl(const Mat& edges, const Mat& dx, const Mat& dy, OutputArray positions, OutputArray votes) = 0;
|
||||
virtual void releaseImpl() = 0;
|
||||
//! Canny high threshold.
|
||||
virtual void setCannyHighThresh(int cannyHighThresh) = 0;
|
||||
virtual int getCannyHighThresh() const = 0;
|
||||
|
||||
private:
|
||||
Mat edges_;
|
||||
Mat dx_;
|
||||
Mat dy_;
|
||||
//! Minimum distance between the centers of the detected objects.
|
||||
virtual void setMinDist(double minDist) = 0;
|
||||
virtual double getMinDist() const = 0;
|
||||
|
||||
//! Inverse ratio of the accumulator resolution to the image resolution.
|
||||
virtual void setDp(double dp) = 0;
|
||||
virtual double getDp() const = 0;
|
||||
|
||||
//! Maximal size of inner buffers.
|
||||
virtual void setMaxBufferSize(int maxBufferSize) = 0;
|
||||
virtual int getMaxBufferSize() const = 0;
|
||||
};
|
||||
|
||||
//! Ballard, D.H. (1981). Generalizing the Hough transform to detect arbitrary shapes. Pattern Recognition 13 (2): 111-122.
|
||||
//! Detects position only without traslation and rotation
|
||||
class CV_EXPORTS GeneralizedHoughBallard : public GeneralizedHough
|
||||
{
|
||||
public:
|
||||
//! R-Table levels.
|
||||
virtual void setLevels(int levels) = 0;
|
||||
virtual int getLevels() const = 0;
|
||||
|
||||
//! The accumulator threshold for the template centers at the detection stage. The smaller it is, the more false positions may be detected.
|
||||
virtual void setVotesThreshold(int votesThreshold) = 0;
|
||||
virtual int getVotesThreshold() const = 0;
|
||||
};
|
||||
|
||||
//! Guil, N., González-Linares, J.M. and Zapata, E.L. (1999). Bidimensional shape detection using an invariant approach. Pattern Recognition 32 (6): 1025-1038.
|
||||
//! Detects position, traslation and rotation
|
||||
class CV_EXPORTS GeneralizedHoughGuil : public GeneralizedHough
|
||||
{
|
||||
public:
|
||||
//! Angle difference in degrees between two points in feature.
|
||||
virtual void setXi(double xi) = 0;
|
||||
virtual double getXi() const = 0;
|
||||
|
||||
//! Feature table levels.
|
||||
virtual void setLevels(int levels) = 0;
|
||||
virtual int getLevels() const = 0;
|
||||
|
||||
//! Maximal difference between angles that treated as equal.
|
||||
virtual void setAngleEpsilon(double angleEpsilon) = 0;
|
||||
virtual double getAngleEpsilon() const = 0;
|
||||
|
||||
//! Minimal rotation angle to detect in degrees.
|
||||
virtual void setMinAngle(double minAngle) = 0;
|
||||
virtual double getMinAngle() const = 0;
|
||||
|
||||
//! Maximal rotation angle to detect in degrees.
|
||||
virtual void setMaxAngle(double maxAngle) = 0;
|
||||
virtual double getMaxAngle() const = 0;
|
||||
|
||||
//! Angle step in degrees.
|
||||
virtual void setAngleStep(double angleStep) = 0;
|
||||
virtual double getAngleStep() const = 0;
|
||||
|
||||
//! Angle votes threshold.
|
||||
virtual void setAngleThresh(int angleThresh) = 0;
|
||||
virtual int getAngleThresh() const = 0;
|
||||
|
||||
//! Minimal scale to detect.
|
||||
virtual void setMinScale(double minScale) = 0;
|
||||
virtual double getMinScale() const = 0;
|
||||
|
||||
//! Maximal scale to detect.
|
||||
virtual void setMaxScale(double maxScale) = 0;
|
||||
virtual double getMaxScale() const = 0;
|
||||
|
||||
//! Scale step.
|
||||
virtual void setScaleStep(double scaleStep) = 0;
|
||||
virtual double getScaleStep() const = 0;
|
||||
|
||||
//! Scale votes threshold.
|
||||
virtual void setScaleThresh(int scaleThresh) = 0;
|
||||
virtual int getScaleThresh() const = 0;
|
||||
|
||||
//! Position votes threshold.
|
||||
virtual void setPosThresh(int posThresh) = 0;
|
||||
virtual int getPosThresh() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -1355,6 +1420,14 @@ CV_EXPORTS_W double pointPolygonTest( InputArray contour, Point2f pt, bool measu
|
||||
|
||||
CV_EXPORTS Ptr<CLAHE> createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8));
|
||||
|
||||
//! Ballard, D.H. (1981). Generalizing the Hough transform to detect arbitrary shapes. Pattern Recognition 13 (2): 111-122.
|
||||
//! Detects position only without traslation and rotation
|
||||
CV_EXPORTS Ptr<GeneralizedHoughBallard> createGeneralizedHoughBallard();
|
||||
|
||||
//! Guil, N., González-Linares, J.M. and Zapata, E.L. (1999). Bidimensional shape detection using an invariant approach. Pattern Recognition 32 (6): 1025-1038.
|
||||
//! Detects position, traslation and rotation
|
||||
CV_EXPORTS Ptr<GeneralizedHoughGuil> createGeneralizedHoughGuil();
|
||||
|
||||
} // cv
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,13 +5,12 @@
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/gpu.hpp"
|
||||
#include "opencv2/gpuimgproc.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/contrib.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using cv::gpu::GpuMat;
|
||||
|
||||
static Mat loadImage(const string& name)
|
||||
{
|
||||
@ -29,8 +28,7 @@ int main(int argc, const char* argv[])
|
||||
CommandLineParser cmd(argc, argv,
|
||||
"{ image i | pic1.png | input image }"
|
||||
"{ template t | templ.png | template image }"
|
||||
"{ scale s | | estimate scale }"
|
||||
"{ rotation r | | estimate rotation }"
|
||||
"{ full | | estimate scale and rotation }"
|
||||
"{ gpu | | use gpu version }"
|
||||
"{ minDist | 100 | minimum distance between the centers of the detected objects }"
|
||||
"{ levels | 360 | R-Table levels }"
|
||||
@ -45,7 +43,7 @@ int main(int argc, const char* argv[])
|
||||
"{ minAngle | 0 | minimal rotation angle to detect in degrees }"
|
||||
"{ maxAngle | 360 | maximal rotation angle to detect in degrees }"
|
||||
"{ angleStep | 1 | angle step in degrees }"
|
||||
"{ maxSize | 1000 | maximal size of inner buffers }"
|
||||
"{ maxBufSize | 1000 | maximal size of inner buffers }"
|
||||
"{ help h ? | | print help message }"
|
||||
);
|
||||
|
||||
@ -59,8 +57,7 @@ int main(int argc, const char* argv[])
|
||||
|
||||
const string templName = cmd.get<string>("template");
|
||||
const string imageName = cmd.get<string>("image");
|
||||
const bool estimateScale = cmd.has("scale");
|
||||
const bool estimateRotation = cmd.has("rotation");
|
||||
const bool full = cmd.has("full");
|
||||
const bool useGpu = cmd.has("gpu");
|
||||
const double minDist = cmd.get<double>("minDist");
|
||||
const int levels = cmd.get<int>("levels");
|
||||
@ -75,7 +72,7 @@ int main(int argc, const char* argv[])
|
||||
const double minAngle = cmd.get<double>("minAngle");
|
||||
const double maxAngle = cmd.get<double>("maxAngle");
|
||||
const double angleStep = cmd.get<double>("angleStep");
|
||||
const int maxSize = cmd.get<int>("maxSize");
|
||||
const int maxBufSize = cmd.get<int>("maxBufSize");
|
||||
|
||||
if (!cmd.check())
|
||||
{
|
||||
@ -86,93 +83,69 @@ int main(int argc, const char* argv[])
|
||||
Mat templ = loadImage(templName);
|
||||
Mat image = loadImage(imageName);
|
||||
|
||||
int method = cv::GeneralizedHough::GHT_POSITION;
|
||||
if (estimateScale)
|
||||
method += cv::GeneralizedHough::GHT_SCALE;
|
||||
if (estimateRotation)
|
||||
method += cv::GeneralizedHough::GHT_ROTATION;
|
||||
Ptr<GeneralizedHough> alg;
|
||||
|
||||
if (!full)
|
||||
{
|
||||
Ptr<GeneralizedHoughBallard> ballard = useGpu ? gpu::createGeneralizedHoughBallard() : createGeneralizedHoughBallard();
|
||||
|
||||
ballard->setMinDist(minDist);
|
||||
ballard->setLevels(levels);
|
||||
ballard->setDp(dp);
|
||||
ballard->setMaxBufferSize(maxBufSize);
|
||||
ballard->setVotesThreshold(votesThreshold);
|
||||
|
||||
alg = ballard;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ptr<GeneralizedHoughGuil> guil = useGpu ? gpu::createGeneralizedHoughGuil() : createGeneralizedHoughGuil();
|
||||
|
||||
guil->setMinDist(minDist);
|
||||
guil->setLevels(levels);
|
||||
guil->setDp(dp);
|
||||
guil->setMaxBufferSize(maxBufSize);
|
||||
|
||||
guil->setMinAngle(minAngle);
|
||||
guil->setMaxAngle(maxAngle);
|
||||
guil->setAngleStep(angleStep);
|
||||
guil->setAngleThresh(angleThresh);
|
||||
|
||||
guil->setMinScale(minScale);
|
||||
guil->setMaxScale(maxScale);
|
||||
guil->setScaleStep(scaleStep);
|
||||
guil->setScaleThresh(scaleThresh);
|
||||
|
||||
guil->setPosThresh(posThresh);
|
||||
|
||||
alg = guil;
|
||||
}
|
||||
|
||||
vector<Vec4f> position;
|
||||
cv::TickMeter tm;
|
||||
TickMeter tm;
|
||||
|
||||
if (useGpu)
|
||||
{
|
||||
GpuMat d_templ(templ);
|
||||
GpuMat d_image(image);
|
||||
GpuMat d_position;
|
||||
gpu::GpuMat d_templ(templ);
|
||||
gpu::GpuMat d_image(image);
|
||||
gpu::GpuMat d_position;
|
||||
|
||||
Ptr<gpu::GeneralizedHough> d_hough = gpu::GeneralizedHough::create(method);
|
||||
d_hough->set("minDist", minDist);
|
||||
d_hough->set("levels", levels);
|
||||
d_hough->set("dp", dp);
|
||||
d_hough->set("maxSize", maxSize);
|
||||
if (estimateScale && estimateRotation)
|
||||
{
|
||||
d_hough->set("angleThresh", angleThresh);
|
||||
d_hough->set("scaleThresh", scaleThresh);
|
||||
d_hough->set("posThresh", posThresh);
|
||||
}
|
||||
else
|
||||
{
|
||||
d_hough->set("votesThreshold", votesThreshold);
|
||||
}
|
||||
if (estimateScale)
|
||||
{
|
||||
d_hough->set("minScale", minScale);
|
||||
d_hough->set("maxScale", maxScale);
|
||||
d_hough->set("scaleStep", scaleStep);
|
||||
}
|
||||
if (estimateRotation)
|
||||
{
|
||||
d_hough->set("minAngle", minAngle);
|
||||
d_hough->set("maxAngle", maxAngle);
|
||||
d_hough->set("angleStep", angleStep);
|
||||
}
|
||||
|
||||
d_hough->setTemplate(d_templ);
|
||||
alg->setTemplate(d_templ);
|
||||
|
||||
tm.start();
|
||||
|
||||
d_hough->detect(d_image, d_position);
|
||||
d_hough->downloadResults(d_position, position);
|
||||
alg->detect(d_image, d_position);
|
||||
d_position.download(position);
|
||||
|
||||
tm.stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
Ptr<GeneralizedHough> hough = GeneralizedHough::create(method);
|
||||
hough->set("minDist", minDist);
|
||||
hough->set("levels", levels);
|
||||
hough->set("dp", dp);
|
||||
if (estimateScale && estimateRotation)
|
||||
{
|
||||
hough->set("angleThresh", angleThresh);
|
||||
hough->set("scaleThresh", scaleThresh);
|
||||
hough->set("posThresh", posThresh);
|
||||
hough->set("maxSize", maxSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
hough->set("votesThreshold", votesThreshold);
|
||||
}
|
||||
if (estimateScale)
|
||||
{
|
||||
hough->set("minScale", minScale);
|
||||
hough->set("maxScale", maxScale);
|
||||
hough->set("scaleStep", scaleStep);
|
||||
}
|
||||
if (estimateRotation)
|
||||
{
|
||||
hough->set("minAngle", minAngle);
|
||||
hough->set("maxAngle", maxAngle);
|
||||
hough->set("angleStep", angleStep);
|
||||
}
|
||||
|
||||
hough->setTemplate(templ);
|
||||
alg->setTemplate(templ);
|
||||
|
||||
tm.start();
|
||||
|
||||
hough->detect(image, position);
|
||||
alg->detect(image, position);
|
||||
|
||||
tm.stop();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user