OpenCV Code Snippets

Datatypes

The OpenCV matrices CvMat and cv::Mat have their own type system:

OpenCV Datatype
CV_8Schar
CV_8Uunsigned char
CV_16Sshort
CV_16Uunsigned short
CV_32Sint
CV_32Ffloat
CV_64Fdouble

It's kind of awkward to remember all the types and even worse, there's no type-checking at compile time. So the recent OpenCV2 introduced the templated matrix cv::Mat_<_Tp>. Now imagine we are writing a highly simple function, where we want to print a matrix.

With a cv::Mat_ we can use the advantadges of templates:

#include <cv.h>
#include <iostream>

using namespace cv;
using namespace std;

template <typename _Tp>
void printMat(const cv::Mat_<_Tp>& mat) {
    typedef typename DataType<_Tp>::work_type _wTp;
    for(int i = 0; i < mat.rows; i++)
        for(int j=0; j < mat.cols; j++)
            cout << (_wTp) mat(i,j) << " ";
    cout << endl;
}

void printMat(const cv::Mat& mat) {
    for(int i = 0; i < mat.rows; i++)
        for(int j=0; j < mat.cols; j++)
            cout << (int) mat.at<unsigned char>(i,j) << " ";
    cout << endl;
}

int main(int argc, const char *argv[]) {

    unsigned char a[] = {0,1,2,3,4,5,6,7,8};
    Mat_<unsigned char> d0 = cv::Mat_<unsigned char>(9,1,a).clone();
    Mat d1 = cv::Mat(9,1,CV_8UC1,a).clone();
    cout << "d0: ";
    printMat(d0);
    cout << "d1: ";
    printMat(d1);
}

If you run the the program you'll get:

d0: 0 1 2 3 4 5 6 7 8 
d1: 0 1 2 3 4 5 6 7 8 

But what happens if I now choose integers instead?

int main(int argc, const char *argv[]) {

    int a[] = {255,256,257,258,259,260,261,262,263};
    Mat_<int> d0 = cv::Mat_<int>(9,1,a).clone();
    Mat d1 = cv::Mat(9,1,CV_32SC1,a).clone();
    cout << "d0: ";
    printMat(d0);
    cout << "d1: ";
    printMat(d1);
}

If I now run the function, you'll see where it fails... The element access to the cv::Mat with unsigned char will truncate the result:

d0: 255 256 257 258 259 260 261 262 263 
d1: 255 0 1 2 3 4 5 6 7 

So the first function stays unchanged, because of using templates, while printMat(const cv::Mat& mat) has to be changed to:

void printMat(const cv::Mat& mat) {
    for(int i = 0; i < mat.rows; i++)
        for(int j=0; j < mat.cols; j++)
            cout << mat.at<int>(i,j) << " ";
    cout << endl;
}

For old code I write my methods in such a way:

template <typename _Tp>
void histogram(const cv::Mat& input, cv::Mat& hist, int N) {
  hist = cv::Mat::zeros(1, N, CV_32SC1);
  for(int i = 0; i < input.rows; i++) {
    for(int j = 0; j < input.cols; j++) {
      int bin = input.at<_Tp>(i,j);
      hist.at<int>(0,bin) += 1;
    }
  }
}

void histogram(const cv::Mat& input, cv::Mat& hist, int N) {
  if(input.type() != CV_8SC1 && input.type() && CV_8UC1 && input.type() != CV_16SC1
            && input.type() != CV_16UC1 && input.type() != CV_32SC1)
  {
    CV_Error(CV_StsUnsupportedFormat, "Only Integer data is supported.");
    lf::logging::error("wrong type for histogram.");
  }

  switch(input.type()) {
    case CV_8SC1: histogram<char>(input, hist, N); break;
    case CV_8UC1: histogram<unsigned char>(input, hist, N); break;
    case CV_16SC1: histogram<short>(input, hist, N); break;
    case CV_16UC1: histogram<unsigned short>(input, hist, N); break;
    case CV_32SC1: histogram<int>(input, hist, N); break;
  }
}

General Matrix Multiplication

In Octave:

octave:1> A = [1 2;3 4]
A =

   1   2
   3   4

octave:2> B = [5 6;7 8]
B =

   5   6
   7   8

octave:3> C = [9 10;11 12]
C =

    9   10
   11   12

octave:4> A*B
ans =

   19   22
   43   50

octave:5> A'*B
ans =

   26   30
   38   44

octave:6> A'*B'
ans =

   23   31
   34   46

octave:7> alpha=2
alpha =  2
octave:8> A*B+alpha*C
ans =

   37   42
   65   74

In OpenCV2 this translates to:

#include <cv.h>
#include <iostream>

int main(int argc, const char *argv[]) {

    float a[] = {1.0, 2.0, 3.0, 4.0};
    float b[] = {5.0, 6.0, 7.0, 8.0};
    float c[] = {9.0, 10.0, 11.0, 12.0};

    cv::Mat A = cv::Mat(2,2,CV_32FC1,a).clone();
    cv::Mat B = cv::Mat(2,2,CV_32FC1, b).clone();
    cv::Mat C = cv::Mat(2,2,CV_32FC1, c).clone();;
    cv::Mat D; // result
    // D = A*B
    cv::gemm(A, B, 1.0, cv::Mat(), 0.0, D);
    std::cout << D << std::endl;
    // D = A^T*B
    cv::gemm(A, B, 1.0, cv::Mat(), 0.0, D, CV_GEMM_A_T);
    std::cout << D << std::endl;
    // D = A^T * B^T
    cv::gemm(A, B, 1.0, cv::Mat(), 0.0, D, CV_GEMM_A_T + CV_GEMM_B_T);
    std::cout << D << std::endl;
    // D = A*B+alpha*C
    float alpha = 2.0;
    cv::gemm(A, B, 1.0, C, alpha, D);
    std::cout << D << std::endl;

    return 0;
}

How to contribute

One of the easiest ways to contribute is to participate in discussions. You can also contribute by submitting pull requests.

General feedback and discussions?

Do you have questions or feedback on this article? Please create an issue on the GitHub issue tracker.

Something is wrong or missing?

There may be something wrong or missing in this article. If you want to help fixing it, then please make a Pull Request to this file on GitHub.