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 // access pixel coordinates
Point pnt = locations[i]; Point pnt = locations[i];
@endcode @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 @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 ); 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. /** @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: 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) } \texttt{PSNR} = 10 \cdot \log_{10}{\left( \frac{R^2}{MSE} \right) }
\f] \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 src1 first input array.
@param src2 second input array of the same size as src1. @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 /** @brief naive nearest neighbor finder

@ -393,25 +393,60 @@ void cv::findNonZero( InputArray _src, OutputArray _idx )
CV_INSTRUMENT_REGION() CV_INSTRUMENT_REGION()
Mat src = _src.getMat(); Mat src = _src.getMat();
CV_Assert( src.type() == CV_8UC1 ); CV_Assert( src.channels() == 1 && src.dims == 2 );
int n = countNonZero(src);
if( n == 0 ) 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(); int j, k = 0;
return; 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.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++ ) if( !idxvec.empty() )
{ Mat(idxvec).copyTo(_idx);
const uchar* bin_ptr = src.ptr(i);
for( int j = 0; j < src.cols; j++ )
if( bin_ptr[j] )
*idx_ptr++ = Point(j, i);
}
} }

@ -1251,13 +1251,13 @@ cv::Hamming::ResultType cv::Hamming::operator()( const unsigned char* a, const u
return cv::hal::normHamming(a, b, size); 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() CV_INSTRUMENT_REGION()
//Input arrays must have depth CV_8U //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())); 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::Values(-1, CV_16S, CV_32S, CV_32F),
testing::Bool())); testing::Bool()));
TEST(Core_FindNonZero, singular) TEST(Core_FindNonZero, regression)
{ {
Mat img(10, 10, CV_8U, Scalar::all(0)); Mat img(10, 10, CV_8U, Scalar::all(0));
vector<Point> pts, pts2(10); vector<Point> pts, pts2(5);
findNonZero(img, pts); findNonZero(img, pts);
findNonZero(img, pts2); findNonZero(img, pts2);
ASSERT_TRUE(pts.empty() && pts2.empty()); 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) TEST(Core_BoolVector, support)

Loading…
Cancel
Save