OpenCV基础: 计算图像的梯度幅值/角度/HOG特征
通过调用 magnitude / phase / cartToPolar, 分别实现梯度幅值/角度的单独计算和同时计算, 并输出/显示.
摘要: 通过调用 magnitude
/ phase
/ cartToPolar
, 分别实现梯度幅值/角度的单独计算和同时计算, 并输出/显示. 需要说明的是, 示例函数可适用于三通道图像, 但计算三通道图像的梯度意义不大, 这里限定为单通道.
计算图像差分
参考来源: OpenCV Tutorials: Sobel Derivatives
Sobel 算子
- Sobel算子是高斯平滑和微分操作的结合体, 能够更好的抗噪;
- 使用扩展的Sobel算子可以计算一阶,二阶, 三阶或混合图像的差分;
- x 方向指的是 Horizontal changes
- y 方向指的是 Vertical changes
x : [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] , y : [ − 1 − 2 − 1 0 0 0 + 1 + 2 + 1 ] x: \begin{bmatrix} -1 & 0 & +1 \\ -2 & 0 & +2 \\ -1 & 0 & +1 \end{bmatrix} , \qquad y: \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ +1 & +2 & +1 \end{bmatrix} x:⎣⎡−1−2−1000+1+2+1⎦⎤,y:⎣⎡−10+1−20+2−10+1⎦⎤
Scharr 算子
- Sobel 算子计算的差分的近似值. 当
ksize=3
时, 可能产生较明显的误差; - Scharr 算子是Sobel算子的优化. OpenCV中只能使用
ksize=3
, 速度一致, 但结果更准确.
x : [ − 3 0 + 3 − 10 0 + 10 − 3 0 + 3 ] , y : [ − 3 − 10 − 3 0 0 0 + 3 + 10 + 3 ] x: \begin{bmatrix} -3 & 0 & +3 \\ -10 & 0 & +10 \\ -3 & 0 & +3 \end{bmatrix} , \qquad y: \begin{bmatrix} -3 & -10 & -3 \\ 0 & 0 & 0 \\ +3 & +10 & +3 \end{bmatrix} x:⎣⎡−3−10−3000+3+10+3⎦⎤,y:⎣⎡−30+3−100+10−30+3⎦⎤
差分显示
void imshowDifferentiation(Mat img)
{
assert(img.channels() == 1);
Mat dx, dy, value;
Sobel(img, dx, CV_32F, 1, 0, 3);
Sobel(img, dy, CV_32F, 0, 1, 3);
// 显示差分图像, 包含负值, 需要转换尺度
convertScaleAbs(dx, dx);
imshow("dx", dx);
convertScaleAbs(dy, dy);
imshow("dy", dy);
}
计算梯度幅值 magnitude
- 一般认为, 梯度即为梯度的幅值大小, 但为了避免歧义, 这里统称
梯度幅值
,梯度方向角
- 计算公式如下:
G = G x 2 + G y 2 G = \sqrt{ G_{x}^{2} + G_{y}^{2} } G=Gx2+Gy2 - 代码示例:
void calculateGradientValue(Mat img)
{
assert(img.channels() == 1);
Mat dx, dy, value;
Sobel(img, dx, CV_32F, 1, 0, 3);
Sobel(img, dy, CV_32F, 0, 1, 3);
magnitude(dx, dy, value);
// 显示梯度幅值图像
value.convertTo(value, CV_8U, 1);
imshow("magnitude", value);
}
计算梯度方向角 phase
- 计算公式如下:
θ = arctan G y G x \theta = \arctan \frac{ G_y}{ G_x } θ=arctanGxGy - 代码示例:
void calculateGradienAngle(Mat img)
{
assert(img.channels() == 1);
Mat dx, dy, angle;
Sobel(img, dx, CV_32F, 1, 0, 3);
Sobel(img, dy, CV_32F, 0, 1, 3);
// 计算梯度角度(弧度制)
phase(dx, dy, angle);
cout << "梯度方向角(弧度制): " << angle(Rect(0, 0, 10, 1)) << endl;
// 计算梯度角度(角度制)
phase(dx, dy, angle, true);
cout << "梯度方向角(角度制): " << angle(Rect(0, 0, 10, 1)) << endl;
}
同时计算梯度幅值和方向角
void calculateGradient(Mat img)
{
assert(img.channels() == 1);
Mat dx, dy, value, angle;
Sobel(img, dx, CV_32F, 1, 0, 3);
Sobel(img, dy, CV_32F, 0, 1, 3);
// 计算梯度幅值和角度(弧度制)
cartToPolar(dx, dy, value, angle);
cout << "梯度方向角(弧度制): " << angle(Rect(0, 0, 10, 1)) << endl;
// 计算梯度幅值和角度(角度制)
cartToPolar(dx, dy, value, angle, true);
cout << "梯度方向角(角度制): " << angle(Rect(0, 0, 10, 1)) << endl;
// 显示梯度幅值图像
value.convertTo(value, CV_32F, 1. / 255);
imshow("cartToPolar", value);
}
HOG特征
限于篇幅,请访问 https://blog.csdn.net/Augurlee/article/details/105034336
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)