【42】【OpenCV C++】 计算图像某一列像素方差 或 某一行像素的方差;
文章目录
- 1 要使用到的函数 和 原理
- 1.1 cv::meanStdDev 函数详解——计算均值和标准差
- 1 .2 方差的通俗解释
- 2 代码实现
- 3 问题
- 3.1 入口参数const cv::Mat& img 和 const cv::Mat img区别
项目要求:
- C++ OPenCV 中 图像img ,
- 当 string ROIdirection =“H”时,代表横向线条,则在图像宽度的一半处取一列像素,计算方差;
- 当 string ROIdirection =“V”时,代表竖向线条,则在图像高度的一半处取一行像素,计算方差;
要求写一个独立的函数实现该功能,计算的方差有入口参数带出来;
1 要使用到的函数 和 原理
1.1 cv::meanStdDev 函数详解——计算均值和标准差
OpenCV的cv::meanStdDev
函数用于同时计算输入矩阵的均值和标准差。函数定义如下:
void cv::meanStdDev(InputArray src, OutputArray mean, OutputArray stddev, InputArray mask=noArray());
参数:
src:
输入数组,必须是单通道或多通道的图像。mean:
输出参数,返回各个通道的均值。stddev:
输出参数,返回各个通道的标准差。mask:
可选的操作掩码,用于指定需要计算的区域。如果不提供,默认计算整个图像。
功能:
meanStdDev
计算输入矩阵src的均值和标准差。均值是数据的平均值,标准差是数据偏离均值的程度。
代码示例及详细解释
假设我们有一个一维矩阵linePixels1D,我们可以使用meanStdDev函数来计算它的均值和标准差。具体代码如下:
cv::Scalar mean, stddev;
cv::meanStdDev(linePixels1D, mean, stddev);
linePixels1D
:输入矩阵,这里是一维的像素值数组。mean
:输出参数,存储均值结果。stddev
:输出参数,存储标准差结果。
例子详细解释:
假设linePixels1D包含以下像素值:
[100, 150, 200, 250, 150, 100, 200, 250]
执行cv::meanStdDev后,计算过程如下:
然后计算这些偏差平方的平均值:
(5625 + 625 + 625 + 5625 + 625 + 5625 + 625 + 5625)/8 = 3593.75;
最后计算标准差(方差的平方根):
sqrt{3593.75} = 59.94;
3.函数结果:
mean[0]
将包含均值:175stddev[0]
将包含标准差:59.94
1 .2 方差的通俗解释
方差是一个统计学概念,用于衡量一组数据的分散程度。通俗地讲,方差告诉我们数据点离平均值有多远。理解方差可以帮助我们了解数据的波动情况。
举例说明:
假设我们有两组学生的考试成绩:
组A:90, 91, 89, 92, 88
组B:60, 95, 85, 70, 100
这两组的平均分可能相同或相近,但数据的分散情况不同。组A的成绩比较集中,组B的成绩波动较大。
计算步骤:
结果解读:
- 组A的方差为2,组B的方差为226。说明组A的成绩比较集中,而组B的成绩波动较大。
- 方差越大,数据分布越分散。方差越小,数据越集中。
方差的通俗意义
- 方差提供了一种量化数据分散程度的方法。
- 在实际应用中,方差可以帮助我们理解和比较不同数据集的稳定性。例如,在股票市场中,较大的方差意味着股票价格波动较大,风险较高;较小的方差意味着价格波动较小,风险较低。
2 代码实现
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>// 计算图像指定方向的像素方差
void calculateVariance(const cv::Mat& img, const std::string& ROIdirection, double& variance) {// 检查图像是否为空if (img.empty()) {std::cerr << "错误: 图像为空!" << std::endl;return;}// 检查方向参数是否有效if (ROIdirection != "H" && ROIdirection != "V") {std::cerr << "错误: 无效的ROIdirection!请使用 'H' 或 'V'。" << std::endl;return;}// 用于存储提取的像素线条cv::Mat linePixels;if (ROIdirection == "H") {// 如果是水平方向,在图像一半宽度处取一列像素int colIndex = img.cols / 2;linePixels = img.col(colIndex);} else if (ROIdirection == "V") {// 如果是垂直方向,在图像一半高度处取一行像素int rowIndex = img.rows / 2;linePixels = img.row(rowIndex);}// 将像素线条转换为一维数组以便计算方差cv::Mat linePixels1D = linePixels.reshape(1, linePixels.total());// 计算均值和标准差cv::Scalar mean, stddev;cv::meanStdDev(linePixels1D, mean, stddev);// 方差是标准差的平方variance = stddev[0] * stddev[0];
}int main() {// 加载示例图像(为了简单起见,使用灰度模式)cv::Mat img = cv::imread("path_to_image.jpg", cv::IMREAD_GRAYSCALE);if (img.empty()) {std::cerr << "错误: 无法加载图像!" << std::endl;return -1;}// 计算图像一半宽度处列像素的方差double varianceH = 0.0;calculateVariance(img, "H", varianceH);std::cout << "图像一半宽度处列像素的方差: " << varianceH << std::endl;// 计算图像一半高度处行像素的方差double varianceV = 0.0;calculateVariance(img, "V", varianceV);std::cout << "图像一半高度处行像素的方差: " << varianceV << std::endl;return 0;
}
3 问题
3.1 入口参数const cv::Mat& img 和 const cv::Mat img区别
const cv::Mat& img:
传递的是图像的引用,不会复制图像数据,只是创建一个对原图像的引用。这在处理大图像时更加高效,因为避免了不必要的数据复制。const cv::Mat img:
传递的是图像的副本,函数内部将持有图像数据的一个拷贝。这会导致额外的内存开销和时间消耗,尤其是在图像很大的时候。