made createContinuous & ensureSizeIsEnough generic (OutputArray support)
authorVladislav Vinogradov <vlad.vinogradov@itseez.com>
Fri, 26 Apr 2013 06:53:15 +0000 (10:53 +0400)
committerVladislav Vinogradov <vlad.vinogradov@itseez.com>
Mon, 10 Jun 2013 08:40:32 +0000 (12:40 +0400)
modules/core/include/opencv2/core/gpu.hpp
modules/core/include/opencv2/core/gpu.inl.hpp
modules/core/src/gpu_cuda_mem.cpp
modules/core/src/gpu_mat.cpp

index bbeda31..7ddbf7f 100644 (file)
@@ -252,11 +252,11 @@ public:
 };
 
 //! creates continuous GPU matrix
-CV_EXPORTS void createContinuous(int rows, int cols, int type, GpuMat& m);
+CV_EXPORTS void createContinuous(int rows, int cols, int type, OutputArray arr);
 
 //! ensures that size of the given matrix is not less than (rows, cols) size
 //! and matrix type is match specified one too
-CV_EXPORTS void ensureSizeIsEnough(int rows, int cols, int type, GpuMat& m);
+CV_EXPORTS void ensureSizeIsEnough(int rows, int cols, int type, OutputArray arr);
 
 CV_EXPORTS GpuMat allocMatFromBuf(int rows, int cols, int type, GpuMat& mat);
 
@@ -296,6 +296,10 @@ public:
     void create(int rows, int cols, int type);
     void create(Size size, int type);
 
+    //! creates alternative CudaMem header for the same data, with different
+    //! number of channels and/or different number of rows
+    CudaMem reshape(int cn, int rows = 0) const;
+
     //! decrements reference counter and released memory if needed.
     void release();
 
index a30f1b6..b44c2b1 100644 (file)
@@ -347,9 +347,9 @@ GpuMat createContinuous(int rows, int cols, int type)
 }
 
 static inline
-void createContinuous(Size size, int type, GpuMat& m)
+void createContinuous(Size size, int type, OutputArray arr)
 {
-    createContinuous(size.height, size.width, type, m);
+    createContinuous(size.height, size.width, type, arr);
 }
 
 static inline
@@ -361,9 +361,9 @@ GpuMat createContinuous(Size size, int type)
 }
 
 static inline
-void ensureSizeIsEnough(Size size, int type, GpuMat& m)
+void ensureSizeIsEnough(Size size, int type, OutputArray arr)
 {
-    ensureSizeIsEnough(size.height, size.width, type, m);
+    ensureSizeIsEnough(size.height, size.width, type, arr);
 }
 
 static inline
index 3681fd7..52de069 100644 (file)
@@ -121,6 +121,49 @@ void cv::gpu::CudaMem::create(int rows_, int cols_, int type_)
 #endif
 }
 
+CudaMem cv::gpu::CudaMem::reshape(int new_cn, int new_rows) const
+{
+    CudaMem hdr = *this;
+
+    int cn = channels();
+    if (new_cn == 0)
+        new_cn = cn;
+
+    int total_width = cols * cn;
+
+    if ((new_cn > total_width || total_width % new_cn != 0) && new_rows == 0)
+        new_rows = rows * total_width / new_cn;
+
+    if (new_rows != 0 && new_rows != rows)
+    {
+        int total_size = total_width * rows;
+
+        if (!isContinuous())
+            CV_Error(cv::Error::BadStep, "The matrix is not continuous, thus its number of rows can not be changed");
+
+        if ((unsigned)new_rows > (unsigned)total_size)
+            CV_Error(cv::Error::StsOutOfRange, "Bad new number of rows");
+
+        total_width = total_size / new_rows;
+
+        if (total_width * new_rows != total_size)
+            CV_Error(cv::Error::StsBadArg, "The total number of matrix elements is not divisible by the new number of rows");
+
+        hdr.rows = new_rows;
+        hdr.step = total_width * elemSize1();
+    }
+
+    int new_width = total_width / new_cn;
+
+    if (new_width * new_cn != total_width)
+        CV_Error(cv::Error::BadNumChannels, "The total width is not divisible by the new number of channels");
+
+    hdr.cols = new_width;
+    hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn - 1) << CV_CN_SHIFT);
+
+    return hdr;
+}
+
 void cv::gpu::CudaMem::release()
 {
 #ifdef HAVE_CUDA
index fb8251c..1bbcb84 100644 (file)
@@ -1022,48 +1022,95 @@ GpuMat& cv::gpu::GpuMat::adjustROI(int dtop, int dbottom, int dleft, int dright)
     return *this;
 }
 
