Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculating the mean and standard deviation in C++ for single channeled histogram

I want calculate the mean and standard deviations for a histogram of a HSV image but I only want to do this histogram and calculations for the V channel.

I have been reading examples on how to do this for a set of channels and have tried these approaches but I am getting confused over whether my approach for initially creating the histogram is correct or not for just one channel because the program keeps crashing when i try to execute it.

Here is what I have at the moment (The variable test is a cv::Mat image and this can be any image you wish to use to recreate the issue). I have probably missed something obvious and the for loop might not be correct in terms of the range of values but I haven't done this in C++ before.

        cv::cvtColor(test, test, CV_BGR2HSV);


        int v_bins = 50;
        int histSize[] = { v_bins };
        cv::MatND hist;

        float v_ranges[] = { 0, 255};
        cv::vector<cv::Mat> channel(3);
        split(test, channel);

        const float* ranges[] = { v_ranges };
        int channels[] = {0};

        cv::calcHist(&channel[2], 1, channels, cv::Mat(), hist, 1, histSize, ranges, true, false); //histogram calculation

        float mean=0;

        float rows= hist.size().height;
        float cols = hist.size().width;

        for (int v = 0; v < v_bins; v++)
        {
            std::cout << hist.at<float>(v, v) << std::endl;;
            mean = mean + hist.at<float>(v);
        }

        mean = mean / (rows*cols);
        std::cout << mean<< std::endl;;
like image 450
bardsleyta Avatar asked Nov 06 '15 14:11

bardsleyta


People also ask

How do you find the mean and standard deviation in C?

We calculate the Mean by adding all the elements and dividing that number by the total number of elements. sum += (num[i] - mean) * (num[i] - mean); SD = sqrt(sum / n); // Calculating Standard Deviation sum = 0.0; for (i = 0; i < n; i++) sum += (num[i] - mean) * (num[i] - mean); SD = sqrt(sum / n);

How do you calculate mean SD on CV?

The formula for the coefficient of variation is: Coefficient of Variation = (Standard Deviation / Mean) * 100. In symbols: CV = (SD/x̄) * 100. Multiplying the coefficient by 100 is an optional step to get a percentage, as opposed to a decimal.


2 Answers

You can simply use cv::meanStdDev, that calculates a mean and standard deviation of array elements.

Note that both mean and stddev arguments are cv::Scalar, so you need to do mean[0] and stddev[0] to get the double values of your single channel array hist.

This code will clarify it's usage:

#include <opencv2\opencv.hpp>
#include <iostream>

int main()
{
    cv::Mat test = cv::imread("path_to_image");

    cv::cvtColor(test, test, CV_BGR2HSV);

    int v_bins = 50;
    int histSize[] = { v_bins };
    cv::MatND hist;

    float v_ranges[] = { 0, 255 };
    cv::vector<cv::Mat> channel(3);
    split(test, channel);

    const float* ranges[] = { v_ranges };
    int channels[] = { 0 };

    cv::calcHist(&channel[2], 1, channels, cv::Mat(), hist, 1, histSize, ranges, true, false); //histogram calculation

    cv::Scalar mean, stddev;
    cv::meanStdDev(hist, mean, stddev);

    std::cout << "Mean: " << mean[0] << "   StdDev: " << stddev[0] << std::endl;

    return 0;
}

UPDATE

You can compute the mean and the standard deviation by their definition:

double dmean = 0.0;
double dstddev = 0.0;

// Mean standard algorithm
for (int i = 0; i < v_bins; ++i)
{
    dmean += hist.at<float>(i);
}
dmean /= v_bins;

// Standard deviation standard algorithm
std::vector<double> var(v_bins);
for (int i = 0; i < v_bins; ++i)
{
    var[i] = (dmean - hist.at<float>(i)) * (dmean - hist.at<float>(i));
}
for (int i = 0; i < v_bins; ++i)
{
    dstddev += var[i];
}
dstddev = sqrt(dstddev / v_bins);

std::cout << "Mean: " << dmean << "   StdDev: " << dstddev << std::endl;

and you'll get the same values as OpenCV meanStdDev.

like image 74
Miki Avatar answered Oct 03 '22 07:10

Miki


Be careful about calculating statistics on a histogram. If you just run meanStdDev, you'll get the mean and stdev of the bin values. That doesn't tell you an awful lot.

Probably what you want is the mean and stdev intensity.

So, if you want to derive the image mean and standard deviation from a histogram (or set of histograms), then you can use the following code:

// assume histogram is of type cv::Mat and comes from cv::calcHist

double s = 0;
double total_hist = 0;

for(int i=0; i < histogram.total(); ++i){
    s += histogram.at<float>(i) * (i + 0.5); // bin centre
    total_hist += histogram.at<float>(i);
}

double mean = s / total_hist;

double t = 0;
for(int i=0; i < histogram.total(); ++i){
    double x = (i - mean);
    t += histogram.at<float>(i)*x*x;
}
double stdev = std::sqrt(t / total_hist);

From the definitions of the mean:

mean = sum(x * p(x)) // expectation
std = sqrt(sum( p(x)*(x - mean)**2 ) // sqrt(variance)

The mean is the expectation value for x. So histogram[x]/sum(histogram) gives you p(x). The definition of standard deviation is similar and comes from the variance. The numbers are slightly simpler because pixels can only take integer values and are unit spaced.

Note this is also useful if you want to calculate normalisation statistics for a batch of images using the accumulate option.

Adapted from: How to calculate the standard deviation from a histogram? (Python, Matplotlib)

like image 34
Josh Avatar answered Oct 03 '22 08:10

Josh