Calculating mean value of pixels of many images

asked 2016-01-15 15:06:59 -0500

Sean87 gravatar image

updated 2016-01-16 10:37:50 -0500

I have some images that I want to calculate mean value of each pixel of all images. Lets say I have 5 image of size 3x3. I read all pixels of each image and put them in row of a Mat object so at the end I have a 5x15 Mat. Using c++ code it is easy (I have a Vector<Vector<double>>)

std::for_each(data->begin(), data->end(),

    [&](const std::vector<uchar>& row)
    {
        std::transform(row.begin(), row.end(), colSums.begin(), colSums.begin(),
                       [](double d1, double d2) { return d1 + d2; });
    });
for (unsigned int i = 0; i < elementsCount; i++) {
    colSums[i] /= dataCount;
}

but how I can use opencv itself to do this? I want sum of each column divided by number of images to form a new Mat. I tried the code below but it does not work gives only a 1x1 mat!!!

void BayesianClassifier::createAggregateFromTrainingVector(pr::training_vector tv)
{
    //building a Mat object from vector pointer
    cv::Mat mat(tv.size(), tv.at(0).size(), CV_8UC1);

    int rows = mat.rows;
    int cols = mat.cols;

    for (int r = 0; r < rows; ++r) {

        uchar *pInput = mat.ptr<uchar>(r);

        for (int c = 0; c < cols; ++c) {
            *pInput = tv.at(r)[c];
            ++pInput;
        }
    }

    mData = mat;

    cv::meanStdDev(mData, mMatMean, mMatVariance);
}

UPDATE

I feel that I didn't clarify enough. Imagine the 6x6 matrix below, where each row represents a 2x3 image, and for simplification lets imagine all images are the same! (I call this Mat mData)

{ 1, 2, 3, 4, 5, 6
  1, 2, 3, 4, 5, 6
  1, 2, 3, 4, 5, 6
  1, 2, 3, 4, 5, 6
  1, 2, 3, 4, 5, 6
  1, 2, 3, 4, 5, 6 }

I want to get the mean value of each pixel, so at the end I want to show a 3x3 image of the mean values. For this, I need to calculate mean of each column. For the simple case above, for column 1 it will be:

SUM OF COL 1 => 1 + 1 + 1 + 1 + 1 + 1 = 6 
MEAN OF COL 1 => 6/6 = 1

Doing this for all column will result in:

{ 1, 2, 3, 4, 5, 6 }

and converting this single row into 2x3 image:

{ 1, 2, 3
  4, 5, 6 }

So my question is, if I do the following code:

Mat cov, mean;
cv::calcCovarMatrix(mData, cov, mean, CV_COVAR_NORMAL | CV_COVAR_ROWS);

The mean will not be a 1x6 { 1, 2, 3, 4, 5, 6 } matrix like what I theoretically calculated above?

edit retag flag offensive close merge delete

Comments

take a look at cv:reduce

sturkmen gravatar imagesturkmen ( 2016-01-15 15:40:19 -0500 )edit

@sturkman Thanks, I am doing that...but does not the calcCovar... or meanStdDev do the same thing to the give OutputArray of their arguments?

Sean87 gravatar imageSean87 ( 2016-01-15 18:33:45 -0500 )edit

cv::mean and cv::meanStdDev fills Scalars with values. A Scalar is 4 doubles that can be accessed with the parentheses operator. If you have only 1 channel, only the first value is filled, so mean(0) would be what you want. It's the average of all rows and cols in the channel.

So if you want the mean of each image individually, (and you do, if I'm reading the first example correctly) then you want to do cv::mean on each of the images, instead of putting them into rows.

Tetragramm gravatar imageTetragramm ( 2016-01-15 22:35:49 -0500 )edit

@Tetragramm can you please check the updated question? I think I was not clear before

Sean87 gravatar imageSean87 ( 2016-01-16 07:59:06 -0500 )edit

I see now. That may work, but that will require much extra work to calculate the covariance. The simplest way is what sturkmen said, so use cv::reduce the dim would be 0, to reduce it to a single row, and you want REDUCE_AVG to get the mean.

Both reduce and calcCovarMatrix will have the same output, but calcCovarMatrix does a significant amount of extra things along the way, and is therefore slower. In addition, the meaning of what you are trying to do will be clearer, since you don't actually care about the covariance.

Tetragramm gravatar imageTetragramm ( 2016-01-16 10:23:21 -0500 )edit

Actually I need the covariance too to implement a naive bayesian classifier

Sean87 gravatar imageSean87 ( 2016-01-16 10:38:49 -0500 )edit

Then yes, calcCovarMatrix is precisely what you want.

Tetragramm gravatar imageTetragramm ( 2016-01-16 10:50:10 -0500 )edit