mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
986 lines
28 KiB
986 lines
28 KiB
// This file is part of OpenCV project. |
|
// It is subject to the license terms in the LICENSE file found in the top-level directory |
|
// of this distribution and at http://opencv.org/license.html. |
|
#include "test_precomp.hpp" |
|
|
|
namespace opencv_test { namespace { |
|
|
|
static Mat initDFTWave( int n, bool inv ) |
|
{ |
|
int i; |
|
double angle = (inv ? 1 : -1)*CV_PI*2/n; |
|
Complexd wi, w1; |
|
Mat wave(1, n, CV_64FC2); |
|
Complexd* w = wave.ptr<Complexd>(); |
|
|
|
w1.re = cos(angle); |
|
w1.im = sin(angle); |
|
w[0].re = wi.re = 1.; |
|
w[0].im = wi.im = 0.; |
|
|
|
for( i = 1; i < n; i++ ) |
|
{ |
|
double t = wi.re*w1.re - wi.im*w1.im; |
|
wi.im = wi.re*w1.im + wi.im*w1.re; |
|
wi.re = t; |
|
w[i] = wi; |
|
} |
|
|
|
return wave; |
|
} |
|
|
|
|
|
static void DFT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat()) |
|
{ |
|
_dst.create(_src.size(), _src.type()); |
|
int i, j, k, n = _dst.cols + _dst.rows - 1; |
|
Mat wave = _wave; |
|
double scale = (flags & DFT_SCALE) ? 1./n : 1.; |
|
size_t esz = _src.elemSize(); |
|
size_t srcstep = esz, dststep = esz; |
|
const uchar* src0 = _src.ptr(); |
|
uchar* dst0 = _dst.ptr(); |
|
|
|
CV_Assert( _src.cols + _src.rows - 1 == n ); |
|
|
|
if( wave.empty() ) |
|
wave = initDFTWave( n, (flags & DFT_INVERSE) != 0 ); |
|
|
|
const Complexd* w = wave.ptr<Complexd>(); |
|
if( !_src.isContinuous() ) |
|
srcstep = _src.step; |
|
if( !_dst.isContinuous() ) |
|
dststep = _dst.step; |
|
|
|
if( _src.type() == CV_32FC2 ) |
|
{ |
|
for( i = 0; i < n; i++ ) |
|
{ |
|
Complexf* dst = (Complexf*)(dst0 + i*dststep); |
|
Complexd sum(0,0); |
|
int delta = i; |
|
k = 0; |
|
|
|
for( j = 0; j < n; j++ ) |
|
{ |
|
const Complexf* src = (const Complexf*)(src0 + j*srcstep); |
|
sum.re += src->re*w[k].re - src->im*w[k].im; |
|
sum.im += src->re*w[k].im + src->im*w[k].re; |
|
k += delta; |
|
k -= (k >= n ? n : 0); |
|
} |
|
|
|
dst->re = (float)(sum.re*scale); |
|
dst->im = (float)(sum.im*scale); |
|
} |
|
} |
|
else if( _src.type() == CV_64FC2 ) |
|
{ |
|
for( i = 0; i < n; i++ ) |
|
{ |
|
Complexd* dst = (Complexd*)(dst0 + i*dststep); |
|
Complexd sum(0,0); |
|
int delta = i; |
|
k = 0; |
|
|
|
for( j = 0; j < n; j++ ) |
|
{ |
|
const Complexd* src = (const Complexd*)(src0 + j*srcstep); |
|
sum.re += src->re*w[k].re - src->im*w[k].im; |
|
sum.im += src->re*w[k].im + src->im*w[k].re; |
|
k += delta; |
|
k -= (k >= n ? n : 0); |
|
} |
|
|
|
dst->re = sum.re*scale; |
|
dst->im = sum.im*scale; |
|
} |
|
} |
|
else |
|
CV_Error(CV_StsUnsupportedFormat, ""); |
|
} |
|
|
|
|
|
static void DFT_2D( const Mat& src, Mat& dst, int flags ) |
|
{ |
|
const int cn = 2; |
|
int i; |
|
dst.create(src.size(), src.type()); |
|
Mat tmp( src.cols, src.rows, src.type()); |
|
Mat wave = initDFTWave( dst.cols, (flags & DFT_INVERSE) != 0 ); |
|
|
|
// 1. row-wise transform |
|
for( i = 0; i < dst.rows; i++ ) |
|
{ |
|
Mat srci = src.row(i).reshape(cn, src.cols), dsti = tmp.col(i); |
|
DFT_1D(srci, dsti, flags, wave ); |
|
} |
|
|
|
if( (flags & DFT_ROWS) == 0 ) |
|
{ |
|
if( dst.cols != dst.rows ) |
|
wave = initDFTWave( dst.rows, (flags & DFT_INVERSE) != 0 ); |
|
|
|
// 2. column-wise transform |
|
for( i = 0; i < dst.cols; i++ ) |
|
{ |
|
Mat srci = tmp.row(i).reshape(cn, tmp.cols), dsti = dst.col(i); |
|
DFT_1D(srci, dsti, flags, wave ); |
|
} |
|
} |
|
else |
|
cvtest::transpose(tmp, dst); |
|
} |
|
|
|
|
|
static Mat initDCTWave( int n, bool inv ) |
|
{ |
|
int i, k; |
|
double angle = CV_PI*0.5/n; |
|
Mat wave(n, n, CV_64F); |
|
|
|
double scale = sqrt(1./n); |
|
for( k = 0; k < n; k++ ) |
|
wave.at<double>(0, k) = scale; |
|
scale *= sqrt(2.); |
|
for( i = 1; i < n; i++ ) |
|
for( k = 0; k < n; k++ ) |
|
wave.at<double>(i, k) = scale*cos( angle*i*(2*k + 1) ); |
|
|
|
if( inv ) |
|
cv::transpose( wave, wave ); |
|
|
|
return wave; |
|
} |
|
|
|
|
|
static void DCT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat() ) |
|
{ |
|
_dst.create( _src.size(), _src.type() ); |
|
int i, j, n = _dst.cols + _dst.rows - 1; |
|
Mat wave = _wave; |
|
int srcstep = 1, dststep = 1; |
|
double* w; |
|
|
|
CV_Assert( _src.cols + _src.rows - 1 == n); |
|
|
|
if( wave.empty() ) |
|
wave = initDCTWave( n, (flags & DFT_INVERSE) != 0 ); |
|
w = wave.ptr<double>(); |
|
|
|
if( !_src.isContinuous() ) |
|
srcstep = (int)(_src.step/_src.elemSize()); |
|
if( !_dst.isContinuous() ) |
|
dststep = (int)(_dst.step/_dst.elemSize()); |
|
|
|
if( _src.type() == CV_32FC1 ) |
|
{ |
|
float *dst = _dst.ptr<float>(); |
|
|
|
for( i = 0; i < n; i++, dst += dststep ) |
|
{ |
|
const float* src = _src.ptr<float>(); |
|
double sum = 0; |
|
|
|
for( j = 0; j < n; j++, src += srcstep ) |
|
sum += src[0]*w[j]; |
|
w += n; |
|
dst[0] = (float)sum; |
|
} |
|
} |
|
else if( _src.type() == CV_64FC1 ) |
|
{ |
|
double *dst = _dst.ptr<double>(); |
|
|
|
for( i = 0; i < n; i++, dst += dststep ) |
|
{ |
|
const double* src = _src.ptr<double>(); |
|
double sum = 0; |
|
|
|
for( j = 0; j < n; j++, src += srcstep ) |
|
sum += src[0]*w[j]; |
|
w += n; |
|
dst[0] = sum; |
|
} |
|
} |
|
else |
|
CV_Assert(0); |
|
} |
|
|
|
|
|
static void DCT_2D( const Mat& src, Mat& dst, int flags ) |
|
{ |
|
const int cn = 1; |
|
int i; |
|
dst.create( src.size(), src.type() ); |
|
Mat tmp(dst.cols, dst.rows, dst.type() ); |
|
Mat wave = initDCTWave( dst.cols, (flags & DCT_INVERSE) != 0 ); |
|
|
|
// 1. row-wise transform |
|
for( i = 0; i < dst.rows; i++ ) |
|
{ |
|
Mat srci = src.row(i).reshape(cn, src.cols); |
|
Mat dsti = tmp.col(i); |
|
DCT_1D(srci, dsti, flags, wave); |
|
} |
|
|
|
if( (flags & DCT_ROWS) == 0 ) |
|
{ |
|
if( dst.cols != dst.rows ) |
|
wave = initDCTWave( dst.rows, (flags & DCT_INVERSE) != 0 ); |
|
|
|
// 2. column-wise transform |
|
for( i = 0; i < dst.cols; i++ ) |
|
{ |
|
Mat srci = tmp.row(i).reshape(cn, tmp.cols); |
|
Mat dsti = dst.col(i); |
|
DCT_1D( srci, dsti, flags, wave ); |
|
} |
|
} |
|
else |
|
cvtest::transpose( tmp, dst ); |
|
} |
|
|
|
|
|
static void convertFromCCS( const Mat& _src0, const Mat& _src1, Mat& _dst, int flags ) |
|
{ |
|
if( _dst.rows > 1 && (_dst.cols > 1 || (flags & DFT_ROWS)) ) |
|
{ |
|
int i, count = _dst.rows, len = _dst.cols; |
|
bool is2d = (flags & DFT_ROWS) == 0; |
|
Mat src0row, src1row, dstrow; |
|
for( i = 0; i < count; i++ ) |
|
{ |
|
int j = !is2d || i == 0 ? i : count - i; |
|
src0row = _src0.row(i); |
|
src1row = _src1.row(j); |
|
dstrow = _dst.row(i); |
|
convertFromCCS( src0row, src1row, dstrow, 0 ); |
|
} |
|
|
|
if( is2d ) |
|
{ |
|
src0row = _src0.col(0); |
|
dstrow = _dst.col(0); |
|
convertFromCCS( src0row, src0row, dstrow, 0 ); |
|
if( (len & 1) == 0 ) |
|
{ |
|
src0row = _src0.col(_src0.cols - 1); |
|
dstrow = _dst.col(len/2); |
|
convertFromCCS( src0row, src0row, dstrow, 0 ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
int i, n = _dst.cols + _dst.rows - 1, n2 = (n+1) >> 1; |
|
int cn = _src0.channels(); |
|
int srcstep = cn, dststep = 1; |
|
|
|
if( !_dst.isContinuous() ) |
|
dststep = (int)(_dst.step/_dst.elemSize()); |
|
|
|
if( !_src0.isContinuous() ) |
|
srcstep = (int)(_src0.step/_src0.elemSize1()); |
|
|
|
if( _dst.depth() == CV_32F ) |
|
{ |
|
Complexf* dst = _dst.ptr<Complexf>(); |
|
const float* src0 = _src0.ptr<float>(); |
|
const float* src1 = _src1.ptr<float>(); |
|
int delta0, delta1; |
|
|
|
dst->re = src0[0]; |
|
dst->im = 0; |
|
|
|
if( (n & 1) == 0 ) |
|
{ |
|
dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep]; |
|
dst[n2*dststep].im = 0; |
|
} |
|
|
|
delta0 = srcstep; |
|
delta1 = delta0 + (cn == 1 ? srcstep : 1); |
|
if( cn == 1 ) |
|
srcstep *= 2; |
|
|
|
for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep ) |
|
{ |
|
float t0 = src0[delta0]; |
|
float t1 = src0[delta1]; |
|
|
|
dst[i*dststep].re = t0; |
|
dst[i*dststep].im = t1; |
|
|
|
t0 = src1[delta0]; |
|
t1 = -src1[delta1]; |
|
|
|
dst[(n-i)*dststep].re = t0; |
|
dst[(n-i)*dststep].im = t1; |
|
} |
|
} |
|
else |
|
{ |
|
Complexd* dst = _dst.ptr<Complexd>(); |
|
const double* src0 = _src0.ptr<double>(); |
|
const double* src1 = _src1.ptr<double>(); |
|
int delta0, delta1; |
|
|
|
dst->re = src0[0]; |
|
dst->im = 0; |
|
|
|
if( (n & 1) == 0 ) |
|
{ |
|
dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep]; |
|
dst[n2*dststep].im = 0; |
|
} |
|
|
|
delta0 = srcstep; |
|
delta1 = delta0 + (cn == 1 ? srcstep : 1); |
|
if( cn == 1 ) |
|
srcstep *= 2; |
|
|
|
for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep ) |
|
{ |
|
double t0 = src0[delta0]; |
|
double t1 = src0[delta1]; |
|
|
|
dst[i*dststep].re = t0; |
|
dst[i*dststep].im = t1; |
|
|
|
t0 = src1[delta0]; |
|
t1 = -src1[delta1]; |
|
|
|
dst[(n-i)*dststep].re = t0; |
|
dst[(n-i)*dststep].im = t1; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
static void fixCCS( Mat& mat, int cols, int flags ) |
|
{ |
|
int i, rows = mat.rows; |
|
int rows2 = (flags & DFT_ROWS) ? rows : rows/2 + 1, cols2 = cols/2 + 1; |
|
|
|
CV_Assert( cols2 == mat.cols ); |
|
|
|
if( mat.type() == CV_32FC2 ) |
|
{ |
|
for( i = 0; i < rows2; i++ ) |
|
{ |
|
Complexf* row = mat.ptr<Complexf>(i); |
|
if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) ) |
|
{ |
|
row[0].im = 0; |
|
if( cols % 2 == 0 ) |
|
row[cols2-1].im = 0; |
|
} |
|
else |
|
{ |
|
Complexf* row2 = mat.ptr<Complexf>(rows-i); |
|
row2[0].re = row[0].re; |
|
row2[0].im = -row[0].im; |
|
|
|
if( cols % 2 == 0 ) |
|
{ |
|
row2[cols2-1].re = row[cols2-1].re; |
|
row2[cols2-1].im = -row[cols2-1].im; |
|
} |
|
} |
|
} |
|
} |
|
else if( mat.type() == CV_64FC2 ) |
|
{ |
|
for( i = 0; i < rows2; i++ ) |
|
{ |
|
Complexd* row = mat.ptr<Complexd>(i); |
|
if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) ) |
|
{ |
|
row[0].im = 0; |
|
if( cols % 2 == 0 ) |
|
row[cols2-1].im = 0; |
|
} |
|
else |
|
{ |
|
Complexd* row2 = mat.ptr<Complexd>(rows-i); |
|
row2[0].re = row[0].re; |
|
row2[0].im = -row[0].im; |
|
|
|
if( cols % 2 == 0 ) |
|
{ |
|
row2[cols2-1].re = row[cols2-1].re; |
|
row2[cols2-1].im = -row[cols2-1].im; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
static void mulComplex( const Mat& src1, const Mat& src2, Mat& dst, int flags ) |
|
{ |
|
dst.create(src1.rows, src1.cols, src1.type()); |
|
int i, j, depth = src1.depth(), cols = src1.cols*2; |
|
|
|
CV_Assert( src1.size == src2.size && src1.type() == src2.type() && |
|
(src1.type() == CV_32FC2 || src1.type() == CV_64FC2) ); |
|
|
|
const Mat* src1_ = &src1; |
|
Mat src1_tmp; |
|
if (dst.data == src1.data) |
|
{ |
|
src1_tmp = src1.clone(); |
|
src1_ = &src1_tmp; |
|
} |
|
const Mat* src2_ = &src2; |
|
Mat src2_tmp; |
|
if (dst.data == src2.data) |
|
{ |
|
src2_tmp = src2.clone(); |
|
src2_ = &src2_tmp; |
|
} |
|
|
|
for( i = 0; i < dst.rows; i++ ) |
|
{ |
|
if( depth == CV_32F ) |
|
{ |
|
const float* a = src1_->ptr<float>(i); |
|
const float* b = src2_->ptr<float>(i); |
|
float* c = dst.ptr<float>(i); |
|
|
|
if( !(flags & CV_DXT_MUL_CONJ) ) |
|
for( j = 0; j < cols; j += 2 ) |
|
{ |
|
double re = (double)a[j]*(double)b[j] - (double)a[j+1]*(double)b[j+1]; |
|
double im = (double)a[j+1]*(double)b[j] + (double)a[j]*(double)b[j+1]; |
|
|
|
c[j] = (float)re; |
|
c[j+1] = (float)im; |
|
} |
|
else |
|
for( j = 0; j < cols; j += 2 ) |
|
{ |
|
double re = (double)a[j]*(double)b[j] + (double)a[j+1]*(double)b[j+1]; |
|
double im = (double)a[j+1]*(double)b[j] - (double)a[j]*(double)b[j+1]; |
|
|
|
c[j] = (float)re; |
|
c[j+1] = (float)im; |
|
} |
|
} |
|
else |
|
{ |
|
const double* a = src1_->ptr<double>(i); |
|
const double* b = src2_->ptr<double>(i); |
|
double* c = dst.ptr<double>(i); |
|
|
|
if( !(flags & CV_DXT_MUL_CONJ) ) |
|
for( j = 0; j < cols; j += 2 ) |
|
{ |
|
double re = a[j]*b[j] - a[j+1]*b[j+1]; |
|
double im = a[j+1]*b[j] + a[j]*b[j+1]; |
|
|
|
c[j] = re; |
|
c[j+1] = im; |
|
} |
|
else |
|
for( j = 0; j < cols; j += 2 ) |
|
{ |
|
double re = a[j]*b[j] + a[j+1]*b[j+1]; |
|
double im = a[j+1]*b[j] - a[j]*b[j+1]; |
|
|
|
c[j] = re; |
|
c[j+1] = im; |
|
} |
|
} |
|
} |
|
} |
|
|
|
class CxCore_DXTBaseTest : public cvtest::ArrayTest |
|
{ |
|
public: |
|
typedef cvtest::ArrayTest Base; |
|
CxCore_DXTBaseTest( bool _allow_complex=false, bool _allow_odd=false, |
|
bool _spectrum_mode=false ); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); |
|
int prepare_test_case( int test_case_idx ); |
|
double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ); |
|
int flags; // transformation flags |
|
bool allow_complex; // whether input/output may be complex or not: |
|
// true for DFT and MulSpectrums, false for DCT |
|
bool allow_odd; // whether input/output may be have odd (!=1) dimensions: |
|
// true for DFT and MulSpectrums, false for DCT |
|
bool spectrum_mode; // (2 complex/ccs inputs, 1 complex/ccs output): |
|
// true for MulSpectrums, false for DFT and DCT |
|
bool inplace; // inplace operation (set for each individual test case) |
|
bool temp_dst; // use temporary destination (for real->ccs DFT and ccs MulSpectrums) |
|
}; |
|
|
|
|
|
CxCore_DXTBaseTest::CxCore_DXTBaseTest( bool _allow_complex, bool _allow_odd, bool _spectrum_mode ) |
|
: Base(), flags(0), allow_complex(_allow_complex), allow_odd(_allow_odd), |
|
spectrum_mode(_spectrum_mode), inplace(false), temp_dst(false) |
|
{ |
|
test_array[INPUT].push_back(NULL); |
|
if( spectrum_mode ) |
|
test_array[INPUT].push_back(NULL); |
|
test_array[OUTPUT].push_back(NULL); |
|
test_array[REF_OUTPUT].push_back(NULL); |
|
test_array[TEMP].push_back(NULL); |
|
test_array[TEMP].push_back(NULL); |
|
|
|
max_log_array_size = 9; |
|
element_wise_relative_error = spectrum_mode; |
|
} |
|
|
|
|
|
void CxCore_DXTBaseTest::get_test_array_types_and_sizes( int test_case_idx, |
|
vector<vector<Size> >& sizes, |
|
vector<vector<int> >& types ) |
|
{ |
|
RNG& rng = ts->get_rng(); |
|
int bits = cvtest::randInt(rng); |
|
int depth = cvtest::randInt(rng)%2 + CV_32F; |
|
int cn = !allow_complex || !(bits & 256) ? 1 : 2; |
|
Size size; |
|
Base::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
flags = bits & (CV_DXT_INVERSE | CV_DXT_SCALE | CV_DXT_ROWS | CV_DXT_MUL_CONJ); |
|
if( spectrum_mode ) |
|
flags &= ~CV_DXT_INVERSE; |
|
types[TEMP][0] = types[TEMP][1] = types[INPUT][0] = |
|
types[OUTPUT][0] = CV_MAKETYPE(depth, cn); |
|
size = sizes[INPUT][0]; |
|
|
|
temp_dst = false; |
|
|
|
if( flags & CV_DXT_ROWS && (bits&1024) ) |
|
{ |
|
if( bits&16 ) |
|
size.width = 1; |
|
else |
|
size.height = 1; |
|
flags &= ~CV_DXT_ROWS; |
|
} |
|
|
|
const int P2_MIN_SIZE = 32; |
|
if( ((bits >> 10) & 1) == 0 ) |
|
{ |
|
size.width = (size.width / P2_MIN_SIZE)*P2_MIN_SIZE; |
|
size.width = MAX(size.width, 1); |
|
size.height = (size.height / P2_MIN_SIZE)*P2_MIN_SIZE; |
|
size.height = MAX(size.height, 1); |
|
} |
|
|
|
if( !allow_odd ) |
|
{ |
|
if( size.width > 1 && (size.width&1) != 0 ) |
|
size.width = (size.width + 1) & -2; |
|
|
|
if( size.height > 1 && (size.height&1) != 0 && !(flags & CV_DXT_ROWS) ) |
|
size.height = (size.height + 1) & -2; |
|
} |
|
|
|
sizes[INPUT][0] = sizes[OUTPUT][0] = size; |
|
sizes[TEMP][0] = sizes[TEMP][1] = cvSize(0,0); |
|
|
|
if( spectrum_mode ) |
|
{ |
|
if( cn == 1 ) |
|
{ |
|
types[OUTPUT][0] = depth + 8; |
|
sizes[TEMP][0] = size; |
|
} |
|
sizes[INPUT][0] = sizes[INPUT][1] = size; |
|
types[INPUT][1] = types[INPUT][0]; |
|
} |
|
else if( /*(cn == 2 && (bits&32)) ||*/ (cn == 1 && allow_complex) ) |
|
{ |
|
types[TEMP][0] = depth + 8; // CV_??FC2 |
|
sizes[TEMP][0] = size; |
|
size = cvSize(size.width/2+1, size.height); |
|
|
|
if( flags & CV_DXT_INVERSE ) |
|
{ |
|
if( cn == 2 ) |
|
{ |
|
types[OUTPUT][0] = depth; |
|
sizes[INPUT][0] = size; |
|
} |
|
types[TEMP][1] = types[TEMP][0]; |
|
sizes[TEMP][1] = sizes[TEMP][0]; |
|
} |
|
else |
|
{ |
|
if( allow_complex ) |
|
types[OUTPUT][0] = depth + 8; |
|
|
|
if( cn == 2 ) |
|
{ |
|
types[INPUT][0] = depth; |
|
types[TEMP][1] = types[TEMP][0]; |
|
sizes[TEMP][1] = size; |
|
} |
|
else |
|
{ |
|
types[TEMP][1] = depth; |
|
sizes[TEMP][1] = sizes[TEMP][0]; |
|
} |
|
temp_dst = true; |
|
} |
|
} |
|
|
|
inplace = false; |
|
if( spectrum_mode || |
|
(!temp_dst && types[INPUT][0] == types[OUTPUT][0]) || |
|
(temp_dst && types[INPUT][0] == types[TEMP][1]) ) |
|
inplace = (bits & 64) != 0; |
|
|
|
types[REF_OUTPUT][0] = types[OUTPUT][0]; |
|
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0]; |
|
} |
|
|
|
|
|
double CxCore_DXTBaseTest::get_success_error_level( int test_case_idx, int i, int j ) |
|
{ |
|
return Base::get_success_error_level( test_case_idx, i, j ); |
|
} |
|
|
|
|
|
int CxCore_DXTBaseTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = Base::prepare_test_case( test_case_idx ); |
|
if( code > 0 ) |
|
{ |
|
int in_type = test_mat[INPUT][0].type(); |
|
int out_type = test_mat[OUTPUT][0].type(); |
|
|
|
if( CV_MAT_CN(in_type) == 2 && CV_MAT_CN(out_type) == 1 ) |
|
fixCCS( test_mat[INPUT][0], test_mat[OUTPUT][0].cols, flags ); |
|
|
|
if( inplace ) |
|
cvtest::copy( test_mat[INPUT][test_case_idx & (int)spectrum_mode], |
|
temp_dst ? test_mat[TEMP][1] : |
|
in_type == out_type ? test_mat[OUTPUT][0] : |
|
test_mat[TEMP][0] ); |
|
} |
|
|
|
return code; |
|
} |
|
|
|
|
|
////////////////////// FFT //////////////////////// |
|
class CxCore_DFTTest : public CxCore_DXTBaseTest |
|
{ |
|
public: |
|
CxCore_DFTTest(); |
|
protected: |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
}; |
|
|
|
|
|
CxCore_DFTTest::CxCore_DFTTest() : CxCore_DXTBaseTest( true, true, false ) |
|
{ |
|
} |
|
|
|
|
|
void CxCore_DFTTest::run_func() |
|
{ |
|
Mat& dst = temp_dst ? test_mat[TEMP][1] : test_mat[OUTPUT][0]; |
|
const Mat& src = inplace ? dst : test_mat[INPUT][0]; |
|
|
|
if(!(flags & CV_DXT_INVERSE)) |
|
cv::dft( src, dst, flags ); |
|
else |
|
cv::idft(src, dst, flags & ~CV_DXT_INVERSE); |
|
} |
|
|
|
|
|
void CxCore_DFTTest::prepare_to_validation( int /*test_case_idx*/ ) |
|
{ |
|
Mat& src = test_mat[INPUT][0]; |
|
Mat& dst = test_mat[REF_OUTPUT][0]; |
|
Mat* tmp_src = &src; |
|
Mat* tmp_dst = &dst; |
|
int src_cn = src.channels(); |
|
int dst_cn = dst.channels(); |
|
|
|
if( src_cn != 2 || dst_cn != 2 ) |
|
{ |
|
tmp_src = &test_mat[TEMP][0]; |
|
|
|
if( !(flags & CV_DXT_INVERSE ) ) |
|
{ |
|
Mat& cvdft_dst = test_mat[TEMP][1]; |
|
convertFromCCS( cvdft_dst, cvdft_dst, |
|
test_mat[OUTPUT][0], flags ); |
|
*tmp_src = Scalar::all(0); |
|
cvtest::insert( src, *tmp_src, 0 ); |
|
} |
|
else |
|
{ |
|
convertFromCCS( src, src, *tmp_src, flags ); |
|
tmp_dst = &test_mat[TEMP][1]; |
|
} |
|
} |
|
|
|
if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) ) |
|
DFT_1D( *tmp_src, *tmp_dst, flags ); |
|
else |
|
DFT_2D( *tmp_src, *tmp_dst, flags ); |
|
|
|
if( tmp_dst != &dst ) |
|
cvtest::extract( *tmp_dst, dst, 0 ); |
|
} |
|
|
|
////////////////////// DCT //////////////////////// |
|
class CxCore_DCTTest : public CxCore_DXTBaseTest |
|
{ |
|
public: |
|
CxCore_DCTTest(); |
|
protected: |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
}; |
|
|
|
|
|
CxCore_DCTTest::CxCore_DCTTest() : CxCore_DXTBaseTest( false, false, false ) |
|
{ |
|
} |
|
|
|
|
|
void CxCore_DCTTest::run_func() |
|
{ |
|
Mat& dst = test_mat[OUTPUT][0]; |
|
const Mat& src = inplace ? dst : test_mat[INPUT][0]; |
|
|
|
if(!(flags & CV_DXT_INVERSE)) |
|
cv::dct( src, dst, flags ); |
|
else |
|
cv::idct( src, dst, flags & ~CV_DXT_INVERSE); |
|
} |
|
|
|
|
|
void CxCore_DCTTest::prepare_to_validation( int /*test_case_idx*/ ) |
|
{ |
|
const Mat& src = test_mat[INPUT][0]; |
|
Mat& dst = test_mat[REF_OUTPUT][0]; |
|
|
|
if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) ) |
|
DCT_1D( src, dst, flags ); |
|
else |
|
DCT_2D( src, dst, flags ); |
|
} |
|
|
|
|
|
////////////////////// MulSpectrums //////////////////////// |
|
class CxCore_MulSpectrumsTest : public CxCore_DXTBaseTest |
|
{ |
|
public: |
|
CxCore_MulSpectrumsTest(); |
|
protected: |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
}; |
|
|
|
|
|
CxCore_MulSpectrumsTest::CxCore_MulSpectrumsTest() : CxCore_DXTBaseTest( true, true, true ) |
|
{ |
|
} |
|
|
|
double CxCore_MulSpectrumsTest::get_success_error_level( int test_case_idx, int i, int j ) |
|
{ |
|
CV_UNUSED(test_case_idx); |
|
CV_Assert(i == OUTPUT); |
|
CV_Assert(j == 0); |
|
int elem_depth = CV_MAT_DEPTH(cvGetElemType(test_array[i][j])); |
|
CV_Assert(elem_depth == CV_32F || elem_depth == CV_64F); |
|
|
|
element_wise_relative_error = false; |
|
double maxInputValue = 1000; // ArrayTest::get_minmax_bounds |
|
double err = 8 * maxInputValue; // result = A*B + C*D |
|
return (elem_depth == CV_32F ? FLT_EPSILON : DBL_EPSILON) * err; |
|
} |
|
|
|
void CxCore_MulSpectrumsTest::run_func() |
|
{ |
|
Mat& dst = !test_mat[TEMP].empty() && !test_mat[TEMP][0].empty() ? |
|
test_mat[TEMP][0] : test_mat[OUTPUT][0]; |
|
const Mat* src1 = &test_mat[INPUT][0], *src2 = &test_mat[INPUT][1]; |
|
|
|
if( inplace ) |
|
{ |
|
if( ts->get_current_test_info()->test_case_idx & 1 ) |
|
src2 = &dst; |
|
else |
|
src1 = &dst; |
|
} |
|
|
|
cv::mulSpectrums( *src1, *src2, dst, flags, (flags & CV_DXT_MUL_CONJ) != 0 ); |
|
} |
|
|
|
|
|
void CxCore_MulSpectrumsTest::prepare_to_validation( int /*test_case_idx*/ ) |
|
{ |
|
Mat* src1 = &test_mat[INPUT][0]; |
|
Mat* src2 = &test_mat[INPUT][1]; |
|
Mat& dst = test_mat[OUTPUT][0]; |
|
Mat& dst0 = test_mat[REF_OUTPUT][0]; |
|
int cn = src1->channels(); |
|
|
|
if( cn == 1 ) |
|
{ |
|
convertFromCCS( *src1, *src1, dst, flags ); |
|
convertFromCCS( *src2, *src2, dst0, flags ); |
|
src1 = &dst; |
|
src2 = &dst0; |
|
} |
|
|
|
mulComplex( *src1, *src2, dst0, flags ); |
|
if( cn == 1 ) |
|
{ |
|
Mat& temp = test_mat[TEMP][0]; |
|
convertFromCCS( temp, temp, dst, flags ); |
|
} |
|
} |
|
|
|
TEST(Core_DCT, accuracy) { CxCore_DCTTest test; test.safe_run(); } |
|
TEST(Core_DFT, accuracy) { CxCore_DFTTest test; test.safe_run(); } |
|
TEST(Core_MulSpectrums, accuracy) { CxCore_MulSpectrumsTest test; test.safe_run(); } |
|
|
|
class Core_DFTComplexOutputTest : public cvtest::BaseTest |
|
{ |
|
public: |
|
Core_DFTComplexOutputTest() {} |
|
~Core_DFTComplexOutputTest() {} |
|
protected: |
|
void run(int) |
|
{ |
|
RNG& rng = theRNG(); |
|
for( int i = 0; i < 10; i++ ) |
|
{ |
|
int m = rng.uniform(2, 11); |
|
int n = rng.uniform(2, 11); |
|
int depth = rng.uniform(0, 2) + CV_32F; |
|
Mat src8u(m, n, depth), src(m, n, depth), dst(m, n, CV_MAKETYPE(depth, 2)); |
|
Mat z = Mat::zeros(m, n, depth), dstz; |
|
randu(src8u, Scalar::all(0), Scalar::all(10)); |
|
src8u.convertTo(src, src.type()); |
|
dst = Scalar::all(123); |
|
Mat mv[] = {src, z}, srcz; |
|
merge(mv, 2, srcz); |
|
dft(srcz, dstz); |
|
dft(src, dst, DFT_COMPLEX_OUTPUT); |
|
if (cvtest::norm(dst, dstz, NORM_INF) > 1e-3) |
|
{ |
|
cout << "actual:\n" << dst << endl << endl; |
|
cout << "reference:\n" << dstz << endl << endl; |
|
CV_Error(CV_StsError, ""); |
|
} |
|
} |
|
} |
|
}; |
|
|
|
TEST(Core_DFT, complex_output) { Core_DFTComplexOutputTest test; test.safe_run(); } |
|
|
|
TEST(Core_DFT, complex_output2) |
|
{ |
|
for( int i = 0; i < 100; i++ ) |
|
{ |
|
int type = theRNG().uniform(0, 2) ? CV_64F : CV_32F; |
|
int m = theRNG().uniform(1, 10); |
|
int n = theRNG().uniform(1, 10); |
|
Mat x(m, n, type), out; |
|
randu(x, -1., 1.); |
|
dft(x, out, DFT_ROWS | DFT_COMPLEX_OUTPUT); |
|
double nrm = cvtest::norm(out, NORM_INF); |
|
double thresh = n*m*2; |
|
if( nrm > thresh ) |
|
{ |
|
cout << "x: " << x << endl; |
|
cout << "out: " << out << endl; |
|
ASSERT_LT(nrm, thresh); |
|
} |
|
} |
|
} |
|
|
|
class Core_DXTReverseTest : public cvtest::BaseTest |
|
{ |
|
public: |
|
enum Mode |
|
{ |
|
ModeDFT, |
|
ModeDCT |
|
}; |
|
Core_DXTReverseTest(Mode m) : mode(m) {} |
|
private: |
|
Mode mode; |
|
protected: |
|
void run(int) |
|
{ |
|
for (int i = 0; i < 3; ++i) |
|
{ |
|
if (mode == ModeDCT && i != 0) |
|
continue; |
|
int flags = 0; |
|
int flags_inv = DFT_INVERSE | DFT_SCALE; |
|
int cn_in = 0; |
|
int cn_out = 0; |
|
switch (i) |
|
{ |
|
case 0: cn_in = 1; cn_out = 1; break; |
|
case 1: cn_in = 1; cn_out = 2; flags |= DFT_COMPLEX_OUTPUT; flags_inv |= DFT_REAL_OUTPUT; break; |
|
case 2: cn_in = 2; cn_out = 2; break; |
|
}; |
|
for (int j = 0; j < 100; ++j) |
|
{ |
|
RNG& rng = ts->get_rng(); |
|
int type = rng.uniform(0, 2) ? CV_64F : CV_32F; |
|
int m = rng.uniform(1, 10); |
|
int n = rng.uniform(1, 10); |
|
if (mode == ModeDCT) |
|
{ |
|
m *= 2; |
|
n *= 2; |
|
} |
|
Mat one(m, n, CV_MAKETYPE(type, cn_in)); |
|
cvtest::randUni(rng, one, Scalar::all(-1.), Scalar::all(1.)); |
|
Mat out; |
|
Mat two; |
|
if (mode == ModeDFT) |
|
{ |
|
cv::dft(one, out, flags); |
|
cv::dft(out, two, flags_inv); |
|
} |
|
else if (mode == ModeDCT) |
|
{ |
|
cv::dct(one, out, flags); |
|
cv::dct(out, two, flags_inv); |
|
} |
|
if (out.channels() != cn_out || two.channels() != cn_in || cvtest::norm(one, two, NORM_INF) > 1e-5) |
|
{ |
|
cout << "Test #" << j + 1 << " - " |
|
<< "elements: " << m << " x " << n << ", " |
|
<< "channels: " |
|
<< one.channels() << " (" << cn_in << ")" << " -> " |
|
<< out.channels() << " (" << cn_out << ")" << " -> " |
|
<< two.channels() << " (" << cn_in << ")" |
|
<< endl; |
|
cout << "signal:\n" << one << endl << endl; |
|
cout << "spectrum:\n" << out << endl << endl; |
|
cout << "inverse:\n" << two << endl << endl; |
|
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT); |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
|
|
TEST(Core_DFT, reverse) { Core_DXTReverseTest test(Core_DXTReverseTest::ModeDFT); test.safe_run(); } |
|
TEST(Core_DCT, reverse) { Core_DXTReverseTest test(Core_DXTReverseTest::ModeDCT); test.safe_run(); } |
|
|
|
}} // namespace
|
|
|