[英]Calculating the mean and standard deviation in C++ for single channeled histogram
我想计算 HSV 图像直方图的平均值和标准偏差,但我只想为 V 通道做这个直方图和计算。
我一直在阅读有关如何为一组通道执行此操作的示例,并尝试了这些方法,但我对我最初创建直方图的方法是否仅对一个通道正确感到困惑,因为程序在我尝试时不断崩溃执行它。
这是我目前所拥有的(变量 test 是一个 cv::Mat 图像,这可以是您希望用来重现问题的任何图像)。 我可能遗漏了一些明显的东西,并且 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;;
您可以简单地使用cv::meanStdDev ,它计算数组元素的均值和标准差。
请注意, mean
和stddev
参数都是cv::Scalar
,因此您需要执行mean[0]
和stddev[0]
来获取单通道数组hist
的双hist
。
此代码将阐明它的用法:
#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;
}
更新
您可以根据它们的定义计算均值和标准差:
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;
并且您将获得与 OpenCV meanStdDev
相同的值。
在直方图上计算统计数据时要小心。 如果您只运行meanStdDev
,您将获得 bin 值的均值和标准差。 这并没有告诉你很多。
可能你想要的是均值和标准差强度。
因此,如果您想从直方图(或一组直方图)中导出图像均值和标准差,则可以使用以下代码:
// 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);
从均值的定义来看:
mean = sum(x * p(x)) // expectation
std = sqrt(sum( p(x)*(x - mean)**2 ) // sqrt(variance)
平均值是 x 的期望值。 所以histogram[x]/sum(histogram)
给你p(x)
。 标准差的定义类似,来自方差。 数字稍微简单一些,因为像素只能取整数值并且是单位间隔的。
请注意,如果您想使用accumulate
选项计算一批图像的归一化统计数据,这也很有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.