当前位置: 首页 > wzjs >正文

临沂免费做网站优秀网站设计赏析

临沂免费做网站,优秀网站设计赏析,珠海市建设工程交易网,潍坊模板建站定制在 OpenCV (C) 中使用 Sobel 算子进行边缘检测 🔪 边缘检测是图像处理和计算机视觉中的一项基础技术。它旨在识别图像中亮度发生剧烈变化或更正式地说是存在不连续性的点。这些剧烈变化通常对应于图像中物体的边界。Sobel 算子是一种广泛使用的一阶离散微分算子&am…

在 OpenCV (C++) 中使用 Sobel 算子进行边缘检测 🔪

边缘检测是图像处理和计算机视觉中的一项基础技术。它旨在识别图像中亮度发生剧烈变化或更正式地说是存在不连续性的点。这些剧烈变化通常对应于图像中物体的边界。Sobel 算子是一种广泛使用的一阶离散微分算子,用于计算图像强度函数梯度的近似值。本文将指导您如何在 C++ 中使用 OpenCV 的 Sobel 算子进行边缘检测。


理解 Sobel 算子

Sobel 算子使用两个 3 × 3 3 \times 3 3×3 的卷积核来近似计算图像在 x x x 方向(水平变化)和 y y y 方向(垂直变化)的偏导数。这两个核分别是:

Sobel G x G_x Gx (用于检测垂直边缘):

G x = [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] G_x = \begin{bmatrix} -1 & 0 & +1 \\ -2 & 0 & +2 \\ -1 & 0 & +1 \end{bmatrix} Gx= 121000+1+2+1

Sobel G y G_y Gy (用于检测水平边缘):

G y = [ − 1 − 2 − 1 0 0 0 + 1 + 2 + 1 ] G_y = \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ +1 & +2 & +1 \end{bmatrix} Gy= 10+120+210+1

当这些核与图像进行卷积时,会产生两个梯度图像: G x ( I ) G_x(I) Gx(I) 代表水平梯度(对垂直边缘敏感), G y ( I ) G_y(I) Gy(I) 代表垂直梯度(对水平边缘敏感)。

每个像素点 ( x , y ) (x, y) (x,y) 的梯度幅值可以通过以下方式近似计算:

∣ G ( x , y ) ∣ = G x ( I ) 2 + G y ( I ) 2 |G(x, y)| = \sqrt{G_x(I)^2 + G_y(I)^2} G(x,y)=Gx(I)2+Gy(I)2

或者,为了计算效率,有时也使用绝对值之和:

∣ G ( x , y ) ∣ = ∣ G x ( I ) ∣ + ∣ G y ( I ) ∣ |G(x, y)| = |G_x(I)| + |G_y(I)| G(x,y)=Gx(I)+Gy(I)

梯度的方向(边缘的朝向)可以估算为:

Θ ( x , y ) = arctan ⁡ ( G y ( I ) G x ( I ) ) \Theta(x, y) = \arctan\left(\frac{G_y(I)}{G_x(I)}\right) Θ(x,y)=arctan(Gx(I)Gy(I))

高梯度幅值表示强烈的强度变化,暗示存在边缘。


在 OpenCV (C++) 中实现 Sobel 边缘检测

OpenCV 提供了 cv::Sobel() 函数,可以方便地将 Sobel 算子应用于图像。

步骤:

  1. 包含头文件:包含必要的 OpenCV 头文件:opencv2/imgproc.hpp (用于图像处理函数如 Sobel) 和 opencv2/highgui.hpp (用于图像显示)。
  2. 加载图像:读取输入图像。通常将图像转换为灰度图是个好主意,因为边缘检测通常基于强度变化。
  3. 高斯模糊 (可选但推荐):在应用 Sobel 算子之前,通常会先对图像进行高斯模糊处理,以减少噪声对边缘检测结果的干扰。可以使用 cv::GaussianBlur()
  4. 应用 Sobel 算子:使用 cv::Sobel() 函数两次:一次用于 x x x 方向,一次用于 y y y 方向。
    • 你需要指定源图像、输出图像、输出图像的深度(通常建议使用 CV_16SCV_32F 来处理导数可能产生的负值和更大的动态范围,之后再转换类型), x x x 方向的导数阶数 (dx),以及 y y y 方向的导数阶数 (dy)。对于标准的 Sobel, G x G_x Gx 对应 dx=1, dy=0 G y G_y Gy 对应 dx=0, dy=1
    • ksize 参数指定了 Sobel 核的大小 (例如, 3, 5, 7)。
  5. 计算梯度幅值: 为了得到一个单一的边缘图,你可以计算梯度幅值。
    • 方法一:分别计算 G x G_x Gx G y G_y Gy 的绝对值,然后按权重相加,例如使用 cv::convertScaleAbs() 分别处理 G x G_x Gx G y G_y Gy,然后用 cv::addWeighted() 合并。
    • 方法二:直接使用 G x G_x Gx G y G_y Gy (可能是 CV_16SCV_32F 类型) 计算精确的幅值,例如使用 cv::magnitude(grad_x, grad_y, abs_grad);,然后将结果转换为 CV_8U
  6. 转换到可显示类型: 如果你使用了 CV_16SCV_32F 作为输出深度,你可能需要将得到的梯度图像转换为 8 位无符号整数类型 (CV_8U) 以便显示,通常使用 cv::convertScaleAbs() 函数,它会取绝对值并缩放结果。
  7. 显示/保存结果: 显示原始图像和检测到的边缘。

