2
votes

i'm try to get covariance matrix from an image stored in cv::Mat. i need it for calculate mahalanobis distance and attempt to some color segmentation.

this is my code:

Mat covar, selection, meanBGR;
selection = src(roi);
calcCovarMatrix(selection, covar, meanBGR, CV_COVAR_NORMAL|CV_COVAR_ROWS);

the Mat src is from webcam and standard BGR opencv format, so CV_32FC3. pixels are stored (i think) in row vector order (blue, green, red).. so i think my code is correct. but i recive this runtime error:

Assertion failed (src.channels() == 1) in mulTransposed

i tried to make a vector too in this way:

vector<Scalar> samples;

for(int i=0; i<selection.rows; i++) {
    for(int j=0; j<selection.cols; j++) {

        Scalar pixel = selection.at<Scalar>(i,j);
        Scalar sample(pixel[0], pixel[1], pixel[2]);
        samples.push_back(sample);
    }
}

calcCovarMatrix(samples, covar, meanBGR, CV_COVAR_NORMAL|CV_COVAR_ROWS);

but i always get the same error. reading the manual doesn't make any kind of idea.

2

2 Answers

2
votes

I don't think you can pass it a 3-channel matrix. Does this small sample work:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <iostream>

using namespace cv;
using namespace std;

int main(int /*argc*/, char** /*argv*/)
{
    Mat_<float> samples = (Mat_<float>(3, 3) << 1.0, 2.0, 3.0,
                                                4.0, 5.0, 6.0,
                                                7.0, 8.0, 9.0);

    Mat cov, mu;
    cv::calcCovarMatrix(samples, cov, mu, CV_COVAR_NORMAL | CV_COVAR_ROWS);

    cout << "cov: " << endl;
    cout << cov << endl;

    cout << "mu: " << endl;
    cout << mu << endl;

    return 0;
}

It should output:

cov: 
[18, 18, 18;
  18, 18, 18;
  18, 18, 18]
mu: 
[4, 5, 6]

Hope that helps!

0
votes

I had the same problem. Unfortunately I think the only way to get the color co-variance is to do it manually. If you split the image and then rehape the resulting matrices into single rows, concat them back together (into a 3 row 1 channel mat) you can then just multiply by the transpose and divide by size - 1.