mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Support non continuous, BORDER_REPLICATE
TODO: HAL-accelerated code
This commit is contained in:
parent
2ff614dfab
commit
6803d1ed28
@ -1382,12 +1382,14 @@ Sobel( src, dy, CV_16SC1, 0, 1, 3 );
|
|||||||
@param dx output image with first-order derivative in x.
|
@param dx output image with first-order derivative in x.
|
||||||
@param dy output image with first-order derivative in y.
|
@param dy output image with first-order derivative in y.
|
||||||
@param ksize size of Sobel kernel. It must be 3.
|
@param ksize size of Sobel kernel. It must be 3.
|
||||||
|
@param borderType pixel extrapolation method, see cv::BorderTypes
|
||||||
|
|
||||||
@sa Sobel
|
@sa Sobel
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CV_EXPORTS_W void spatialGradient( InputArray src, OutputArray dx,
|
CV_EXPORTS_W void spatialGradient( InputArray src, OutputArray dx,
|
||||||
OutputArray dy, int ksize = 3 );
|
OutputArray dy, int ksize = 3,
|
||||||
|
int borderType = BORDER_DEFAULT );
|
||||||
|
|
||||||
/** @brief Calculates the first x- or y- image derivative using Scharr operator.
|
/** @brief Calculates the first x- or y- image derivative using Scharr operator.
|
||||||
|
|
||||||
|
@ -7,18 +7,20 @@ using namespace testing;
|
|||||||
using std::tr1::make_tuple;
|
using std::tr1::make_tuple;
|
||||||
using std::tr1::get;
|
using std::tr1::get;
|
||||||
|
|
||||||
typedef std::tr1::tuple<Size, int> Size_Ksize_t;
|
typedef std::tr1::tuple<Size, int, int> Size_Ksize_BorderType_t;
|
||||||
typedef perf::TestBaseWithParam<Size_Ksize_t> Size_Ksize;
|
typedef perf::TestBaseWithParam<Size_Ksize_BorderType_t> Size_Ksize_BorderType;
|
||||||
|
|
||||||
PERF_TEST_P( Size_Ksize, spatialGradient,
|
PERF_TEST_P( Size_Ksize_BorderType, spatialGradient,
|
||||||
Combine(
|
Combine(
|
||||||
SZ_ALL_HD,
|
SZ_ALL_HD,
|
||||||
Values( 3 )
|
Values( 3 ),
|
||||||
|
Values( BORDER_DEFAULT )
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Size size = std::tr1::get<0>(GetParam());
|
Size size = std::tr1::get<0>(GetParam());
|
||||||
int ksize = std::tr1::get<1>(GetParam());
|
int ksize = std::tr1::get<1>(GetParam());
|
||||||
|
int borderType = std::tr1::get<2>(GetParam());
|
||||||
|
|
||||||
Mat src(size, CV_8UC1);
|
Mat src(size, CV_8UC1);
|
||||||
Mat dx(size, CV_16SC1);
|
Mat dx(size, CV_16SC1);
|
||||||
@ -26,7 +28,7 @@ PERF_TEST_P( Size_Ksize, spatialGradient,
|
|||||||
|
|
||||||
declare.in(src, WARMUP_RNG).out(dx, dy);
|
declare.in(src, WARMUP_RNG).out(dx, dy);
|
||||||
|
|
||||||
TEST_CYCLE() spatialGradient(src, dx, dy, ksize);
|
TEST_CYCLE() spatialGradient(src, dx, dy, ksize, borderType);
|
||||||
|
|
||||||
SANITY_CHECK(dx);
|
SANITY_CHECK(dx);
|
||||||
SANITY_CHECK(dy);
|
SANITY_CHECK(dy);
|
||||||
|
@ -46,128 +46,73 @@
|
|||||||
namespace cv
|
namespace cv
|
||||||
{
|
{
|
||||||
|
|
||||||
void spatialGradient( InputArray _src, OutputArray _dx, OutputArray _dy, int ksize )
|
void spatialGradient( InputArray _src, OutputArray _dx, OutputArray _dy,
|
||||||
|
int ksize, int borderType )
|
||||||
{
|
{
|
||||||
|
|
||||||
// Prepare InputArray src
|
// Prepare InputArray src
|
||||||
Mat src = _src.getMat();
|
Mat src = _src.getMat();
|
||||||
CV_Assert( !src.empty() );
|
CV_Assert( !src.empty() );
|
||||||
CV_Assert( src.isContinuous() );
|
|
||||||
CV_Assert( src.type() == CV_8UC1 );
|
CV_Assert( src.type() == CV_8UC1 );
|
||||||
|
CV_Assert( borderType == BORDER_DEFAULT || borderType == BORDER_REPLICATE );
|
||||||
|
|
||||||
// Prepare OutputArrays dx, dy
|
// Prepare OutputArrays dx, dy
|
||||||
_dx.create( src.size(), CV_16SC1 );
|
_dx.create( src.size(), CV_16SC1 );
|
||||||
_dy.create( src.size(), CV_16SC1 );
|
_dy.create( src.size(), CV_16SC1 );
|
||||||
Mat dx = _dx.getMat(),
|
Mat dx = _dx.getMat(),
|
||||||
dy = _dy.getMat();
|
dy = _dy.getMat();
|
||||||
CV_Assert( dx.isContinuous() );
|
|
||||||
CV_Assert( dy.isContinuous() );
|
|
||||||
|
|
||||||
// TODO: Allow for other kernel sizes
|
// TODO: Allow for other kernel sizes
|
||||||
CV_Assert(ksize == 3);
|
CV_Assert(ksize == 3);
|
||||||
|
|
||||||
// Reference
|
|
||||||
//Sobel( src, dx, CV_16SC1, 1, 0, ksize );
|
|
||||||
//Sobel( src, dy, CV_16SC1, 0, 1, ksize );
|
|
||||||
|
|
||||||
// Get dimensions
|
// Get dimensions
|
||||||
int H = src.rows,
|
const int H = src.rows,
|
||||||
W = src.cols,
|
W = src.cols;
|
||||||
N = H * W;
|
|
||||||
|
|
||||||
// Get raw pointers to input/output data
|
|
||||||
uchar* p_src = src.ptr<uchar>(0);
|
|
||||||
short* p_dx = dx.ptr<short>(0);
|
|
||||||
short* p_dy = dy.ptr<short>(0);
|
|
||||||
|
|
||||||
// Row, column indices
|
// Row, column indices
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
/* NOTE:
|
// Store pointers to rows of input/output data
|
||||||
*
|
// Padded by two rows for border handling
|
||||||
* Sobel-x: -1 0 1
|
uchar* P_src[H+2];
|
||||||
* -2 0 2
|
short* P_dx [H+2];
|
||||||
* -1 0 1
|
short* P_dy [H+2];
|
||||||
*
|
|
||||||
* Sobel-y: -1 -2 -1
|
|
||||||
* 0 0 0
|
|
||||||
* 1 2 1
|
|
||||||
*/
|
|
||||||
|
|
||||||
// No-SSE
|
int i_top = 0, // Case for H == 1 && W == 1 && BORDER_REPLICATE
|
||||||
int idx;
|
i_bottom = H - 1,
|
||||||
|
j_offl = 0, // j offset from 0th pixel to reach -1st pixel
|
||||||
|
j_offr = 0; // j offset from W-1th pixel to reach Wth pixel
|
||||||
|
|
||||||
p_dx[0] = 0; // Top-left corner
|
if ( borderType == BORDER_DEFAULT ) // Equiv. to BORDER_REFLECT_101
|
||||||
p_dy[0] = 0;
|
|
||||||
p_dx[W-1] = 0; // Top-right corner
|
|
||||||
p_dy[W-1] = 0;
|
|
||||||
p_dx[N-1] = 0; // Bottom-right corner
|
|
||||||
p_dy[N-1] = 0;
|
|
||||||
p_dx[N-W] = 0; // Bottom-left corner
|
|
||||||
p_dy[N-W] = 0;
|
|
||||||
|
|
||||||
// Handle special case: column matrix
|
|
||||||
if ( W == 1 )
|
|
||||||
{
|
{
|
||||||
for ( i = 1; i < H - 1; i++ )
|
if ( H > 1 )
|
||||||
{
|
{
|
||||||
p_dx[i] = 0;
|
i_top = 1;
|
||||||
p_dy[i] = 4*(p_src[i + 1] - p_src[i - 1]); // Should be 2?! 4 makes tests pass
|
i_bottom = H - 2;
|
||||||
}
|
}
|
||||||
return;
|
if ( W > 1 )
|
||||||
}
|
|
||||||
|
|
||||||
// Handle special case: row matrix
|
|
||||||
if ( H == 1 )
|
|
||||||
{
|
|
||||||
for ( j = 1; j < W - 1; j++ )
|
|
||||||
{
|
{
|
||||||
p_dx[j] = 4*(p_src[j + 1] - p_src[j - 1]); // Should be 2?! 4 makes tests pass
|
j_offl = 1;
|
||||||
p_dy[j] = 0;
|
j_offr = -1;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do top row
|
P_src[0] = src.ptr<uchar>(i_top); // Mirrored top border
|
||||||
for ( j = 1; j < W - 1; j++ )
|
P_src[H+1] = src.ptr<uchar>(i_bottom); // Mirrored bottom border
|
||||||
|
|
||||||
|
for ( i = 0; i < H; i++ )
|
||||||
{
|
{
|
||||||
idx = j;
|
P_src[i+1] = src.ptr<uchar>(i);
|
||||||
p_dx[idx] = -(p_src[idx+W-1] + 2*p_src[idx-1] + p_src[idx+W-1]) +
|
P_dx [i] = dx.ptr<short>(i);
|
||||||
(p_src[idx+W+1] + 2*p_src[idx+1] + p_src[idx+W+1]);
|
P_dy [i] = dy.ptr<short>(i);
|
||||||
p_dy[idx] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do right column
|
// Pointer to row vectors
|
||||||
idx = 2*W - 1;
|
uchar *p_src, *c_src, *n_src; // previous, current, next row
|
||||||
for ( i = 1; i < H - 1; i++ )
|
short *c_dx, *c_dy;
|
||||||
{
|
|
||||||
p_dx[idx] = 0;
|
|
||||||
p_dy[idx] = -(p_src[idx-W-1] + 2*p_src[idx-W] + p_src[idx-W-1]) +
|
|
||||||
(p_src[idx+W-1] + 2*p_src[idx+W] + p_src[idx+W-1]);
|
|
||||||
idx += W;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do bottom row
|
int j_start = 0;
|
||||||
idx = N - W + 1;
|
/*
|
||||||
for ( j = 1; j < W - 1; j++ )
|
|
||||||
{
|
|
||||||
p_dx[idx] = -(p_src[idx-W-1] + 2*p_src[idx-1] + p_src[idx-W-1]) +
|
|
||||||
(p_src[idx-W+1] + 2*p_src[idx+1] + p_src[idx-W+1]);
|
|
||||||
p_dy[idx] = 0;
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do left column
|
|
||||||
idx = W;
|
|
||||||
for ( i = 1; i < H - 1; i++ )
|
|
||||||
{
|
|
||||||
p_dx[idx] = 0;
|
|
||||||
p_dy[idx] = -(p_src[idx-W+1] + 2*p_src[idx-W] + p_src[idx-W+1]) +
|
|
||||||
(p_src[idx+W+1] + 2*p_src[idx+W] + p_src[idx+W+1]);
|
|
||||||
idx += W;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do Inner area
|
|
||||||
#if CV_SIMD128
|
#if CV_SIMD128
|
||||||
// Characters in variable names have the following meanings:
|
// Characters in variable names have the following meanings:
|
||||||
// u: unsigned char
|
// u: unsigned char
|
||||||
@ -260,16 +205,39 @@ void spatialGradient( InputArray _src, OutputArray _dx, OutputArray _dy, int ksi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
for ( i = 1; i < H - 1; i++ )
|
*/
|
||||||
for ( j = 1; j < W - 1; j++ )
|
|
||||||
|
/* NOTE:
|
||||||
|
*
|
||||||
|
* Sobel-x: -1 0 1
|
||||||
|
* -2 0 2
|
||||||
|
* -1 0 1
|
||||||
|
*
|
||||||
|
* Sobel-y: -1 -2 -1
|
||||||
|
* 0 0 0
|
||||||
|
* 1 2 1
|
||||||
|
*/
|
||||||
|
int j_p, j_n;
|
||||||
|
for ( i = 0; i < H; i++ )
|
||||||
{
|
{
|
||||||
idx = i*W + j;
|
p_src = P_src[i]; c_src = P_src[i+1]; n_src = P_src[i+2];
|
||||||
p_dx[idx] = -(p_src[idx-W-1] + 2*p_src[idx-1] + p_src[idx+W-1]) +
|
c_dx = P_dx [i];
|
||||||
(p_src[idx-W+1] + 2*p_src[idx+1] + p_src[idx+W+1]);
|
c_dy = P_dy [i];
|
||||||
p_dy[idx] = -(p_src[idx-W-1] + 2*p_src[idx-W] + p_src[idx-W+1]) +
|
|
||||||
(p_src[idx+W-1] + 2*p_src[idx+W] + p_src[idx+W+1]);
|
for ( j = j_start; j < W; j++ )
|
||||||
|
{
|
||||||
|
j_p = j - 1;
|
||||||
|
j_n = j + 1;
|
||||||
|
if ( j_p < 0 ) j_p = j + j_offl;
|
||||||
|
if ( j_n >= W ) j_n = j + j_offr;
|
||||||
|
|
||||||
|
c_dx[j] = -(p_src[j_p] + c_src[j_p] + c_src[j_p] + n_src[j_p]) +
|
||||||
|
(p_src[j_n] + c_src[j_n] + c_src[j_n] + n_src[j_n]);
|
||||||
|
c_dy[j] = -(p_src[j_p] + p_src[j] + p_src[j] + p_src[j_n]) +
|
||||||
|
(n_src[j_p] + n_src[j] + n_src[j] + n_src[j_n]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
//#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,19 +587,17 @@ void CV_SpatialGradientTest::get_test_array_types_and_sizes( int test_case_idx,
|
|||||||
|
|
||||||
// Outputs are only CV_16SC1 for now
|
// Outputs are only CV_16SC1 for now
|
||||||
types[OUTPUT][0] = types[OUTPUT][1] = types[REF_OUTPUT][0]
|
types[OUTPUT][0] = types[OUTPUT][1] = types[REF_OUTPUT][0]
|
||||||
= types[REF_OUTPUT][1] = CV_16SC1;
|
= types[REF_OUTPUT][1] = CV_16SC1;
|
||||||
|
|
||||||
ksize = 3;
|
ksize = 3;
|
||||||
|
border = BORDER_DEFAULT; // TODO: Add BORDER_REPLICATE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CV_SpatialGradientTest::run_func()
|
void CV_SpatialGradientTest::run_func()
|
||||||
{
|
{
|
||||||
Mat dx, dy;
|
spatialGradient( test_mat[INPUT][0], test_mat[OUTPUT][0],
|
||||||
spatialGradient( test_mat[INPUT][0].clone(), dx, dy, ksize );
|
test_mat[OUTPUT][1], ksize, border );
|
||||||
|
|
||||||
test_mat[OUTPUT][0] = dx;
|
|
||||||
test_mat[OUTPUT][1] = dy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CV_SpatialGradientTest::prepare_to_validation( int /*test_case_idx*/ )
|
void CV_SpatialGradientTest::prepare_to_validation( int /*test_case_idx*/ )
|
||||||
@ -607,10 +605,12 @@ void CV_SpatialGradientTest::prepare_to_validation( int /*test_case_idx*/ )
|
|||||||
int dx, dy;
|
int dx, dy;
|
||||||
|
|
||||||
dx = 1; dy = 0;
|
dx = 1; dy = 0;
|
||||||
Sobel( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], CV_16SC1, dx, dy, ksize );
|
Sobel( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], CV_16SC1, dx, dy, ksize,
|
||||||
|
1, 0, border );
|
||||||
|
|
||||||
dx = 0; dy = 1;
|
dx = 0; dy = 1;
|
||||||
Sobel( test_mat[INPUT][0], test_mat[REF_OUTPUT][1], CV_16SC1, dx, dy, ksize );
|
Sobel( test_mat[INPUT][0], test_mat[REF_OUTPUT][1], CV_16SC1, dx, dy, ksize,
|
||||||
|
1, 0, border );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user