mirror of
https://github.com/opencv/opencv.git
synced 2024-11-25 11:40:44 +08:00
checkRange fixes
1) fix multichannel support 2) remove useless bad_value, read value from original Mat directly 3) add more tests 4) fix docs for cvCeil and checkRange
This commit is contained in:
parent
8e67f0ba84
commit
b26580cc7b
@ -1509,7 +1509,7 @@ CV_EXPORTS_W void magnitude(InputArray x, InputArray y, OutputArray magnitude);
|
||||
|
||||
/** @brief Checks every element of an input array for invalid values.
|
||||
|
||||
The functions checkRange check that every array element is neither NaN nor infinite. When minVal \<
|
||||
The functions checkRange check that every array element is neither NaN nor infinite. When minVal \>
|
||||
-DBL_MAX and maxVal \< DBL_MAX, the functions also check that each value is between minVal and
|
||||
maxVal. In case of multi-channel arrays, each channel is processed independently. If some values
|
||||
are out of range, position of the first outlier is stored in pos (when pos != NULL). Then, the
|
||||
@ -2906,6 +2906,21 @@ public:
|
||||
|
||||
};
|
||||
|
||||
static inline
|
||||
String& operator << (String& out, Ptr<Formatted> fmtd)
|
||||
{
|
||||
fmtd->reset();
|
||||
for(const char* str = fmtd->next(); str; str = fmtd->next())
|
||||
out += cv::String(str);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline
|
||||
String& operator << (String& out, const Mat& mtx)
|
||||
{
|
||||
return out << Formatter::get()->format(mtx);
|
||||
}
|
||||
|
||||
//////////////////////////////////////// Algorithm ////////////////////////////////////
|
||||
|
||||
class CV_EXPORTS Algorithm;
|
||||
|
@ -1571,9 +1571,8 @@ template<> struct mat_type_assotiations<CV_32S>
|
||||
static const type max_allowable = INT_MAX;
|
||||
};
|
||||
|
||||
// inclusive maxVal !!!
|
||||
template<int depth>
|
||||
bool checkIntegerRange(cv::Mat src, Point& bad_pt, int minVal, int maxVal, double& bad_value)
|
||||
static bool checkIntegerRange(cv::Mat src, Point& bad_pt, int minVal, int maxVal)
|
||||
{
|
||||
typedef mat_type_assotiations<depth> type_ass;
|
||||
|
||||
@ -1591,20 +1590,19 @@ bool checkIntegerRange(cv::Mat src, Point& bad_pt, int minVal, int maxVal, doubl
|
||||
for (int j = 0; j < as_one_channel.rows; ++j)
|
||||
for (int i = 0; i < as_one_channel.cols; ++i)
|
||||
{
|
||||
if (as_one_channel.at<typename type_ass::type>(j ,i) < minVal || as_one_channel.at<typename type_ass::type>(j ,i) > maxVal)
|
||||
typename type_ass::type v = as_one_channel.at<typename type_ass::type>(j ,i);
|
||||
if (v < minVal || v > maxVal)
|
||||
{
|
||||
bad_pt.y = j ;
|
||||
bad_pt.x = i % src.channels();
|
||||
bad_value = as_one_channel.at<typename type_ass::type>(j ,i);
|
||||
bad_pt.y = j;
|
||||
bad_pt.x = i / src.channels();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bad_value = 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*check_range_function)(cv::Mat src, Point& bad_pt, int minVal, int maxVal, double& bad_value);
|
||||
typedef bool (*check_range_function)(cv::Mat src, Point& bad_pt, int minVal, int maxVal);
|
||||
|
||||
check_range_function check_range_functions[] =
|
||||
{
|
||||
@ -1621,15 +1619,16 @@ bool checkRange(InputArray _src, bool quiet, Point* pt, double minVal, double ma
|
||||
|
||||
if ( src.dims > 2 )
|
||||
{
|
||||
CV_Assert(pt == NULL); // no way to provide location info
|
||||
|
||||
const Mat* arrays[] = {&src, 0};
|
||||
Mat planes[1];
|
||||
NAryMatIterator it(arrays, planes);
|
||||
|
||||
for ( size_t i = 0; i < it.nplanes; i++, ++it )
|
||||
{
|
||||
if (!checkRange( it.planes[0], quiet, pt, minVal, maxVal ))
|
||||
if (!checkRange( it.planes[0], quiet, NULL, minVal, maxVal ))
|
||||
{
|
||||
// todo: set index properly
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1638,20 +1637,19 @@ bool checkRange(InputArray _src, bool quiet, Point* pt, double minVal, double ma
|
||||
|
||||
int depth = src.depth();
|
||||
Point badPt(-1, -1);
|
||||
double badValue = 0;
|
||||
|
||||
if (depth < CV_32F)
|
||||
{
|
||||
// see "Bug #1784"
|
||||
int minVali = minVal<(-INT_MAX - 1) ? (-INT_MAX - 1) : cvFloor(minVal);
|
||||
int maxVali = maxVal>INT_MAX ? INT_MAX : cvCeil(maxVal) - 1; // checkIntegerRang() use inclusive maxVal
|
||||
int minVali = minVal <= INT_MIN ? INT_MIN : cvFloor(minVal);
|
||||
int maxVali = maxVal > INT_MAX ? INT_MAX : cvCeil(maxVal) - 1;
|
||||
|
||||
(check_range_functions[depth])(src, badPt, minVali, maxVali, badValue);
|
||||
(check_range_functions[depth])(src, badPt, minVali, maxVali);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, loc = 0;
|
||||
Size size = getContinuousSize( src, src.channels() );
|
||||
int cn = src.channels();
|
||||
Size size = getContinuousSize( src, cn );
|
||||
|
||||
if( depth == CV_32F )
|
||||
{
|
||||
@ -1675,8 +1673,8 @@ bool checkRange(InputArray _src, bool quiet, Point* pt, double minVal, double ma
|
||||
|
||||
if( val < ia || val >= ib )
|
||||
{
|
||||
badPt = Point((loc + i) % src.cols, (loc + i) / src.cols);
|
||||
badValue = ((const float*)isrc)[i];
|
||||
int pixelId = (loc + i) / cn;
|
||||
badPt = Point(pixelId % src.cols, pixelId / src.cols);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1704,8 +1702,8 @@ bool checkRange(InputArray _src, bool quiet, Point* pt, double minVal, double ma
|
||||
|
||||
if( val < ia || val >= ib )
|
||||
{
|
||||
badPt = Point((loc + i) % src.cols, (loc + i) / src.cols);
|
||||
badValue = ((const double*)isrc)[i];
|
||||
int pixelId = (loc + i) / cn;
|
||||
badPt = Point(pixelId % src.cols, pixelId / src.cols);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1718,10 +1716,15 @@ bool checkRange(InputArray _src, bool quiet, Point* pt, double minVal, double ma
|
||||
if( pt )
|
||||
*pt = badPt;
|
||||
if( !quiet )
|
||||
{
|
||||
cv::String value_str;
|
||||
value_str << src(cv::Range(badPt.y, badPt.y + 1), cv::Range(badPt.x, badPt.x + 1));
|
||||
CV_Error_( CV_StsOutOfRange,
|
||||
("the value at (%d, %d)=%g is out of range", badPt.x, badPt.y, badValue));
|
||||
("the value at (%d, %d)=%s is out of range [%f, %f)", badPt.x, badPt.y, value_str.c_str(), minVal, maxVal));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return badPt.x < 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
@ -2502,40 +2502,25 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
class Core_CheckRange_Empty : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
Core_CheckRange_Empty(){}
|
||||
~Core_CheckRange_Empty(){}
|
||||
protected:
|
||||
virtual void run( int start_from );
|
||||
};
|
||||
|
||||
void Core_CheckRange_Empty::run( int )
|
||||
TEST(Core_CheckRange_Empty, accuracy)
|
||||
{
|
||||
cv::Mat m;
|
||||
ASSERT_TRUE( cv::checkRange(m) );
|
||||
}
|
||||
|
||||
TEST(Core_CheckRange_Empty, accuracy) { Core_CheckRange_Empty test; test.safe_run(); }
|
||||
|
||||
class Core_CheckRange_INT_MAX : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
Core_CheckRange_INT_MAX(){}
|
||||
~Core_CheckRange_INT_MAX(){}
|
||||
protected:
|
||||
virtual void run( int start_from );
|
||||
};
|
||||
|
||||
void Core_CheckRange_INT_MAX::run( int )
|
||||
TEST(Core_CheckRange_INT_MAX, accuracy)
|
||||
{
|
||||
cv::Mat m(3, 3, CV_32SC1, cv::Scalar(INT_MAX));
|
||||
ASSERT_FALSE( cv::checkRange(m, true, 0, 0, INT_MAX) );
|
||||
ASSERT_TRUE( cv::checkRange(m) );
|
||||
}
|
||||
|
||||
TEST(Core_CheckRange_INT_MAX, accuracy) { Core_CheckRange_INT_MAX test; test.safe_run(); }
|
||||
TEST(Core_CheckRange_INT_MAX1, accuracy)
|
||||
{
|
||||
cv::Mat m(3, 3, CV_32SC1, cv::Scalar(INT_MAX));
|
||||
ASSERT_TRUE( cv::checkRange(m, true, 0, 0, INT_MAX+1.0f) );
|
||||
ASSERT_TRUE( cv::checkRange(m) );
|
||||
}
|
||||
|
||||
template <typename T> class Core_CheckRange : public testing::Test {};
|
||||
|
||||
@ -2546,13 +2531,30 @@ TYPED_TEST_P(Core_CheckRange, Negative)
|
||||
double min_bound = 4.5;
|
||||
double max_bound = 16.0;
|
||||
|
||||
TypeParam data[] = {5, 10, 15, 4, 10, 2, 8, 12, 14};
|
||||
TypeParam data[] = {5, 10, 15, 10, 10, 2, 8, 12, 14};
|
||||
cv::Mat src = cv::Mat(3,3, cv::DataDepth<TypeParam>::value, data);
|
||||
|
||||
cv::Point bad_pt(0, 0);
|
||||
|
||||
ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound));
|
||||
ASSERT_EQ(bad_pt.x, 0);
|
||||
ASSERT_EQ(bad_pt.x, 2);
|
||||
ASSERT_EQ(bad_pt.y, 1);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(Core_CheckRange, Negative3CN)
|
||||
{
|
||||
double min_bound = 4.5;
|
||||
double max_bound = 16.0;
|
||||
|
||||
TypeParam data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
|
||||
10, 11, 12, 10, 11, 12, 2, 5, 6,
|
||||
8, 8, 8, 12, 12, 12, 14, 14, 14};
|
||||
cv::Mat src = cv::Mat(3,3, CV_MAKETYPE(cv::DataDepth<TypeParam>::value, 3), data);
|
||||
|
||||
cv::Point bad_pt(0, 0);
|
||||
|
||||
ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound));
|
||||
ASSERT_EQ(bad_pt.x, 2);
|
||||
ASSERT_EQ(bad_pt.y, 1);
|
||||
}
|
||||
|
||||
@ -2614,7 +2616,49 @@ TYPED_TEST_P(Core_CheckRange, One)
|
||||
ASSERT_TRUE( checkRange(src2, true, NULL, min_bound, max_bound) );
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(Core_CheckRange, Negative, Positive, Bounds, Zero, One);
|
||||
TEST(Core_CheckRange, NaN)
|
||||
{
|
||||
float data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
|
||||
10, 11, 12, 10, 11, 12, 5, 5, std::numeric_limits<float>::quiet_NaN(),
|
||||
8, 8, 8, 12, 12, 12, 14, 14, 14};
|
||||
cv::Mat src = cv::Mat(3,3, CV_32FC3, data);
|
||||
|
||||
cv::Point bad_pt(0, 0);
|
||||
|
||||
ASSERT_FALSE(checkRange(src, true, &bad_pt));
|
||||
ASSERT_EQ(bad_pt.x, 2);
|
||||
ASSERT_EQ(bad_pt.y, 1);
|
||||
}
|
||||
|
||||
TEST(Core_CheckRange, Inf)
|
||||
{
|
||||
float data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
|
||||
10, 11, 12, 10, 11, 12, 5, 5, std::numeric_limits<float>::infinity(),
|
||||
8, 8, 8, 12, 12, 12, 14, 14, 14};
|
||||
cv::Mat src = cv::Mat(3,3, CV_32FC3, data);
|
||||
|
||||
cv::Point bad_pt(0, 0);
|
||||
|
||||
ASSERT_FALSE(checkRange(src, true, &bad_pt));
|
||||
ASSERT_EQ(bad_pt.x, 2);
|
||||
ASSERT_EQ(bad_pt.y, 1);
|
||||
}
|
||||
|
||||
TEST(Core_CheckRange, Inf_Minus)
|
||||
{
|
||||
float data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
|
||||
10, 11, 12, 10, 11, 12, 5, 5, -std::numeric_limits<float>::infinity(),
|
||||
8, 8, 8, 12, 12, 12, 14, 14, 14};
|
||||
cv::Mat src = cv::Mat(3,3, CV_32FC3, data);
|
||||
|
||||
cv::Point bad_pt(0, 0);
|
||||
|
||||
ASSERT_FALSE(checkRange(src, true, &bad_pt));
|
||||
ASSERT_EQ(bad_pt.x, 2);
|
||||
ASSERT_EQ(bad_pt.y, 1);
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(Core_CheckRange, Negative, Negative3CN, Positive, Bounds, Zero, One);
|
||||
|
||||
typedef ::testing::Types<signed char,unsigned char, signed short, unsigned short, signed int> mat_data_types;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(Negative_Test, Core_CheckRange, mat_data_types);
|
||||
|
@ -415,7 +415,7 @@ CV_INLINE int cvFloor( double value )
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @brief Rounds floating-point number to the nearest integer not larger than the original.
|
||||
/** @brief Rounds floating-point number to the nearest integer not smaller than the original.
|
||||
|
||||
The function computes an integer i such that:
|
||||
\f[i \le \texttt{value} < i+1\f]
|
||||
|
Loading…
Reference in New Issue
Block a user