4

I am writing a function in which I need to access to a element of a Mat, but this function can receive Mat of differents types. So, if I have:

filtered.at<TypeofMat>(i) = (typeofmat) somevalue;

It only occurs to me to do something like this filtered.at<myMat.type()>(i), but obviously this does not work because type returns a int

I am stuck, Could someone give some light?

Alejandro Alcalde
  • 5,990
  • 6
  • 39
  • 79
  • can you show a simplified version of the function you want to do? – Miki Oct 15 '15 at 11:14
  • I am creating kernels for applying smooth filters. I have two functions, one that creates the kernel (also access Mat elements) and the one that computes the convolution. – Alejandro Alcalde Oct 15 '15 at 11:15
  • usually, if you know the number of channels (should be 1 here, right?) you simply convert internally all matrix to double `CV_64F`, and work internally on doubles. Then you convert the result back to the original type. – Miki Oct 15 '15 at 11:17
  • I am going to try, thank you!, It it works, make your comment an answer :-) – Alejandro Alcalde Oct 15 '15 at 11:20
  • 1
    you can convert to CV_64FC3 the images internally, and work on doubles – Miki Oct 15 '15 at 11:21
  • @Miki, it seems to be working. Post an answer If you want me to accept it. Thank you! – Alejandro Alcalde Oct 15 '15 at 11:33

2 Answers2

5

You can convert the source matrix to a matrix of double (type CV_64F). In this way you won't lose any data due to casting. Then you can work on this matrix as usual, since you know its type. Last step is to convert back the destination image to the source type.

You need to know the number of channels of your matrices, though. A CV_assert will make sure that you're working on the correct type.

#include <opencv2/opencv.hpp>
using namespace cv;

void foo(const Mat& src, Mat& dst)
{
    // Assert number of channels
    CV_Assert(src.channels() == 3);

    // Convert to CV64F
    Mat3d _src, _dst;
    src.convertTo(_src, CV_64F);
    _dst.create(_src.size());

    // Work on _src and _dst (you know the type)
    _dst(0,0) = _src(0,0) + Vec3d(1,2,3);

    // Convert _dst to src type
    _dst.convertTo(dst, src.type());
}

int main()
{
    Mat3b img(10,10,Vec3b(0,0,0));

    Mat res;
    foo(img, res);

    // res will be CV_8UC3

    return 0;
}

There are also alternatives to this approach:

  • create a template function an call the appropriate specialization. See here
  • work on raw pointers. See here
  • use only OpenCV functions, that handle correctly every type. See here. This is usually the best option, if available.
Community
  • 1
  • 1
Miki
  • 40,887
  • 13
  • 123
  • 202
  • Just a general wondering, can the template method in the answer below work? – Rick M. Mar 01 '17 at 10:09
  • 1
    Yes, but you need a `switch` to select the function with the correct template in the calling function. This is equivalent to the first alternative approach I mentioned – Miki Mar 01 '17 at 10:14
1

If it is a possibility, make the function receiving the openCV Mat a template function:

void f<typename T>(const Mat& m)
{
    (void) m.at<T>(0, 0);
}

use it like that:

Mat m1/* ... */;
m1.at<int>(0, 0) = 0;
f<int>(m);
prgasp77
  • 37
  • 1