OpenCV基礎: 計算圖像的梯度幅值/角度/HOG特徵


摘要: 通過調用 magnitude / phase / cartToPolar, 分別實現梯度幅值/角度的單獨計算和同時計算, 並輸出/顯示. 需要說明的是, 示例函數可適用於三通道圖像, 但計算三通道圖像的梯度意義不大, 這裏限定爲單通道.


計算圖像差分

參考來源: OpenCV Tutorials: Sobel Derivatives

Sobel 算子

  • Sobel算子是高斯平滑和微分操作的結合體, 能夠更好的抗噪;
  • 使用擴展的Sobel算子可以計算一階,二階, 三階或混合圖像的差分;
  • x 方向指的是 Horizontal changes
  • y 方向指的是 Vertical changes
    x:[10+120+210+1],y:[121000+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}

Scharr 算子

  • Sobel 算子計算的差分的近似值. 當ksize=3時, 可能產生較明顯的誤差;
  • Scharr 算子是Sobel算子的優化. OpenCV中只能使用ksize=3, 速度一致, 但結果更準確.

x:[30+3100+1030+3],y:[3103000+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}

差分顯示

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);
    magnitude(dx, dy, value);
    // 顯示差分圖像, 包含負值, 需要轉換尺度
    convertScaleAbs(dx, dx);
    imshow("dx", dx);
    convertScaleAbs(dy, dy);
    imshow("dy", dy);
}

在這裏插入圖片描述

計算梯度幅值

  • 一般認爲, 梯度即爲梯度的幅值大小, 但爲了避免歧義, 這裏統稱梯度幅值, 梯度方向角
  • 計算公式如下:
    G=Gx2+Gy2 G = \sqrt{ G_{x}^{2} + G_{y}^{2} }
  • 代碼示例:
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);
}

在這裏插入圖片描述

計算梯度方向角

  • 計算公式如下:
    θ=arctanGyGx \theta = \arctan \frac{ G_y}{ G_x }
  • 代碼示例:
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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章