欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++的OpenCV 進(jìn)行圖像梯度提取的幾種實(shí)現(xiàn)

 更新時(shí)間:2025年05月31日 10:07:43   作者:whoarethenext  
本文主要介紹了C/C++的OpenCV 進(jìn)行圖像梯度提取的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

圖像梯度表示圖像中像素強(qiáng)度的變化率和方向。它是圖像分析中的一個(gè)基本概念,廣泛應(yīng)用于邊緣檢測(cè)、特征提取和物體識(shí)別等任務(wù)。OpenCV 提供了多種計(jì)算圖像梯度的函數(shù)。本文將介紹幾種常用的梯度算子及其在 C++/OpenCV 中的實(shí)現(xiàn)。

預(yù)備知識(shí)

在開始之前,請(qǐng)確保您已經(jīng)安裝了 OpenCV,并且您的 C++ 開發(fā)環(huán)境已經(jīng)配置好可以鏈接 OpenCV 庫。

通常,我們需要包含以下頭文件:

#include <opencv2/opencv.hpp> // 包含所有核心和contrib模塊
#include <iostream>

為方便起見,我們也會(huì)使用 cv 命名空間:

using namespace cv;
using namespace std;

1. 圖像加載與預(yù)處理

梯度計(jì)算通常在灰度圖像上進(jìn)行,因?yàn)轭伾畔?duì)于梯度方向的確定可能會(huì)引入不必要的復(fù)雜性。

int main(int argc, char** argv) {
    // 1. 加載圖像
    // const char* filename = argc >= 2 ? argv[1] : "lena.jpg"; // 從命令行參數(shù)或默認(rèn)讀取
    Mat src = imread("your_image.jpg", IMREAD_COLOR); // 請(qǐng)?zhí)鎿Q為您的圖片路徑
    if (src.empty()) {
        cout << "無法加載圖像: " << "your_image.jpg" << endl;
        return -1;
    }

    // 2. 轉(zhuǎn)換為灰度圖
    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);

    // 3. (可選)高斯模糊以減少噪聲,從而獲得更清晰的梯度
    Mat blurred_gray;
    GaussianBlur(gray, blurred_gray, Size(3, 3), 0, 0, BORDER_DEFAULT);

    // 接下來我們將對(duì) blurred_gray 或 gray 進(jìn)行操作

2. Sobel 算子

Sobel 算子是一種離散的一階微分算子,用于計(jì)算圖像亮度函數(shù)梯度的近似值。它結(jié)合了高斯平滑和微分求導(dǎo)。Sobel 算子分別計(jì)算水平方向(Gx)和垂直方向(Gy)的梯度。

cv::Sobel 函數(shù)原型:

void Sobel( InputArray src, OutputArray dst, int ddepth,
            int dx, int dy, int ksize = 3,
            double scale = 1, double delta = 0,
            int borderType = BORDER_DEFAULT );
  • src: 輸入圖像。
  • dst: 輸出圖像,與輸入圖像大小和通道數(shù)相同。
  • ddepth: 輸出圖像的深度。由于梯度值可能為負(fù),通常使用 CV_16S 或 CV_32F 以避免信息丟失。然后通過 cv::convertScaleAbs 轉(zhuǎn)換為 CV_8U 進(jìn)行顯示。
  • dx: x 方向上的差分階數(shù) (0 或 1)。
  • dy: y 方向上的差分階數(shù) (0 或 1)。
  • ksize: Sobel 核的大小,必須是 1, 3, 5 或 7。
  • scale: 可選的計(jì)算出的導(dǎo)數(shù)值的縮放因子。
  • delta: 可選的增量,在將結(jié)果存儲(chǔ)到 dst 之前添加到結(jié)果中。
  • borderType: 像素外插方法。

