简体   繁体   English

在 C++ 中计算单通道直方图的均值和标准差

[英]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.我想计算 HSV 图像直方图的平均值和标准偏差,但我只想为 V 通道做这个直方图和计算。

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).这是我目前所拥有的(变量 test 是一个 cv::Mat 图像,这可以是您希望用来重现问题的任何图像)。 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.我可能遗漏了一些明显的东西,并且 for 循环在值的范围方面可能不正确,但我之前没有在 C++ 中这样做过。

        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;;

You can simply use cv::meanStdDev , that calculates a mean and standard deviation of array elements.您可以简单地使用cv::meanStdDev ,它计算数组元素的均值和标准差。

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 .请注意, meanstddev参数都是cv::Scalar ,因此您需要执行mean[0]stddev[0]来获取单通道数组hist的双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 .并且您将获得与 OpenCV meanStdDev相同的值。

Be careful about calculating statistics on a histogram.在直方图上计算统计数据时要小心。 If you just run meanStdDev , you'll get the mean and stdev of the bin values.如果您只运行meanStdDev ,您将获得 bin 值的均值和标准差。 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.平均值是 x 的期望值 So histogram[x]/sum(histogram) gives you p(x) .所以histogram[x]/sum(histogram)给你p(x) The definition of standard deviation is similar and comes from thevariance .标准差的定义类似,来自方差 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.请注意,如果您想使用accumulate选项计算一批图像的归一化统计数据,这也很有用。

Adapted from: How to calculate the standard deviation from a histogram?改编自: 如何计算直方图的标准偏差? (Python, Matplotlib) (Python,Matplotlib)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM