如何计算平均梯度方向和平均梯度强度/幅度

时间:2018-05-13 12:17:22

标签: opencv computer-vision

在OpenCV中,您如何计算Mat和平均梯度方向的平均梯度强度?

我通过谷歌搜索获得了以下方法,但我想在进入下一步之前确认我实际上已经这样做了。

这是对的吗?

Mat img = imread('foo.png', CV_8UC); // read image as grayscale single channel

// Calculate the mean intensity and the std deviation
// Any errors here or am I doing this correctly?
Scalar sMean, sStdDev;
meanStdDev(src, sMean, sStdDev);
double mean = sMean[0];
double stddev = sStdDev[0];


// Calculate the average gradient magnitude/strength across the image
// Any errors here or am I doing this correctly?
Mat dX, dY, magnitude;
Sobel(src, dX, CV_32F, 1, 0, 1);
Sobel(src, dY, CV_32F, 0, 1, 1);
magnitude(dX, dY, magnitude);

Scalar sMMean, sMStdDev;
meanStdDev(magnitude, sMMean, sMStdDev);
double magnitudeMean = sMMean[0];
double magnitudeStdDev = sMStdDev[0];


// Calculate the average gradient direction across the image
// Any errors here or am I doing this correctly?
Scalar avgHorizDir = mean(dX);
Scalar avgVertDir = mean(dY);
double avgDir = atan2(-avgVertDir[0], avgHorizDir[0]);


float blurriness = cv::videostab::calcBlurriness(src); // low values = sharper. High values = blurry

1 个答案:

答案 0 :(得分:2)

从技术上讲,这是获得两个平均值的正确方法。

计算平均方向的方式使用加权方向统计,这意味着没有强梯度的像素对平均值的影响较小。

然而,对于大多数图像而言,这个平均方向并不是很有意义,因为在所有方向都存在边缘并取消。

如果你的图像只有一个边缘,那么这将很有效。

如果您的图像中包含线条,包含相反方向的边缘,则无效。在这种情况下,您需要平均双倍角度(平均方向)。这样做的显而易见的方法是将每个像素的方向计算为一个角度,将它们加倍,然后使用方向统计来平均(即转换回矢量并平均那些)。加倍角度会导致相反的方向映射到相同的值,因此平均不会取消这些。

平均取向的另一种简单方法是取梯度场的外积与其自身获得的张量场的平均值,并确定对应于最大特征值的本征向量的方向。张量场如下获得:

Mat Sxx = dX * dX;
Mat Syy = dY * dY;
Mat Sxy = dX * dY;

然后应将其平均化:

Scalar mSxx = mean(sXX);
Scalar mSyy = mean(sYY);
Scalar mSxy = mean(sXY);

这些值形成2x2实值对称矩阵:

|  mSxx   mSxy  |
|  mSxy   mSyy  |

确定其特征分解是相对简单的,可以通过分析完成。我现在手边没有方程式,所以我会将它作为练习留给读者。 :)