計(jì)算 X 和 Y 方向的梯度

    // ... 接上文 blurred_gray

    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;

    // 計(jì)算 X 方向梯度
    // ddepth = CV_16S ???????????????????????? (overflow)
    Sobel(blurred_gray, grad_x, CV_16S, 1, 0, 3, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(grad_x, abs_grad_x); // 轉(zhuǎn)換回 CV_8U 并取絕對(duì)值

    // 計(jì)算 Y 方向梯度
    Sobel(blurred_gray, grad_y, CV_16S, 0, 1, 3, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(grad_y, abs_grad_y);

    // 顯示 X 和 Y 方向的梯度
    imshow("Sobel X Gradient", abs_grad_x);
    imshow("Sobel Y Gradient", abs_grad_y);

合并梯度

通常,我們將 X 和 Y 方向的梯度組合起來得到總的梯度幅值。一個(gè)常見的方法是使用 cv::addWeighted

G = α ⋅ ∣ G x ∣ + β ⋅ ∣ G y ∣ + γ G = \alpha \cdot |G_x| + \beta \cdot |G_y| + \gammaG=α⋅∣Gx?∣+β⋅∣Gy?∣+γ

或者直接計(jì)算幅值 G = G x 2 + G y 2 G = \sqrt{G_x^2 + G_y^2}G=Gx2?+Gy2??。cv::addWeighted 提供了一種近似方法。

    Mat grad_combined;
    // 近似梯度幅值 (權(quán)重可以調(diào)整,這里簡(jiǎn)單相加)
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad_combined);
    imshow("Sobel Combined Gradient", grad_combined);

更精確的幅值計(jì)算通常需要 grad_x 和 grad_y 為 CV_32F 類型,然后使用 cv::magnitude

    Mat grad_x_f, grad_y_f;
    Sobel(blurred_gray, grad_x_f, CV_32F, 1, 0, 3);
    Sobel(blurred_gray, grad_y_f, CV_32F, 0, 1, 3);

    Mat magnitude, angle;
    cartToPolar(grad_x_f, grad_y_f, magnitude, angle, true); // angle in degrees
    
    Mat abs_magnitude;
    convertScaleAbs(magnitude, abs_magnitude);
    imshow("Sobel Magnitude Precise", abs_magnitude);

3. Scharr 算子

Scharr 算子是對(duì) Sobel 算子在核大小為 3x3 時(shí)的一種優(yōu)化。它具有更好的旋轉(zhuǎn)對(duì)稱性,因此在某些情況下可以提供比 3x3 Sobel 算子更準(zhǔn)確的結(jié)果。

cv::Scharr 函數(shù)原型與 cv::Sobel 類似,但它沒有 ksize 參數(shù),因?yàn)?Scharr 算子總是使用固定的 3x3 核。當(dāng) dx=1, dy=0 或 dx=0, dy=1 時(shí)使用。

void Scharr( InputArray src, OutputArray dst, int ddepth,
             int dx, int dy, double scale = 1, double delta = 0,
             int borderType = BORDER_DEFAULT );

