a part of PR #11364 (extended findNonZero & PSNR) (#11837)

* a part of https://github.com/opencv/opencv/pull/11364 by Tetragramm. Rewritten and extended findNonZero & PSNR to support more types, not just 8u.

* fixed compile & doxygen warnings

* fixed small bug in findNonZero test
pull/7153/merge
Vadim Pisarevsky 6 years ago committed by GitHub
parent cc8db99695
commit 051b40f956
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      modules/core/include/opencv2/core.hpp
  2. 69
      modules/core/src/count_non_zero.cpp
  3. 6
      modules/core/src/norm.cpp
  4. 45
      modules/core/test/test_arithm.cpp

@ -599,7 +599,7 @@ or
// access pixel coordinates
Point pnt = locations[i];
@endcode
@param src single-channel array (type CV_8UC1)
@param src single-channel array
@param idx the output array, type of cv::Mat or std::vector<Point>, corresponding to non-zero indices in the input
*/
CV_EXPORTS_W void findNonZero( InputArray src, OutputArray idx );
@ -699,7 +699,8 @@ CV_EXPORTS double norm( const SparseMat& src, int normType );
/** @brief Computes the Peak Signal-to-Noise Ratio (PSNR) image quality metric.
This function calculates the Peak Signal-to-Noise Ratio (PSNR) image quality metric in decibels (dB), between two input arrays src1 and src2. Arrays must have depth CV_8U.
This function calculates the Peak Signal-to-Noise Ratio (PSNR) image quality metric in decibels (dB),
between two input arrays src1 and src2. The arrays must have the same type.
The PSNR is calculated as follows:
@ -707,13 +708,15 @@ The PSNR is calculated as follows:
\texttt{PSNR} = 10 \cdot \log_{10}{\left( \frac{R^2}{MSE} \right) }
\f]
where R is the maximum integer value of depth CV_8U (255) and MSE is the mean squared error between the two arrays.
where R is the maximum integer value of depth (e.g. 255 in the case of CV_8U data)
and MSE is the mean squared error between the two arrays.
@param src1 first input array.
@param src2 second input array of the same size as src1.
@param R the maximum pixel value (255 by default)
*/
CV_EXPORTS_W double PSNR(InputArray src1, InputArray src2);
CV_EXPORTS_W double PSNR(InputArray src1, InputArray src2, double R=255.);
/** @brief naive nearest neighbor finder

@ -393,25 +393,60 @@ void cv::findNonZero( InputArray _src, OutputArray _idx )
CV_INSTRUMENT_REGION()
Mat src = _src.getMat();
CV_Assert( src.type() == CV_8UC1 );
int n = countNonZero(src);
if( n == 0 )
CV_Assert( src.channels() == 1 && src.dims == 2 );
int depth = src.depth();
std::vector<Point> idxvec;
int rows = src.rows, cols = src.cols;
AutoBuffer<int> buf_(cols + 1);
int* buf = buf_;
for( int i = 0; i < rows; i++ )
{
_idx.release();
return;
int j, k = 0;
const uchar* ptr8 = src.ptr(i);
if( depth == CV_8U || depth == CV_8S )
{
for( j = 0; j < cols; j++ )
if( ptr8[j] != 0 ) buf[k++] = j;
}
else if( depth == CV_16U || depth == CV_16S )
{
const ushort* ptr16 = (const ushort*)ptr8;
for( j = 0; j < cols; j++ )
if( ptr16[j] != 0 ) buf[k++] = j;
}
else if( depth == CV_32S )
{
const int* ptr32s = (const int*)ptr8;
for( j = 0; j < cols; j++ )
if( ptr32s[j] != 0 ) buf[k++] = j;
}
else if( depth == CV_32F )
{
const float* ptr32f = (const float*)ptr8;
for( j = 0; j < cols; j++ )
if( ptr32f[j] != 0 ) buf[k++] = j;
}
else
{
const double* ptr64f = (const double*)ptr8;
for( j = 0; j < cols; j++ )
if( ptr64f[j] != 0 ) buf[k++] = j;
}
if( k > 0 )
{
size_t sz = idxvec.size();
idxvec.resize(sz + k);
for( j = 0; j < k; j++ )
idxvec[sz + j] = Point(buf[j], i);
}
}
if( _idx.kind() == _InputArray::MAT && !_idx.getMatRef().isContinuous() )
if( idxvec.empty() || (_idx.kind() == _InputArray::MAT && !_idx.getMatRef().isContinuous()) )
_idx.release();
_idx.create(n, 1, CV_32SC2);
Mat idx = _idx.getMat();
CV_Assert(idx.isContinuous());
Point* idx_ptr = idx.ptr<Point>();
for( int i = 0; i < src.rows; i++ )
{
const uchar* bin_ptr = src.ptr(i);
for( int j = 0; j < src.cols; j++ )
if( bin_ptr[j] )
*idx_ptr++ = Point(j, i);
}
if( !idxvec.empty() )
Mat(idxvec).copyTo(_idx);
}

@ -1251,13 +1251,13 @@ cv::Hamming::ResultType cv::Hamming::operator()( const unsigned char* a, const u
return cv::hal::normHamming(a, b, size);
}
double cv::PSNR(InputArray _src1, InputArray _src2)
double cv::PSNR(InputArray _src1, InputArray _src2, double R)
{
CV_INSTRUMENT_REGION()
//Input arrays must have depth CV_8U
CV_Assert( _src1.depth() == CV_8U && _src2.depth() == CV_8U );
CV_Assert( _src1.type() == _src2.type() );
double diff = std::sqrt(norm(_src1, _src2, NORM_L2SQR)/(_src1.total()*_src1.channels()));
return 20*log10(255./(diff+DBL_EPSILON));
return 20*log10(R/(diff+DBL_EPSILON));
}

@ -1847,13 +1847,54 @@ INSTANTIATE_TEST_CASE_P(Arithm, SubtractOutputMatNotEmpty, testing::Combine(
testing::Values(-1, CV_16S, CV_32S, CV_32F),
testing::Bool()));
TEST(Core_FindNonZero, singular)
TEST(Core_FindNonZero, regression)
{
Mat img(10, 10, CV_8U, Scalar::all(0));
vector<Point> pts, pts2(10);
vector<Point> pts, pts2(5);
findNonZero(img, pts);
findNonZero(img, pts2);
ASSERT_TRUE(pts.empty() && pts2.empty());
RNG rng((uint64)-1);
size_t nz = 0;
for( int i = 0; i < 10; i++ )
{
int idx = rng.uniform(0, img.rows*img.cols);
if( !img.data[idx] ) nz++;
img.data[idx] = (uchar)rng.uniform(1, 256);
}
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_8S );
pts.clear();
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_16U );
pts.resize(pts.size()*2);
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_16S );
pts.resize(pts.size()*3);
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_32S );
pts.resize(pts.size()*4);
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_32F );
pts.resize(pts.size()*5);
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
img.convertTo( img, CV_64F );
pts.clear();
findNonZero(img, pts);
ASSERT_TRUE(pts.size() == nz);
}
TEST(Core_BoolVector, support)

Loading…
Cancel
Save