GPU resize with INTER_AREA
authorMarina Kolpakova <no@email>
Wed, 6 Jun 2012 10:39:42 +0000 (10:39 +0000)
committerMarina Kolpakova <no@email>
Wed, 6 Jun 2012 10:39:42 +0000 (10:39 +0000)
modules/gpu/src/cuda/resize.cu
modules/gpu/src/opencv2/gpu/device/filters.hpp
modules/gpu/src/opencv2/gpu/device/vec_traits.hpp
modules/gpu/src/resize.cpp
modules/gpu/test/test_resize.cpp
modules/gpu/test/utility.hpp
modules/imgproc/src/imgwarp.cpp
modules/imgproc/test/test_imgwarp.cpp

index 732b0f7..813bced 100644 (file)
@@ -46,6 +46,7 @@
 #include "opencv2/gpu/device/vec_math.hpp"\r
 #include "opencv2/gpu/device/saturate_cast.hpp"\r
 #include "opencv2/gpu/device/filters.hpp"\r
+# include <cfloat>\r
 \r
 namespace cv { namespace gpu { namespace device\r
 {\r
@@ -65,6 +66,17 @@ namespace cv { namespace gpu { namespace device
             }\r
         }\r
 \r
+        template <typename Ptr2D, typename T> __global__ void resize_area(const Ptr2D src, float fx, float fy, DevMem2D_<T> dst)\r
+        {\r
+            const int x = blockDim.x * blockIdx.x + threadIdx.x;\r
+            const int y = blockDim.y * blockIdx.y + threadIdx.y;\r
+\r
+            if (x < dst.cols && y < dst.rows)\r
+            {\r
+                dst(y, x) = saturate_cast<T>(src(y, x));\r
+            }\r
+        }\r
+\r
         template <template <typename> class Filter, typename T> struct ResizeDispatcherStream\r
         {\r
             static void call(DevMem2D_<T> src, float fx, float fy, DevMem2D_<T> dst, cudaStream_t stream)\r
@@ -74,13 +86,43 @@ namespace cv { namespace gpu { namespace device
 \r
                 BrdReplicate<T> brd(src.rows, src.cols);\r
                 BorderReader< PtrStep<T>, BrdReplicate<T> > brdSrc(src, brd);\r
-                Filter< BorderReader< PtrStep<T>, BrdReplicate<T> > > filteredSrc(brdSrc);\r
+                Filter< BorderReader< PtrStep<T>, BrdReplicate<T> > > filteredSrc(brdSrc, fx, fy);\r
 \r
                 resize<<<grid, block, 0, stream>>>(filteredSrc, fx, fy, dst);\r
                 cudaSafeCall( cudaGetLastError() );\r
             }\r
         };\r
 \r
+        template <typename T> struct ResizeDispatcherStream<AreaFilter, T>\r
+        {\r
+            static void call(DevMem2D_<T> src, float fx, float fy, DevMem2D_<T> dst, cudaStream_t stream)\r
+            {\r
+                dim3 block(32, 8);\r
+                dim3 grid(divUp(dst.cols, block.x), divUp(dst.rows, block.y));\r
+\r
+                BrdConstant<T> brd(src.rows, src.cols);\r
+                BorderReader< PtrStep<T>, BrdConstant<T> > brdSrc(src, brd);\r
+                AreaFilter< BorderReader< PtrStep<T>, BrdConstant<T> > > filteredSrc(brdSrc, fx, fy);\r
+                resize_area<<<grid, block, 0, stream>>>(filteredSrc, fx, fy, dst);\r
+                cudaSafeCall( cudaGetLastError() );\r
+            }\r
+        };\r
+\r
+        template <typename T> struct ResizeDispatcherStream<IntegerAreaFilter, T>\r
+        {\r
+            static void call(DevMem2D_<T> src, float fx, float fy, DevMem2D_<T> dst, cudaStream_t stream)\r
+            {\r
+                dim3 block(32, 8);\r
+                dim3 grid(divUp(dst.cols, block.x), divUp(dst.rows, block.y));\r
+\r
+                BrdConstant<T> brd(src.rows, src.cols);\r
+                BorderReader< PtrStep<T>, BrdConstant<T> > brdSrc(src, brd);\r
+                IntegerAreaFilter< BorderReader< PtrStep<T>, BrdConstant<T> > > filteredSrc(brdSrc, fx, fy);\r
+                resize_area<<<grid, block, 0, stream>>>(filteredSrc, fx, fy, dst);\r
+                cudaSafeCall( cudaGetLastError() );\r
+            }\r
+        };\r
+\r
         template <template <typename> class Filter, typename T> struct ResizeDispatcherNonStream\r
         {\r
             static void call(DevMem2D_<T> src, DevMem2D_<T> srcWhole, int xoff, int yoff, float fx, float fy, DevMem2D_<T> dst)\r
@@ -169,14 +211,31 @@ namespace cv { namespace gpu { namespace device
             }\r
         };\r
 \r
+        template <typename T> struct ResizeDispatcher<AreaFilter, T>\r
+        {\r
+            static void call(DevMem2D_<T> src, DevMem2D_<T> srcWhole, int xoff, int yoff, float fx, float fy, DevMem2D_<T> dst, cudaStream_t stream)\r
+            {\r
+                int iscale_x = round(fx);\r
+                int iscale_y = round(fy);\r
+\r
+                if( std::abs(fx - iscale_x) < FLT_MIN && std::abs(fy - iscale_y) < FLT_MIN)\r
+                    ResizeDispatcherStream<IntegerAreaFilter, T>::call(src, fx, fy, dst, stream);\r
+                else\r
+                    ResizeDispatcherStream<AreaFilter, T>::call(src, fx, fy, dst, stream);\r
+            }\r
+        };\r
+\r
         template <typename T> void resize_gpu(DevMem2Db src, DevMem2Db srcWhole, int xoff, int yoff, float fx, float fy, \r
             DevMem2Db dst, int interpolation, cudaStream_t stream)\r
         {\r
             typedef void (*caller_t)(DevMem2D_<T> src, DevMem2D_<T> srcWhole, int xoff, int yoff, float fx, float fy, DevMem2D_<T> dst, cudaStream_t stream);\r
 \r
-            static const caller_t callers[3] = \r
+            static const caller_t callers[4] =\r
             {\r
-                ResizeDispatcher<PointFilter, T>::call, ResizeDispatcher<LinearFilter, T>::call, ResizeDispatcher<CubicFilter, T>::call\r
+                ResizeDispatcher<PointFilter, T>::call,\r
+                ResizeDispatcher<LinearFilter, T>::call,\r
+                ResizeDispatcher<CubicFilter, T>::call,\r
+                ResizeDispatcher<AreaFilter, T>::call\r
             };\r
 \r
             callers[interpolation](static_cast< DevMem2D_<T> >(src), static_cast< DevMem2D_<T> >(srcWhole), xoff, yoff, fx, fy, \r
index 537d6af..9294b55 100644 (file)
@@ -55,7 +55,7 @@ namespace cv { namespace gpu { namespace device
         typedef typename Ptr2D::elem_type elem_type;\r
         typedef float index_type;\r
 \r
-        explicit __host__ __device__ __forceinline__ PointFilter(const Ptr2D& src_) : src(src_) {}\r
+        explicit __host__ __device__ __forceinline__ PointFilter(const Ptr2D& src_, float fx = 0.f, float fy = 0.f) : src(src_) {}\r
 \r
         __device__ __forceinline__ elem_type operator ()(float y, float x) const\r
         {\r
@@ -70,7 +70,7 @@ namespace cv { namespace gpu { namespace device
         typedef typename Ptr2D::elem_type elem_type;\r
         typedef float index_type;\r
 \r
-        explicit __host__ __device__ __forceinline__ LinearFilter(const Ptr2D& src_) : src(src_) {}\r
+        explicit __host__ __device__ __forceinline__ LinearFilter(const Ptr2D& src_, float fx = 0.f, float fy = 0.f) : src(src_) {}\r
 \r
         __device__ __forceinline__ elem_type operator ()(float y, float x) const\r
         {\r
@@ -107,7 +107,7 @@ namespace cv { namespace gpu { namespace device
         typedef float index_type;\r
         typedef typename TypeVec<float, VecTraits<elem_type>::cn>::vec_type work_type;\r
 \r
-        explicit __host__ __device__ __forceinline__ CubicFilter(const Ptr2D& src_) : src(src_) {}\r
+        explicit __host__ __device__ __forceinline__ CubicFilter(const Ptr2D& src_, float fx = 0.f, float fy = 0.f) : src(src_) {}\r
 \r
         static __device__ __forceinline__ float bicubicCoeff(float x_)\r
         {\r
@@ -154,6 +154,111 @@ namespace cv { namespace gpu { namespace device
 \r
         const Ptr2D src;\r
     };\r
+    // for integer scaling\r
+    template <typename Ptr2D> struct IntegerAreaFilter\r
+    {\r
+        typedef typename Ptr2D::elem_type elem_type;\r
+        typedef float index_type;\r
+\r
+        explicit __host__ __device__ __forceinline__ IntegerAreaFilter(const Ptr2D& src_, float scale_x_, float scale_y_)\r
+            : src(src_), scale_x(scale_x_), scale_y(scale_y_), scale(1.f / (scale_x * scale_y)) {}\r
+\r
+        __device__ __forceinline__ elem_type operator ()(float y, float x) const\r
+        {\r
+            float fsx1 = x * scale_x;\r
+            float fsx2 = fsx1 + scale_x;\r
+\r
+            int sx1 = __float2int_ru(fsx1);\r
+            int sx2 = __float2int_rd(fsx2);\r
+\r
+            float fsy1 = y * scale_y;\r
+            float fsy2 = fsy1 + scale_y;\r
+\r
+            int sy1 = __float2int_ru(fsy1);\r
+            int sy2 = __float2int_rd(fsy2);\r
+\r
+            typedef typename TypeVec<float, VecTraits<elem_type>::cn>::vec_type work_type;\r
+            work_type out = VecTraits<work_type>::all(0.f);\r
+\r
+            for(int dy = sy1; dy < sy2; ++dy)\r
+                for(int dx = sx1; dx < sx2; ++dx)\r
+                {\r
+                    out = out + src(dy, dx) * scale;\r
+                }\r
+\r
+            return saturate_cast<elem_type>(out);\r
+        }\r
+\r
+        const Ptr2D src;\r
+        float scale_x, scale_y ,scale;\r
+    };\r
+\r
+    template <typename Ptr2D> struct AreaFilter\r
+    {\r
+        typedef typename Ptr2D::elem_type elem_type;\r
+        typedef float index_type;\r
+\r
+        explicit __host__ __device__ __forceinline__ AreaFilter(const Ptr2D& src_, float scale_x_, float scale_y_)\r
+            : src(src_), scale_x(scale_x_), scale_y(scale_y_){}\r
+\r
+        __device__ __forceinline__ elem_type operator ()(float y, float x) const\r
+        {\r
+            float fsx1 = x * scale_x;\r
+            float fsx2 = fsx1 + scale_x;\r
+\r
+            int sx1 = __float2int_ru(fsx1);\r
+            int sx2 = __float2int_rd(fsx2);\r
+\r
+            float fsy1 = y * scale_y;\r
+            float fsy2 = fsy1 + scale_y;\r
+\r
+            int sy1 = __float2int_ru(fsy1);\r
+            int sy2 = __float2int_rd(fsy2);\r
+\r
+            float scale = 1.f / (fminf(scale_x, src.width - fsx1) * fminf(scale_y, src.height - fsy1));\r
+\r
+            typedef typename TypeVec<float, VecTraits<elem_type>::cn>::vec_type work_type;\r
+            work_type out = VecTraits<work_type>::all(0.f);\r
+\r
+            for (int dy = sy1; dy < sy2; ++dy)\r
+            {\r
+                for (int dx = sx1; dx < sx2; ++dx)\r
+                    out = out + src(dy, dx) * scale;\r
+\r
+                if (sx1 > fsx1)\r
+                    out = out + src(dy, (sx1 -1) ) * ((sx1 - fsx1) * scale);\r
+\r
+                if (sx2 < fsx2)\r
+                    out = out + src(dy, sx2) * ((fsx2 -sx2) * scale);\r
+            }\r
+\r
+            if (sy1 > fsy1)\r
+                for (int dx = sx1; dx < sx2; ++dx)\r
+                    out = out + src( (sy1 - 1) , dx) * ((sy1 -fsy1) * scale);\r
+\r
+            if (sy2 < fsy2)\r
+                for (int dx = sx1; dx < sx2; ++dx)\r
+                    out = out + src(sy2, dx) * ((fsy2 -sy2) * scale);\r
+\r
+            if ((sy1 > fsy1) &&  (sx1 > fsx1))\r
+                out = out + src( (sy1 - 1) , (sx1 - 1)) * ((sy1 -fsy1) * (sx1 -fsx1) * scale);\r
+\r
+            if ((sy1 > fsy1) &&  (sx2 < fsx2))\r
+                out = out + src( (sy1 - 1) , sx2) * ((sy1 -fsy1) * (fsx2 -sx2) * scale);\r
+\r
+            if ((sy2 < fsy2) &&  (sx2 < fsx2))\r
+                out = out + src(sy2, sx2) * ((fsy2 -sy2) * (fsx2 -sx2) * scale);\r
+\r
+            if ((sy2 < fsy2) &&  (sx1 > fsx1))\r
+                out = out + src(sy2, (sx1 - 1)) * ((fsy2 -sy2) * (sx1 -fsx1) * scale);\r
+\r
+            return saturate_cast<elem_type>(out);\r
+        }\r
+\r
+        const Ptr2D src;\r
+        float scale_x, scale_y;\r
+        int width, haight;\r
+    };\r
 }}} // namespace cv { namespace gpu { namespace device\r
 \r
 #endif // __OPENCV_GPU_FILTERS_HPP__\r
index 7ead7cb..955fe0d 100644 (file)
@@ -221,7 +221,7 @@ namespace cv { namespace gpu { namespace device
 \r
     template<> struct VecTraits<char> \r
     { \r
-        typedef char elem_type; \r
+        typedef char elem_type;\r
         enum {cn=1}; \r
         static __device__ __host__ __forceinline__ char all(char v) {return v;}\r
         static __device__ __host__ __forceinline__ char make(char x) {return x;}\r
@@ -229,7 +229,7 @@ namespace cv { namespace gpu { namespace device
     };\r
     template<> struct VecTraits<schar> \r
     { \r
-        typedef schar elem_type; \r
+        typedef schar elem_type;\r
         enum {cn=1}; \r
         static __device__ __host__ __forceinline__ schar all(schar v) {return v;}\r
         static __device__ __host__ __forceinline__ schar make(schar x) {return x;}\r
index ef28892..cba53c2 100644 (file)
@@ -61,7 +61,8 @@ namespace cv { namespace gpu { namespace device
 void cv::gpu::resize(const GpuMat& src, GpuMat& dst, Size dsize, double fx, double fy, int interpolation, Stream& s)\r
 {\r
     CV_Assert(src.depth() <= CV_32F && src.channels() <= 4);\r
-    CV_Assert(interpolation == INTER_NEAREST || interpolation == INTER_LINEAR || interpolation == INTER_CUBIC);\r
+    CV_Assert(interpolation == INTER_NEAREST || interpolation == INTER_LINEAR\r
+            || interpolation == INTER_CUBIC || interpolation == INTER_AREA);\r
     CV_Assert(!(dsize == Size()) || (fx > 0 && fy > 0));\r
 \r
     if (dsize == Size())\r
index b4c9ddc..2204833 100644 (file)
@@ -48,7 +48,8 @@
 \r
 namespace\r
 {\r
-    template <typename T, template <typename> class Interpolator> void resizeImpl(const cv::Mat& src, cv::Mat& dst, double fx, double fy)\r
+    template <typename T, template <typename> class Interpolator>\r
+    void resizeImpl(const cv::Mat& src, cv::Mat& dst, double fx, double fy)\r
     {\r
         const int cn = src.channels();\r
 \r
@@ -156,6 +157,51 @@ INSTANTIATE_TEST_CASE_P(GPU_ImgProc, Resize, testing::Combine(
     testing::Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)),\r
     WHOLE_SUBMAT));\r
 \r
+\r
+/////////////////\r
+PARAM_TEST_CASE(ResizeArea, cv::gpu::DeviceInfo, cv::Size, MatType, double, Interpolation, UseRoi)\r
+{\r
+    cv::gpu::DeviceInfo devInfo;\r
+    cv::Size size;\r
+    double coeff;\r
+    int interpolation;\r
+    int type;\r
+    bool useRoi;\r
+\r
+    virtual void SetUp()\r
+    {\r
+        devInfo = GET_PARAM(0);\r
+        size = GET_PARAM(1);\r
+        type = GET_PARAM(2);\r
+        coeff = GET_PARAM(3);\r
+        interpolation = GET_PARAM(4);\r
+        useRoi = GET_PARAM(5);\r
+\r
+        cv::gpu::setDevice(devInfo.deviceID());\r
+    }\r
+};\r
+\r
+TEST_P(ResizeArea, Accuracy)\r
+{\r
+    cv::Mat src = randomMat(size, type);\r
+\r
+    cv::gpu::GpuMat dst = createMat(cv::Size(cv::saturate_cast<int>(src.cols * coeff), cv::saturate_cast<int>(src.rows * coeff)), type, useRoi);\r
+    cv::gpu::resize(loadMat(src, useRoi), dst, cv::Size(), coeff, coeff, interpolation);\r
+\r
+    cv::Mat dst_cpu;\r
+    cv::resize(src, dst_cpu, cv::Size(), coeff, coeff, interpolation);\r
+\r
+    EXPECT_MAT_NEAR(dst_cpu, dst, src.depth() == CV_32F ? 1e-2 : 1.0);\r
+}\r
+\r
+INSTANTIATE_TEST_CASE_P(GPU_ImgProc, ResizeArea, testing::Combine(\r
+    ALL_DEVICES,\r
+    DIFFERENT_SIZES,\r
+    testing::Values(MatType(CV_8UC3), MatType(CV_16UC1), MatType(CV_16UC3), MatType(CV_16UC4), MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)),\r
+    testing::Values(/*0.3,*/0.5),\r
+    testing::Values(Interpolation(cv::INTER_AREA)),\r
+    WHOLE_SUBMAT));\r
+\r
 ///////////////////////////////////////////////////////////////////\r
 // Test NPP\r
 \r
index f1a83fb..3ad02de 100644 (file)
@@ -277,7 +277,7 @@ IMPLEMENT_PARAM_CLASS(Channels, int)
 \r
 CV_ENUM(NormCode, cv::NORM_INF, cv::NORM_L1, cv::NORM_L2, cv::NORM_TYPE_MASK, cv::NORM_RELATIVE, cv::NORM_MINMAX)\r
 \r
-CV_ENUM(Interpolation, cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_CUBIC)\r
+CV_ENUM(Interpolation, cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_CUBIC, cv::INTER_AREA)\r
 \r
 CV_ENUM(BorderType, cv::BORDER_REFLECT101, cv::BORDER_REPLICATE, cv::BORDER_CONSTANT, cv::BORDER_REFLECT, cv::BORDER_WRAP)\r
 #define ALL_BORDER_TYPES testing::Values(BorderType(cv::BORDER_REFLECT101), BorderType(cv::BORDER_REPLICATE), BorderType(cv::BORDER_CONSTANT), BorderType(cv::BORDER_REFLECT), BorderType(cv::BORDER_WRAP))\r
index 88d1196..0102e6b 100644 (file)
@@ -878,8 +878,8 @@ struct VResizeLinear
         VecOp vecOp;
 
         int x = vecOp((const uchar**)src, (uchar*)dst, (const uchar*)beta, width);
-           #if CV_ENABLE_UNROLLED
-               for( ; x <= width - 4; x += 4 )
+        #if CV_ENABLE_UNROLLED
+        for( ; x <= width - 4; x += 4 )
         {
             WT t0, t1;
             t0 = S0[x]*b0 + S1[x]*b1;
@@ -1035,7 +1035,7 @@ struct VResizeLanczos4
         CastOp castOp;
         VecOp vecOp;
         int k, x = vecOp((const uchar**)src, (uchar*)dst, (const uchar*)beta, width);
-               #if CV_ENABLE_UNROLLED
+        #if CV_ENABLE_UNROLLED
         for( ; x <= width - 4; x += 4 )
         {
             WT b = beta[0];
@@ -1130,7 +1130,7 @@ static void resizeGeneric_( const Mat& src, Mat& dst,
         if( k0 < ksize )
             hresize( srows + k0, rows + k0, ksize - k0, xofs, alpha,
                      ssize.width, dsize.width, cn, xmin, xmax );
-               vresize( (const WT**)rows, (T*)(dst.data + dst.step*dy), beta, dsize.width );
+        vresize( (const WT**)rows, (T*)(dst.data + dst.step*dy), beta, dsize.width );
     }
 }
 
@@ -1163,8 +1163,8 @@ static void resizeAreaFast_( const Mat& src, Mat& dst, const int* ofs, const int
         {
             const T* S = (const T*)(src.data + src.step*sy0) + xofs[dx];
             WT sum = 0;
-                       k=0;
-                       #if CV_ENABLE_UNROLLED
+            k=0;
+            #if CV_ENABLE_UNROLLED
             for( ; k <= area - 4; k += 4 )
                 sum += S[ofs[k]] + S[ofs[k+1]] + S[ofs[k+2]] + S[ofs[k+3]];
             #endif
@@ -1329,11 +1329,11 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
         resizeGeneric_<
             HResizeLinear<uchar, int, short,
                 INTER_RESIZE_COEF_SCALE,
-                               HResizeLinearVec_8u32s>,
+                HResizeLinearVec_8u32s>,
             VResizeLinear<uchar, int, short,
                 FixedPtCast<int, uchar, INTER_RESIZE_COEF_BITS*2>,
-                               VResizeLinearVec_32s8u> >,
-               0,
+                VResizeLinearVec_32s8u> >,
+        0,
         resizeGeneric_<
             HResizeLinear<ushort, float, float, 1,
                 HResizeLinearVec_16u32f>,
@@ -1344,7 +1344,7 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
                 HResizeLinearVec_16s32f>,
             VResizeLinear<short, float, float, Cast<float, short>,
                 VResizeLinearVec_32f16s> >,
-               0,
+        0,
         resizeGeneric_<
             HResizeLinear<float, float, float, 1,
                 HResizeLinearVec_32f>,
@@ -1374,7 +1374,7 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
             HResizeCubic<short, float, float>,
             VResizeCubic<short, float, float, Cast<float, short>,
             VResizeCubicVec_32f16s> >,
-               0,
+        0,
         resizeGeneric_<
             HResizeCubic<float, float, float>,
             VResizeCubic<float, float, float, Cast<float, float>,
@@ -1396,10 +1396,10 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
         resizeGeneric_<HResizeLanczos4<ushort, float, float>,
             VResizeLanczos4<ushort, float, float, Cast<float, ushort>,
             VResizeNoVec> >,
-               resizeGeneric_<HResizeLanczos4<short, float, float>,
+        resizeGeneric_<HResizeLanczos4<short, float, float>,
             VResizeLanczos4<short, float, float, Cast<float, short>,
             VResizeNoVec> >,
-               0,
+        0,
         resizeGeneric_<HResizeLanczos4<float, float, float>,
             VResizeLanczos4<float, float, float, Cast<float, float>,
             VResizeNoVec> >,
@@ -1412,8 +1412,8 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
     static ResizeAreaFastFunc areafast_tab[] =
     {
         resizeAreaFast_<uchar, int>, 0,
-               resizeAreaFast_<ushort, float>,
-               resizeAreaFast_<short, float>,
+        resizeAreaFast_<ushort, float>,
+        resizeAreaFast_<short, float>,
         0,
         resizeAreaFast_<float, float>,
         resizeAreaFast_<double, double>,
@@ -1528,7 +1528,7 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
                 assert( k < ssize.width*2 );
                 xofs[k].di = dx*cn;
                 xofs[k].si = sx2*cn;
-                xofs[k++].alpha = (float)((fsx2 - sx2)*scale);
+                xofs[k++].alpha = (float)(min(fsx2 - sx2, 1.)*scale);
             }
         }
 
@@ -3480,7 +3480,7 @@ void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr,
     if( !CV_ARE_TYPES_EQ( src, dst ))
         CV_Error( CV_StsUnmatchedFormats, "" );
 
-       ssize.width = src->cols;
+    ssize.width = src->cols;
     ssize.height = src->rows;
     dsize.width = dst->cols;
     dsize.height = dst->rows;
index 7eab003..7b6d8f3 100644 (file)
@@ -1462,6 +1462,40 @@ TEST(Imgproc_fitLine_Mat_3dC1, regression)
     ASSERT_EQ(line2.size(), (size_t)6);
 }
 
+TEST(Imgproc_resize_area, regression)
+{
+    static ushort input_data[16 * 16] = {
+         90,  94,  80,   3, 231,   2, 186, 245, 188, 165,  10,  19, 201, 169,   8, 228,
+         86,   5, 203, 120, 136, 185,  24,  94,  81, 150, 163, 137,  88, 105, 132, 132,
+        236,  48, 250, 218,  19,  52,  54, 221, 159, 112,  45,  11, 152, 153, 112, 134,
+         78, 133, 136,  83,  65,  76,  82, 250,   9, 235, 148,  26, 236, 179, 200,  50,
+         99,  51, 103, 142, 201,  65, 176,  33,  49, 226, 177, 109,  46,  21,  67, 130,
+         54, 125, 107, 154, 145,  51, 199, 189, 161, 142, 231, 240, 139, 162, 240,  22,
+        231,  86,  79, 106,  92,  47, 146, 156,  36, 207,  71,  33,   2, 244, 221,  71,
+         44, 127,  71, 177,  75, 126,  68, 119, 200, 129, 191, 251,   6, 236, 247,  6,
+        133, 175,  56, 239, 147, 221, 243, 154, 242,  82, 106,  99,  77, 158,  60, 229,
+          2,  42,  24, 174,  27, 198,  14, 204, 246, 251, 141,  31, 114, 163,  29, 147,
+        121,  53,  74,  31, 147, 189,  42,  98, 202,  17, 228, 123, 209,  40,  77,  49,
+        112, 203,  30,  12, 205,  25,  19, 106, 145, 185, 163, 201, 237, 223, 247,  38,
+         33, 105, 243, 117,  92, 179, 204, 248, 160,  90,  73, 126,   2,  41, 213, 204,
+          6, 124, 195, 201, 230, 187, 210, 167,  48,  79, 123, 159, 145, 218, 105, 209,
+        240, 152, 136, 235, 235, 164, 157,  9,  152,  38,  27, 209, 120,  77, 238, 196,
+        240, 233,  10, 241,  90,  67,  12, 79,    0,  43,  58,  27,  83, 199, 190, 182};
+
+    static ushort expected_data = {
+        // row 1
+        120, 100, 151, 101, 103,//?
+        // row 2
+        106, 115, 141, 130, suturate_cast<ushort>(0),
+        // row 3
+        91, 136, 170, 114, suturate_cast<ushort>(0),
+        // row 4
+        104, 122, 131, 147, suturate_cast<ushort>(0),
+        // row 5
+        suturate_cast<ushort>(0),suturate_cast<ushort>(0),suturate_cast<ushort>(0),suturate_cast<ushort>(0),suturate_cast<ushort>(0)
+    };
+}
+
 //////////////////////////////////////////////////////////////////////////
 
 TEST(Imgproc_Resize, accuracy) { CV_ResizeTest test; test.safe_run(); }