C++ 代码示例

以下是一个使用 OpenCV 进行 Sobel 边缘检测的 C++ 代码片段:

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>int main(int argc, char** argv) {if (argc != 2) {std::cout << "用法: " << argv[0] << " <图片路径>" << std::endl;return -1;}// 1. 加载源图像cv::Mat src = cv::imread(argv[1], cv::IMREAD_COLOR);if (src.empty()) {std::cerr << "错误: 无法加载图像 " << argv[1] << std::endl;return -1;}// 2. 转换为灰度图cv::Mat gray;cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);// 3. 高斯模糊 (可选,但通常推荐用于降噪)cv::Mat blurred;cv::GaussianBlur(gray, blurred, cv::Size(3, 3), 0, 0, cv::BORDER_DEFAULT);// 4. 计算 X 方向和 Y 方向的梯度cv::Mat grad_x, grad_y;cv::Mat abs_grad_x, abs_grad_y;int scale = 1;int delta = 0;int ddepth = CV_16S; // 使用16位有符号类型,避免计算梯度时溢出int ksize = 3;       // Sobel核的大小// X方向梯度// cv::Sobel(src_gray, grad_x, ddepth, 1, 0, ksize, scale, delta, cv::BORDER_DEFAULT);cv::Sobel(blurred, grad_x, ddepth, 1, 0, ksize, scale, delta, cv::BORDER_DEFAULT);cv::convertScaleAbs(grad_x, abs_grad_x); // 计算绝对值并转换到8位无符号// Y方向梯度// cv::Sobel(src_gray, grad_y, ddepth, 0, 1, ksize, scale, delta, cv::BORDER_DEFAULT);cv::Sobel(blurred, grad_y, ddepth, 0, 1, ksize, scale, delta, cv::BORDER_DEFAULT);cv::convertScaleAbs(grad_y, abs_grad_y); // 计算绝对值并转换到8位无符号// 5. 合并梯度 (近似梯度幅值)cv::Mat grad;cv::addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);// 或者,更精确的梯度幅值计算:// cv::Mat grad_magnitude;// cv::magnitude(grad_x, grad_y, grad_magnitude); // grad_x, grad_y 应该是 CV_16S 或 CV_32F// cv::convertScaleAbs(grad_magnitude, grad);// 6. 显示结果cv::imshow("原始图像", src);cv::imshow("灰度图", gray);cv::imshow("Sobel X 梯度", abs_grad_x);cv::imshow("Sobel Y 梯度", abs_grad_y);cv::imshow("Sobel 合并梯度", grad);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

代码解释

  1. cv::imread(argv[1], cv::IMREAD_COLOR): 加载彩色图像。
  2. cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY): 将彩色图像转换为灰度图像,因为 Sobel 通常在单通道图像上操作。
  3. cv::GaussianBlur(gray, blurred, cv::Size(3,3), 0, 0, cv::BORDER_DEFAULT): 对灰度图像进行高斯模糊,以减少噪声。cv::Size(3,3) 是高斯核的大小。
  4. cv::Sobel(blurred, grad_x, ddepth, 1, 0, ksize, scale, delta, cv::BORDER_DEFAULT):
    • blurred: 输入图像 (推荐使用模糊后的图像)。
    • grad_x: 输出的 x x x 方向梯度图像。
    • ddepth: 输出图像的深度。CV_16S 用于存储可能为负的梯度值,并且范围比 CV_8U 更大,可以防止信息丢失。
    • 1: x x x 方向的导数阶数。
    • 0: y y y 方向的导数阶数。
    • ksize: Sobel 核的大小,通常为 3。也可以是 1, 5, 7。
    • scale: 可选的缩放因子,默认为1。
    • delta: 可选的增量值,在存储之前添加到结果中,默认为0。
    • cv::BORDER_DEFAULT: 边界处理方式。
      类似的参数用于计算 grad_y ( y y y 方向梯度),其中 dx=0, dy=1
  5. cv::convertScaleAbs(grad_x, abs_grad_x):
    • 此函数首先计算输入数组 (grad_x) 中每个元素的绝对值。
    • 然后将结果缩放(如果指定了 alphabeta,这里使用默认值 alpha=1, beta=0)。
    • 最后将结果转换为 8 位无符号类型 (CV_8U)。这对于显示梯度图像非常有用。
  6. cv::addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad):
    • 这是一种近似计算总梯度幅值的方法,通过将 x x x 方向和 y y y 方向梯度的绝对值按权重(这里是各0.5)相加。
    • 0.5abs_grad_x 的权重。
    • 0.5abs_grad_y 的权重。
    • 0 是加到和上的标量 (gamma)。
    • grad 是输出的合并梯度图像。
  7. cv::imshow()cv::waitKey(): 用于显示图像并等待用户按键。