使用方法與 Sobel 類似:

    // ... 接上文 blurred_gray

    Mat scharr_grad_x, scharr_grad_y;
    Mat abs_scharr_grad_x, abs_scharr_grad_y;

    // 計(jì)算 X 方向 Scharr 梯度
    Scharr(blurred_gray, scharr_grad_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(scharr_grad_x, abs_scharr_grad_x);

    // 計(jì)算 Y 方向 Scharr 梯度
    Scharr(blurred_gray, scharr_grad_y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(scharr_grad_y, abs_scharr_grad_y);

    // 顯示 Scharr 梯度
    imshow("Scharr X Gradient", abs_scharr_grad_x);
    imshow("Scharr Y Gradient", abs_scharr_grad_y);

    Mat scharr_grad_combined;
    addWeighted(abs_scharr_grad_x, 0.5, abs_scharr_grad_y, 0.5, 0, scharr_grad_combined);
    imshow("Scharr Combined Gradient", scharr_grad_combined);

4. Laplacian 算子

Laplacian (拉普拉斯) 算子是一種二階微分算子,它計(jì)算圖像的二階導(dǎo)數(shù)。它可以用來檢測(cè)邊緣,對(duì)噪聲比較敏感。Laplacian 算子通常通過檢測(cè)圖像中的零交叉點(diǎn)來定位邊緣。

cv::Laplacian 函數(shù)原型:

void Laplacian( InputArray src, OutputArray dst, int ddepth,
                int ksize = 1, double scale = 1, double delta = 0,
                int borderType = BORDER_DEFAULT );
  • ksize: 拉普拉斯核的大小,必須是正奇數(shù)。通常是 1 或 3。
    // ... 接上文 blurred_gray

    Mat laplacian_dst;
    Mat abs_laplacian_dst;

    Laplacian(blurred_gray, laplacian_dst, CV_16S, 3, 1, 0, BORDER_DEFAULT); // ksize=3
    convertScaleAbs(laplacian_dst, abs_laplacian_dst);

    imshow("Laplacian Operator", abs_laplacian_dst);

由于拉普拉斯算子是二階導(dǎo)數(shù),它的結(jié)果中正值和負(fù)值都有意義(表示亮度的快速變化)。convertScaleAbs 將這些值轉(zhuǎn)換為適合顯示的 8 位無符號(hào)整數(shù)。

5. 顯示結(jié)果與程序結(jié)束

在 main 函數(shù)的末尾,添加等待按鍵和關(guān)閉窗口的調(diào)用:

    // ... 所有 imshow 調(diào)用之后
    cout << "按任意鍵退出..." << endl;
    waitKey(0);
    destroyAllWindows();
    return 0;
}

完整示例代碼

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char** argv) {
    // 1. 加載圖像
    const char* filename = "your_image.jpg"; // 請(qǐng)?zhí)鎿Q為您的圖片路徑
    Mat src = imread(filename, IMREAD_COLOR);
    if (src.empty()) {
        cout << "無法加載圖像: " << filename << endl;
        return -1;
    }
    imshow("Original Image", src);

    // 2. 轉(zhuǎn)換為灰度圖
    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    imshow("Grayscale Image", gray);

    // 3. (可選)高斯模糊以減少噪聲
    Mat blurred_gray;
    GaussianBlur(gray, blurred_gray, Size(3, 3), 0, 0, BORDER_DEFAULT);
    imshow("Blurred Grayscale", blurred_gray);

    // --- Sobel 梯度 ---
    Mat grad_x_sobel, grad_y_sobel;
    Mat abs_grad_x_sobel, abs_grad_y_sobel;
    Mat grad_combined_sobel;

    Sobel(blurred_gray, grad_x_sobel, CV_16S, 1, 0, 3, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(grad_x_sobel, abs_grad_x_sobel);

    Sobel(blurred_gray, grad_y_sobel, CV_16S, 0, 1, 3, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(grad_y_sobel, abs_grad_y_sobel);

    addWeighted(abs_grad_x_sobel, 0.5, abs_grad_y_sobel, 0.5, 0, grad_combined_sobel);

    imshow("Sobel X Gradient", abs_grad_x_sobel);
    imshow("Sobel Y Gradient", abs_grad_y_sobel);
    imshow("Sobel Combined Gradient", grad_combined_sobel);
    
    // --- Scharr 梯度 ---
    Mat grad_x_scharr, grad_y_scharr;
    Mat abs_grad_x_scharr, abs_grad_y_scharr;
    Mat grad_combined_scharr;

    Scharr(blurred_gray, grad_x_scharr, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(grad_x_scharr, abs_grad_x_scharr);

    Scharr(blurred_gray, grad_y_scharr, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(grad_y_scharr, abs_grad_y_scharr);
    
    addWeighted(abs_grad_x_scharr, 0.5, abs_grad_y_scharr, 0.5, 0, grad_combined_scharr);

    imshow("Scharr X Gradient", abs_grad_x_scharr);
    imshow("Scharr Y Gradient", abs_grad_y_scharr);
    imshow("Scharr Combined Gradient", grad_combined_scharr);

    // --- Laplacian 梯度 ---
    Mat laplacian_dst;
    Mat abs_laplacian_dst;

    Laplacian(blurred_gray, laplacian_dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(laplacian_dst, abs_laplacian_dst);
    imshow("Laplacian Operator", abs_laplacian_dst);

    cout << "按任意鍵退出..." << endl;
    waitKey(0);
    destroyAllWindows();

    return 0;
}

編譯與運(yùn)行

假設(shè)您已正確安裝 OpenCV,可以使用 g++ 編譯上述代碼:

g++ your_code_file.cpp -o gradient_extraction $(pkg-config --cflags --libs opencv4)
./gradient_extraction your_image.jpg

(如果 pkg-config --libs opencv4 不起作用,請(qǐng)根據(jù)您的 OpenCV 版本和安裝方式調(diào)整鏈接器標(biāo)志,例如 opencv 或特定模塊如 opencv_core opencv_imgproc opencv_highgui opencv_imgcodecs)

總結(jié)

圖像梯度是圖像處理中的重要工具。Sobel、Scharr 和 Laplacian 算子是 OpenCV 中用于計(jì)算梯度的常用方法。

  • Sobel 是最常用的,提供 x 和 y 方向的梯度。
  • Scharr 在 3x3 核上通常比 Sobel 更精確。
  • Laplacian 是二階導(dǎo)數(shù),對(duì)噪聲敏感,但可以直接給出邊緣信息。

選擇哪種算子取決于具體的應(yīng)用需求和圖像特性。通常,在計(jì)算梯度之前進(jìn)行高斯模糊可以幫助減少噪聲對(duì)結(jié)果的影響。同時(shí),注意輸出圖像深度 (ddepth) 的選擇,以避免梯度計(jì)算過程中的信息丟失,后續(xù)再通過 convertScaleAbs 轉(zhuǎn)換到適合顯示的 CV_8U 格式。

到此這篇關(guān)于C/C++的OpenCV 進(jìn)行圖像梯度提取的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)OpenCV 圖像梯度提取內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++單例模式為何要實(shí)例化一個(gè)對(duì)象不全部使用static

    C++單例模式為何要實(shí)例化一個(gè)對(duì)象不全部使用static

    這篇文章主要介紹了C++單例模式為何要實(shí)例化一個(gè)對(duì)象不全部使用static,文基于C++圍繞主題展開詳細(xì)內(nèi)容,需要的小伙伴可以參考一下
    2022-05-05
  • 深入const int *p與int * const p的區(qū)別詳解(常量指針與指向常量的指針)

    深入const int *p與int * const p的區(qū)別詳解(常量指針與指向常量的指針)

    本篇文章是對(duì)const int *p與int * const p的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • 詳解C++中的const和constexpr

    詳解C++中的const和constexpr

    這篇文章主要為大家介紹了C++中的const和constexpr ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • Qt?QString的使用實(shí)現(xiàn)

    Qt?QString的使用實(shí)現(xiàn)

    本文主要介紹了Qt?QString的使用實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • C++實(shí)現(xiàn)順序排序算法簡(jiǎn)單示例代碼

    C++實(shí)現(xiàn)順序排序算法簡(jiǎn)單示例代碼

    這篇文章主要介紹了C++實(shí)現(xiàn)順序排序算法簡(jiǎn)單示例代碼,對(duì)于學(xué)過C++的朋友一定不會(huì)陌生,現(xiàn)在重溫一下這個(gè)算法,需要的朋友可以參考下
    2014-08-08
  • C++小知識(shí):大于0并不意味著等于1

    C++小知識(shí):大于0并不意味著等于1

    今天小編就為大家分享一篇關(guān)于C++小知識(shí):大于0并不意味著等于1,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • C語言中的運(yùn)算符優(yōu)先級(jí)和結(jié)合性一覽表

    C語言中的運(yùn)算符優(yōu)先級(jí)和結(jié)合性一覽表

    這篇文章主要介紹了C語言中的運(yùn)算符優(yōu)先級(jí)和結(jié)合性一覽表,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C++類和對(duì)象基礎(chǔ)詳解

    C++類和對(duì)象基礎(chǔ)詳解

    類是創(chuàng)建對(duì)象的模板,一個(gè)類可以創(chuàng)建多個(gè)對(duì)象,每個(gè)對(duì)象都是類類型的一個(gè)變量;創(chuàng)建對(duì)象的過程也叫類的實(shí)例化。每個(gè)對(duì)象都是類的一個(gè)具體實(shí)例(Instance),擁有類的成員變量和成員函數(shù)
    2021-08-08
  • C++實(shí)現(xiàn)LeetCode(85.最大矩形)

    C++實(shí)現(xiàn)LeetCode(85.最大矩形)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(85.最大矩形),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • c# 實(shí)現(xiàn)獲取漢字十六進(jìn)制Unicode編碼字符串的實(shí)例

    c# 實(shí)現(xiàn)獲取漢字十六進(jìn)制Unicode編碼字符串的實(shí)例

    下面小編就為大家?guī)硪黄猚# 實(shí)現(xiàn)獲取漢字十六進(jìn)制Unicode編碼字符串的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01

最新評(píng)論