fixed Bug #2074
authorIlya Lavrenov <ilya.lavrenov@itseez.com>
Mon, 8 Oct 2012 08:59:15 +0000 (12:59 +0400)
committerIlya Lavrenov <ilya.lavrenov@itseez.com>
Mon, 8 Oct 2012 08:59:15 +0000 (12:59 +0400)
modules/imgproc/src/color.cpp
modules/imgproc/test/test_color.cpp

index bc01127..2b7da03 100644 (file)
@@ -2168,11 +2168,11 @@ static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
 
     bayer += bstep*2;
 
-#if CV_SSE2
+#ifdef CV_SSE2
     bool haveSSE = cv::checkHardwareSupport(CV_CPU_SSE2);
     #define _mm_absdiff_epu16(a,b) _mm_adds_epu16(_mm_subs_epu16(a, b), _mm_subs_epu16(b, a))
 #endif
-
+    
     for( int y = 2; y < size.height - 4; y++ )
     {
         uchar* dstrow = dst + dststep*y + 6;
@@ -2188,7 +2188,7 @@ static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
 
             i = 1;
 
-#if CV_SSE2
+#ifdef CV_SSE2
             if( haveSSE )
             {
                 __m128i z = _mm_setzero_si128();
@@ -2263,7 +2263,7 @@ static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
         bool greenCell = greenCell0;
 
         i = 2;
-#if CV_SSE2
+#ifdef CV_SSE2
         int limit = !haveSSE ? N-2 : greenCell ? std::min(3, N-2) : 2;
 #else
         int limit = N - 2;
@@ -2431,12 +2431,13 @@ static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
                 greenCell = !greenCell;
             }
 
-#if CV_SSE2
+#ifdef CV_SSE2
             if( !haveSSE )
                 break;
 
             __m128i emask    = _mm_set1_epi32(0x0000ffff),
                     omask    = _mm_set1_epi32(0xffff0000),
+                    smask    = _mm_set1_epi16(0x7fff), // Get rid of sign bit in u16's
                     z        = _mm_setzero_si128();
             __m128 _0_5      = _mm_set1_ps(0.5f);
 
@@ -2658,6 +2659,11 @@ static void Bayer2RGB_VNG_8u( const Mat& srcmat, Mat& dstmat, int code )
                 x2 = _mm_merge_epi16(t0, x0);
 
                 uchar R[8], G[8], B[8];
+                
+                // Make sure there is no sign bit in the 16 bit values so they can saturate correctly
+                x1 = _mm_and_si128(x1, smask);
+                x2 = _mm_and_si128(x2, smask);
+                t1 = _mm_and_si128(t1, smask);
 
                 _mm_storel_epi64(blueIdx ? (__m128i*)B : (__m128i*)R, _mm_packus_epi16(x1, z));
                 _mm_storel_epi64((__m128i*)G, _mm_packus_epi16(x2, z));
@@ -3548,7 +3554,7 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
             if(dcn <= 0) dcn = 1;
             CV_Assert( scn == 1 && dcn == 1 );
 
-            _dst.create(sz, depth);
+            _dst.create(sz, CV_MAKETYPE(depth, dcn));
             dst = _dst.getMat();
 
             if( depth == CV_8U )
@@ -3561,26 +3567,29 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
 
         case CV_BayerBG2BGR: case CV_BayerGB2BGR: case CV_BayerRG2BGR: case CV_BayerGR2BGR:
         case CV_BayerBG2BGR_VNG: case CV_BayerGB2BGR_VNG: case CV_BayerRG2BGR_VNG: case CV_BayerGR2BGR_VNG:
-            if(dcn <= 0) dcn = 3;
-            CV_Assert( scn == 1 && dcn == 3 );
+            {
+                if (dcn <= 0) 
+                    dcn = 3;
+                CV_Assert( scn == 1 && dcn == 3 );
 
-            _dst.create(sz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
+                _dst.create(sz, CV_MAKE_TYPE(depth, dcn));
+                Mat dst_ = _dst.getMat();
 
-            if( code == CV_BayerBG2BGR || code == CV_BayerGB2BGR ||
-                code == CV_BayerRG2BGR || code == CV_BayerGR2BGR )
-            {
-                if( depth == CV_8U )
-                    Bayer2RGB_<uchar, SIMDBayerInterpolator_8u>(src, dst, code);
-                else if( depth == CV_16U )
-                    Bayer2RGB_<ushort, SIMDBayerStubInterpolator_<ushort> >(src, dst, code);
+                if( code == CV_BayerBG2BGR || code == CV_BayerGB2BGR ||
+                    code == CV_BayerRG2BGR || code == CV_BayerGR2BGR )
+                {
+                    if( depth == CV_8U )
+                        Bayer2RGB_<uchar, SIMDBayerInterpolator_8u>(src, dst_, code);
+                    else if( depth == CV_16U )
+                        Bayer2RGB_<ushort, SIMDBayerStubInterpolator_<ushort> >(src, dst_, code);
+                    else
+                        CV_Error(CV_StsUnsupportedFormat, "Bayer->RGB demosaicing only supports 8u and 16u types");
+                }
                 else
-                    CV_Error(CV_StsUnsupportedFormat, "Bayer->RGB demosaicing only supports 8u and 16u types");
-            }
-            else
-            {
-                CV_Assert( depth == CV_8U );
-                Bayer2RGB_VNG_8u(src, dst, code);
+                {
+                    CV_Assert( depth == CV_8U );
+                    Bayer2RGB_VNG_8u(src, dst_, code);
+                }
             }
             break;
         case CV_YUV2BGR_NV21:  case CV_YUV2RGB_NV21:  case CV_YUV2BGR_NV12:  case CV_YUV2RGB_NV12:
index 1422f4c..9ad6cfa 100644 (file)
@@ -1700,8 +1700,10 @@ TEST(Imgproc_ColorBayerVNG, regression)
     Mat gold = imread(string(ts.get_data_path()) + "/cvtcolor/bayerVNG_gold.png", CV_LOAD_IMAGE_UNCHANGED);
     Mat result;
 
+    CV_Assert(given.data != NULL);
+    
     cvtColor(given, result, CV_BayerBG2BGR_VNG, 3);
-
+    
     EXPECT_EQ(gold.type(), result.type());
     EXPECT_EQ(gold.cols, result.cols);
     EXPECT_EQ(gold.rows, result.rows);
@@ -1711,3 +1713,128 @@ TEST(Imgproc_ColorBayerVNG, regression)
 
     EXPECT_EQ(0, countNonZero(diff.reshape(1) > 1));
 }
+
+TEST(Imgproc_ColorBayerVNG_Strict, regression)
+{
+    cvtest::TS& ts = *cvtest::TS::ptr();
+    const char pattern[][3] = { "bg", "gb", "rg", "gr" };
+    const std::string image_name = "lena.png";
+    const std::string parent_path = string(ts.get_data_path()) + "./cvtcolor_strict/";
+
+    Mat src, dst, bayer, reference;
+    std::string full_path = parent_path + image_name;
+    src = imread(full_path, CV_LOAD_IMAGE_UNCHANGED);
+    Size ssize = src.size();
+
+    if (src.data == NULL)
+    {
+        ts.set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
+        ts.printf(cvtest::TS::SUMMARY, "No input image\n");
+        return;
+    }
+    
+    int type = -1;
+    for (int i = 0; i < 4; ++i)
+    {
+        // creating Bayer pattern
+        bayer.create(ssize, CV_MAKETYPE(src.depth(), 1));
+
+        if (!strcmp(pattern[i], "bg"))
+        {
+            for (int y = 0; y < ssize.height; ++y)
+                for (int x = 0; x < ssize.width; ++x)
+                {
+                    if ((x + y) % 2)
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[1];
+                    else if (x % 2)
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[0];
+                    else
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[2];
+                }
+            type = CV_BayerBG2BGR_VNG;
+        }
+        else if (!strcmp(pattern[i], "gb"))
+        {
+            for (int y = 0; y < ssize.height; ++y)
+                for (int x = 0; x < ssize.width; ++x)
+                {
+                    if ((x + y) % 2 == 0)
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[1];
+                    else if (x % 2 == 0)
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[0];
+                    else
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[2];
+                }
+            type = CV_BayerGB2BGR_VNG;
+        }
+        else if (!strcmp(pattern[i], "rg"))
+        {
+            for (int y = 0; y < ssize.height; ++y)
+                for (int x = 0; x < ssize.width; ++x)
+                {
+                    if ((x + y) % 2)
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[1];
+                    else if (x % 2 == 0)
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[0];
+                    else
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[2];
+                }
+            type = CV_BayerRG2BGR_VNG;
+        }
+        else
+        {
+            for (int y = 0; y < ssize.height; ++y)
+                for (int x = 0; x < ssize.width; ++x)
+                {
+                    if ((x + y) % 2 == 0)
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[1];
+                    else if (x % 2)
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[0];
+                    else
+                        bayer.at<uchar>(y, x) = src.at<Vec3b>(y, x)[2];
+                }
+            type = CV_BayerGR2BGR_VNG;
+        }
+
+        // calculating a dst image
+        cvtColor(bayer, dst, type);
+        
+        // reading a reference image
+        full_path = parent_path + pattern[i] + image_name;
+        reference = imread(full_path, CV_LOAD_IMAGE_UNCHANGED);
+        if (reference.data == NULL)
+        {
+            imwrite(full_path, dst);
+            continue;
+        }
+        
+        if (reference.depth() != dst.depth() || reference.channels() != dst.channels() ||
+            reference.size() != dst.size())
+        {
+            ts.set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+            ts.printf(cvtest::TS::SUMMARY, "\nReference channels: %d\n"
+                "Actual channels: %d\n", reference.channels(), dst.channels());
+            ts.printf(cvtest::TS::SUMMARY, "\nReference depth: %d\n"
+                "Actual depth: %d\n", reference.depth(), dst.depth());
+            ts.printf(cvtest::TS::SUMMARY, "\nReference rows: %d\n"
+                "Actual rows: %d\n", reference.rows, dst.rows);
+            ts.printf(cvtest::TS::SUMMARY, "\nReference cols: %d\n"
+                "Actual cols: %d\n", reference.cols, dst.cols);
+            ts.set_gtest_status();
+            
+            return;
+        }
+        
+        Mat diff;
+        absdiff(reference, dst, diff);
+        
+        int nonZero = countNonZero(diff.reshape(1) > 1);
+        if (nonZero != 0)
+        {
+            ts.set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+            ts.printf(cvtest::TS::SUMMARY, "\nCount non zero in absdiff: %d\n", nonZero);
+            ts.set_gtest_status();
+            return;
+        }
+    }
+}