或者,使用 cv::magnitude 计算精确梯度幅值
如果你想计算更精确的梯度幅值 G x 2 + G y 2 \sqrt{G_x^2 + G_y^2} Gx2+Gy2 ,可以这样做:

// ... 计算 grad_x 和 grad_y (类型为 CV_16S 或 CV_32F) ...
cv::Mat grad_magnitude;
cv::magnitude(grad_x, grad_y, grad_magnitude); // grad_x, grad_y 应该是 CV_16S 或 CV_32F 类型
cv::Mat final_grad;
cv::convertScaleAbs(grad_magnitude, final_grad); // 转换为 CV_8U 以便显示
cv::imshow("Sobel 精确梯度幅值", final_grad);

在这种情况下,grad_xgrad_y 应该是应用 cv::Sobel 后且未调用 cv::convertScaleAbs 时的结果(即 CV_16SCV_32F 类型)。


编译

要编译此 C++ 代码,你需要 g++ (或任何兼容 C++11 的编译器) 和已安装的 OpenCV。

g++ -o sobel_app sobel_edge_detection.cpp `pkg-config --cflags --libs opencv4` -std=c++11

(如果你的 OpenCV 版本较旧,或者 pkg-config 的设置不同,请使用 opencv 替换 opencv4)。

运行:

./sobel_app <你的图片路径.jpg>

总结

Sobel 算子是边缘检测中一种经典且有效的方法。通过分别计算图像在 x x x y y y 方向上的梯度,并将其组合起来,我们可以识别出图像中的边缘。OpenCV 提供了易于使用的函数来实现这一过程,使得开发者可以快速地在自己的应用中集成边缘检测功能。记住,在应用 Sobel 算子之前进行高斯模糊通常能获得更好的结果,因为它可以减少噪声的干扰。

http://www.dtcms.com/wzjs/64108.html

相关文章:

  • wordpress video模板整站优化
  • 网站建设教程论坛新闻稿件代发平台
  • app网站制作今日财经新闻
  • 电商网站功能列表厦门seo关键词优化
  • 视频网站的建设费用新网站seo外包
  • 珠海企业网站建设费用百度账号登录入口官网
  • 供应链软件系统寻找郑州网站优化公司
  • 绍兴网站定制公司怎么看app的下载网址
  • 电子商务网站策划方案百度竞价推广是什么意思
  • 单网站建设杭州seo搜索引擎优化公司
  • 有源码后怎么做网站促销活动推广语言
  • 网站页面设计的特色seo百度排名优化
  • 武汉网站开发首选千捷科技搜狗官网
  • 温州网站制作建设淘宝店铺推广方式有哪些
  • 个人网站首页布局图哈尔滨网络推广
  • 做网站时可以切换语言的在线网站建设平台
  • js音乐网站模板推特最新消息今天
  • 上海建网站开发公最近发生的新闻
  • 图片素材网站建设昆明网络推广公司排名
  • 辽宁建设工程信息网招标软件中央网站seo
  • 腾讯云 个人网站百度搜索广告怎么收费
  • 河北衡水建设网站公司网络营销推广有哪些方法
  • asp在线生成网站地图源代码网页设计模板网站
  • 重庆网站建设小能手今日热搜第一名
  • 大型网站开发框架金华网站建设
  • 微信网站开发用什么语言什么网站可以发布广告
  • 装修公司取名高端大气seoaoo
  • 没有网站想做个链接页面怎么做百度推广开户费用
  • 做外贸有哪些平台广州seo实战培训
  • 营利性网站的域名怎么做拍照搜索百度识图