-void cv::gpu::createContinuous(int rows, int cols, int type, GpuMat& m)
+namespace
 {
-    const int area = rows * cols;
+    template <class ObjType>
+    void createContinuousImpl(int rows, int cols, int type, ObjType& obj)
+    {
+        const int area = rows * cols;
 
-    if (m.empty() || m.type() != type || !m.isContinuous() || m.size().area() < area)
-        m.create(1, area, type);
+        if (obj.empty() || obj.type() != type || !obj.isContinuous() || obj.size().area() < area)
+            obj.create(1, area, type);
 
-    m.cols = cols;
-    m.rows = rows;
-    m.step = m.elemSize() * cols;
-    m.flags |= Mat::CONTINUOUS_FLAG;
+        obj = obj.reshape(obj.channels(), rows);
+    }
 }
 
-void cv::gpu::ensureSizeIsEnough(int rows, int cols, int type, GpuMat& m)
+void cv::gpu::createContinuous(int rows, int cols, int type, OutputArray arr)
 {
-    if (m.empty() || m.type() != type || m.data != m.datastart)
+    switch (arr.kind())
     {
-        m.create(rows, cols, type);
-    }
-    else
-    {
-        const size_t esz = m.elemSize();
-        const ptrdiff_t delta2 = m.dataend - m.datastart;
+    case _InputArray::MAT:
+        ::createContinuousImpl(rows, cols, type, arr.getMatRef());
+        break;
+
+    case _InputArray::GPU_MAT:
+        ::createContinuousImpl(rows, cols, type, arr.getGpuMatRef());
+        break;
 
-        const size_t minstep = m.cols * esz;
+    case _InputArray::CUDA_MEM:
+        ::createContinuousImpl(rows, cols, type, arr.getCudaMemRef());
+        break;
 
-        Size wholeSize;
-        wholeSize.height = std::max(static_cast<int>((delta2 - minstep) / m.step + 1), m.rows);
-        wholeSize.width = std::max(static_cast<int>((delta2 - m.step * (wholeSize.height - 1)) / esz), m.cols);
+    default:
+        arr.create(rows, cols, type);
+    }
+}
 
-        if (wholeSize.height < rows || wholeSize.width < cols)
+namespace
+{
+    template <class ObjType>
+    void ensureSizeIsEnoughImpl(int rows, int cols, int type, ObjType& obj)
+    {
+        if (obj.empty() || obj.type() != type || obj.data != obj.datastart)
         {
-            m.create(rows, cols, type);
+            obj.create(rows, cols, type);
         }
         else
         {
-            m.cols = cols;
-            m.rows = rows;
+            const size_t esz = obj.elemSize();
+            const ptrdiff_t delta2 = obj.dataend - obj.datastart;
+
+            const size_t minstep = obj.cols * esz;
+
+            Size wholeSize;
+            wholeSize.height = std::max(static_cast<int>((delta2 - minstep) / static_cast<size_t>(obj.step) + 1), obj.rows);
+            wholeSize.width = std::max(static_cast<int>((delta2 - static_cast<size_t>(obj.step) * (wholeSize.height - 1)) / esz), obj.cols);
+
+            if (wholeSize.height < rows || wholeSize.width < cols)
+            {
+                obj.create(rows, cols, type);
+            }
+            else
+            {
+                obj.cols = cols;
+                obj.rows = rows;
+            }
         }
     }
 }
 
+void cv::gpu::ensureSizeIsEnough(int rows, int cols, int type, OutputArray arr)
+{
+    switch (arr.kind())
+    {
+    case _InputArray::MAT:
+        ::ensureSizeIsEnoughImpl(rows, cols, type, arr.getMatRef());
+        break;
+
+    case _InputArray::GPU_MAT:
+        ::ensureSizeIsEnoughImpl(rows, cols, type, arr.getGpuMatRef());
+        break;
+
+    case _InputArray::CUDA_MEM:
+        ::ensureSizeIsEnoughImpl(rows, cols, type, arr.getCudaMemRef());
+        break;
+
+    default:
+        arr.create(rows, cols, type);
+    }
+}
+
 GpuMat cv::gpu::allocMatFromBuf(int rows, int cols, int type, GpuMat& mat)
 {
     if (!mat.empty() && mat.type() == type && mat.rows >= rows && mat.cols >= cols)