fixed bug for #1496 and correctness tests for function CheckRange
authorMarina Kolpakova <no@email>
Wed, 28 Mar 2012 20:09:13 +0000 (20:09 +0000)
committerMarina Kolpakova <no@email>
Wed, 28 Mar 2012 20:09:13 +0000 (20:09 +0000)
modules/core/src/mathfuncs.cpp
modules/core/test/test_math.cpp

index 3f8308d..74c8364 100644 (file)
@@ -1996,19 +1996,98 @@ void sqrt(InputArray a, OutputArray b)
 
 /************************** CheckArray for NaN's, Inf's *********************************/
 
-bool checkRange(InputArray _src, bool quiet, Point* pt,
-                double minVal, double maxVal)
+template<int cv_mat_type> struct mat_type_assotiations{};
+
+template<> struct mat_type_assotiations<CV_8U>
+{
+    typedef unsigned char type;
+    static const type min_allowable = 0x0;
+    static const type max_allowable = 0xFF;
+};
+
+template<> struct mat_type_assotiations<CV_8S>
+{
+    typedef signed char type;
+    static const type min_allowable = SCHAR_MIN;
+    static const type max_allowable = SCHAR_MAX;
+};
+
+template<> struct mat_type_assotiations<CV_16U>
+{
+    typedef unsigned short type;
+    static const type min_allowable = 0x0;
+    static const type max_allowable = USHRT_MAX;
+};
+template<> struct mat_type_assotiations<CV_16S>
+{
+    typedef signed short type;
+    static const type min_allowable = SHRT_MIN;
+    static const type max_allowable = SHRT_MAX;
+};
+
+template<> struct mat_type_assotiations<CV_32S>
+{
+    typedef int type;
+    static const type min_allowable = (-INT_MAX - 1);
+    static const type max_allowable = INT_MAX;
+};
+
+template<int depth>
+bool chackIntegerRang(cv::Mat src, Point& bad_pt, int minVal, int maxVal, double& bad_value)
+{
+    typedef mat_type_assotiations<depth> type_ass; 
+    
+    if (minVal < type_ass::min_allowable && maxVal > type_ass::max_allowable)
+    {
+        return true;
+    }
+    else if (minVal >= type_ass::max_allowable || maxVal <= type_ass::min_allowable || maxVal <= minVal)
+    {
+        bad_pt = cv::Point(0,0);
+        return false;
+    }
+    cv::Mat as_one_channel = src.reshape(1,0);
+
+    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)
+            {            
+                bad_pt.y = j ; 
+                bad_pt.x = i % src.channels();
+                bad_value = as_one_channel.at<typename type_ass::type>(j ,i);
+                return false;
+            }
+        }
+    bad_value = 0.0;
+    
+    return true;
+}
+
+typedef bool (*check_pange_function)(cv::Mat src, Point& bad_pt, int minVal, int maxVal, double& bad_value); 
+
+check_pange_function check_range_functions[] = 
+{
+    &chackIntegerRang<CV_8U>,
+    &chackIntegerRang<CV_8S>,
+    &chackIntegerRang<CV_16U>,
+    &chackIntegerRang<CV_16S>,
+    &chackIntegerRang<CV_32S>
+};
+
+bool checkRange(InputArray _src, bool quiet, Point* pt, double minVal, double maxVal)
 {
     Mat src = _src.getMat();
-    if( src.dims > 2 )
+
+    if ( src.dims > 2 )
     {
         const Mat* arrays[] = {&src, 0};
         Mat planes[1];
         NAryMatIterator it(arrays, planes);
         
-        for( size_t i = 0; i < it.nplanes; i++, ++it )
+        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, pt, minVal, maxVal ))
             {
                 // todo: set index properly
                 return false;
@@ -2021,21 +2100,12 @@ bool checkRange(InputArray _src, bool quiet, Point* pt,
     Point badPt(-1, -1);
     double badValue = 0;
 
-    if( depth < CV_32F )
+    if (depth < CV_32F)
     {
-        double m = 0, M = 0;
-        Point mp, MP;
-        minMaxLoc(src.reshape(1,0), &m, &M, &mp, &MP);
-        if( M >= maxVal )
-        {
-            badPt = MP;
-            badValue = M;
-        }
-        else if( m < minVal )
-        {
-            badPt = mp;
-            badValue = m;
-        }
+        int minVali = cvFloor(minVal);
+        int maxVali = cvCeil(maxVal);
+
+        (check_range_functions[depth])(src, badPt, minVali, maxVali, badValue);
     }
     else
     {
index b7e36b1..af9c85d 100644 (file)
@@ -2347,6 +2347,93 @@ void Core_SolvePolyTest::run( int )
     }
 }
 
+template <typename T> class Core_CheckRange : public testing::Test {};
+
+template<typename type> struct depth_for_type{};
+
+template<> struct depth_for_type<unsigned char>
+{
+    static const int depth = CV_8U;
+};
+
+template<> struct depth_for_type<signed char>
+{
+    static const int depth = CV_8S;
+};
+
+template<> struct depth_for_type<unsigned short>
+{
+    static const int depth = CV_16U;
+};
+
+template<> struct depth_for_type<signed short>
+{
+    static const int depth = CV_16S;
+};
+
+template<> struct depth_for_type<signed int>
+{
+    static const int depth = CV_32S;
+};
+
+
+TYPED_TEST_CASE_P(Core_CheckRange);
+
+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};
+    cv::Mat src = cv::Mat(3,3, depth_for_type<TypeParam>::depth, data);
+
+    cv::Point* bad_pt = new cv::Point(0, 0);  
+
+    ASSERT_FALSE(checkRange(src, true, bad_pt, min_bound, max_bound));
+    ASSERT_EQ(bad_pt->x,0);
+    ASSERT_EQ(bad_pt->y,1);
+
+    delete bad_pt;
+}
+
+TYPED_TEST_P(Core_CheckRange, Positive)
+{
+    double min_bound = -1;
+    double max_bound = 16.0;
+
+    TypeParam data[] = {5, 10, 15, 4, 10 ,2, 8, 12, 14};
+    cv::Mat src = cv::Mat(3,3, depth_for_type<TypeParam>::depth, data);
+
+    cv::Point* bad_pt = new cv::Point(0, 0);  
+
+    ASSERT_TRUE(checkRange(src, true, bad_pt, min_bound, max_bound));
+    ASSERT_EQ(bad_pt->x,0);
+    ASSERT_EQ(bad_pt->y,0);
+
+    delete bad_pt;
+}
+
+TYPED_TEST_P(Core_CheckRange, Bounds)
+{
+    double min_bound = 24.5;
+    double max_bound = 1.0;
+
+    TypeParam data[] = {5, 10, 15, 4, 10 ,2, 8, 12, 14};
+    cv::Mat src = cv::Mat(3,3, depth_for_type<TypeParam>::depth, data);
+
+    cv::Point* bad_pt = new cv::Point(0, 0);    
+
+    ASSERT_FALSE(checkRange(src, true, bad_pt, min_bound, max_bound));
+    ASSERT_EQ(bad_pt->x,0);
+    ASSERT_EQ(bad_pt->y,0);
+
+    delete bad_pt;
+}
+
+REGISTER_TYPED_TEST_CASE_P(Core_CheckRange, Negative, Positive, Bounds);
+
+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);
 
 /////////////////////////////////////////////////////////////////////////////////////////////////////