7

I would like to access the elements of a matrix of unknown type:

for(int ii = 0; ii < origCols; ii++)
{
  colIdx.at<img.type()>(0,ii) = ii+1; // make one based index
}

The expression defining the type (inside the <>) has to be a constant, so the above code will not work. Is there a way to do this other than just switching across the different image types?

zzzz
  • 682
  • 10
  • 16

2 Answers2

4

After looking through some of the docs, I don't think there is a native OpenCV way to do it without avoiding branching.

If you are just concerned about cleaner code, you could try a template approach so long as you don't mind templates:

template <typename T> void dostuff(cv::Mat& colIdx, int origCols)
{
   for(int ii = 0; ii < origCols; ii++)
   {
       colIdx.at<T>(0,ii) = (T)(ii+1); // make one based index
   }
}

void dostuff_poly(cv::Mat& colIdx, int origCols)
{
    switch(colIdx.type())
    {
        case CV_8UC1: dostuff<char>(colIdx, origCols); break;
        case CV_32FC1: dostuff<float>(colIdx, origCols); break;
        case CV_64FC1: dostuff<double>(colIdx, origCols); break;
        // and so on
        default:
    }
}

In this example, the code is rather small, so templates seems like it wouldn't be a bad choice and would give you the polymorphism you want without writing a bunch of redundant code.

Maybe some of these tutorials would give you a better idea:

OpenCV docs: core module tutorials

OpenCV docs: How to scan images

Matteo Mannino
  • 401
  • 1
  • 3
  • 9
1

There is no native Opencv solution to your problem, and it is a frequent pain with this library. There are three possible solutions:

  1. Always use matrices with the same depth. I guess that's not what you want to hear.
  2. Template the method that calls your code by the type of the elements contained in the matrix: this will only work for single channel matrices, as the template of the .at<> method will have to be something by cv::Point2f for matrices for multiple channels.
  3. Create a "smart" iterator class that will know how to access matrix data based on the matrix depth. Something like:

    class PtrMat
    {
      PtrMat(cv::Mat& mat, int row)
      {
        if(mat.depth() == CV_32F) { _ptr = new PtrFloat(mat, row); }
        else if(mat.depth() == CV_8U) { _ptr = new PtrUchar(mat, row); }
        ...
      }
      Ptr* _ptr
    };
    
    class Ptr
    {
      virtual void set(const float& val)=0;
    };
    class PtrFloat: public Ptr
    {
      PtrFloat(const cv::Mat& mat, int row){ _val = mat.ptr<float>(row); }
      void set(const float& val) { _val = val; }
      float* _val;
    }
    class PtrUchar: public Ptr
    {
      PtrUchar(const cv::Mat& mat, int row){ _val = mat.ptr<uchar>(row); }
      void set(const float& val) { _val = val; }
      uchar* _val;
    }
    

Of course, with the third solution you end up with lots of duplicated code. Float casting can also slow down your loops. No solution is perfect in this case.

Régis B.
  • 10,092
  • 6
  • 54
  • 90
  • I think that Toti's answer below is cleaner for what I want to do, but that you make several good points. Thanks for the response. The combination helped me figure what I will try, which will probably be template based. – zzzz Jul 19 '12 at 16:48