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

c/c++的opencv霍夫变换

OpenCV中的霍夫变换 (C/C++) Hough Transform

霍夫变换 (Hough Transform) 是一种在图像分析中用于检测几何形状(如直线、圆形等)的特征提取技术。它通过一种投票机制在参数空间中寻找特定形状的实例。OpenCV 库为 C++ 开发者提供了强大且易用的霍夫变换函数。


1. 霍夫直线变换 (Hough Line Transform) 📏

霍夫直线变换用于检测图像中的直线。其基本思想是将图像空间中的点映射到参数空间(通常是极坐标 ( ρ , θ ) (\rho, \theta) (ρ,θ) 空间),并在参数空间中寻找峰值,这些峰值对应于图像空间中的直线。

直线方程: ρ = x cos ⁡ θ + y sin ⁡ θ \rho = x \cos\theta + y \sin\theta ρ=xcosθ+ysinθ
其中:

  • ρ \rho ρ (rho) 是从原点到直线的垂直距离。
  • θ \theta θ (theta) 是这条垂直线与 x 轴之间的角度。

1.1 标准霍夫变换 (Standard Hough Transform - SHT)

cv::HoughLines 函数实现了标准霍夫变换。它返回一个包含 ( ρ , θ ) (\rho, \theta) (ρ,θ) 对的向量。

函数原型:

void cv::HoughLines(cv::InputArray image,         // 输入图像 (必须是8位单通道二值图像,通常是Canny边缘检测的输出)cv::OutputArray lines,        // 输出向量,存储检测到的直线的参数 (cv::Vec2f 表示 rho 和 theta)double rho,                   // rho 的累加器分辨率 (以像素为单位)double theta,                 // theta 的累加器分辨率 (以弧度为单位)int threshold,                // 累加器阈值参数,只有累加值大于该阈值的直线才会被检测到double srn = 0,               // 对于多尺度霍夫变换,它是 rho 的除数。如果为0,则使用经典霍夫变换。double stn = 0,               // 对于多尺度霍夫变换,它是 theta 的除数。如果为0,则使用经典霍夫变换。double min_theta = 0,         // 检测直线的最小角度 (弧度)double max_theta = CV_PI      // 检测直线的最大角度 (弧度)
);

主要步骤:

  1. 边缘检测:通常使用 cv::Canny
  2. 应用 cv::HoughLines
  3. 遍历检测到的直线参数,并在原图上绘制。

示例代码:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>int main() {cv::Mat src = cv::imread("your_image_with_lines.png", cv::IMREAD_GRAYSCALE);if (src.empty()) {std::cerr << "Error: Could not load image." << std::endl;return -1;}cv::Mat edges;cv::Canny(src, edges, 50, 200, 3); // 1. 边缘检测std::vector<cv::Vec2f> lines; // (rho, theta)// 2. 标准霍夫变换cv::HoughLines(edges, lines, 1, CV_PI / 180, 150, 0, 0);cv::Mat color_dst;cv::cvtColor(edges, color_dst, cv::COLOR_GRAY2BGR); // 用于绘制彩色线条// 3. 绘制直线for (size_t i = 0; i < lines.size(); i++) {float rho = lines[i][0], theta = lines[i][1];cv::Point pt1, pt2;double a = cos(theta), b = sin(theta);double x0 = a * rho, y0 = b * rho;pt1.x = cvRound(x0 + 1000 * (-b));pt1.y = cvRound(y0 + 1000 * (a));pt2.x = cvRound(x0 - 1000 * (-b));pt2.y = cvRound(y0 - 1000 * (a));cv::line(color_dst, pt1, pt2, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);}cv::imshow("Source", src);cv::imshow("Detected Lines (Standard Hough)", color_dst);cv::waitKey(0);return 0;
}

1.2 概率霍夫变换 (Progressive Probabilistic Hough Transform - PPHT)

cv::HoughLinesP 函数实现了概率霍夫变换。它是一种更高效的霍夫变换,因为它只对图像中的一个随机子集点进行投票。它还直接返回检测到的线段的两个端点。

函数原型:

void cv::HoughLinesP(cv::InputArray image,         // 输入图像 (8位单通道二值图像)cv::OutputArray lines,        // 输出向量,存储检测到的线段的端点 (cv::Vec4i 表示 x1, y1, x2, y2)double rho,                   // rho 的累加器分辨率 (以像素为单位)double theta,                 // theta 的累加器分辨率 (以弧度为单位)int threshold,                // 累加器阈值参数double minLineLength = 0,     // 检测线段的最小长度double maxLineGap = 0         // 同一直线上两点之间的最大允许间隙,以将它们连接起来
);

主要步骤:

  1. 边缘检测:通常使用 cv::Canny
  2. 应用 cv::HoughLinesP
  3. 遍历检测到的线段端点,并在原图上绘制。

示例代码:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>int main() {cv::Mat src = cv::imread("your_image_with_lines.png", cv::IMREAD_COLOR);if (src.empty()) {std::cerr << "Error: Could not load image." << std::endl;return -1;}cv::Mat gray, edges;cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);cv::Canny(gray, edges, 50, 200, 3); // 1. 边缘检测std::vector<cv::Vec4i> linesP; // (x1, y1, x2, y2)// 2. 概率霍夫变换cv::HoughLinesP(edges, linesP, 1, CV_PI / 180, 80, 50, 10);// 3. 绘制线段for (size_t i = 0; i < linesP.size(); i++) {cv::Vec4i l = linesP[i];cv::line(src, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(0, 0, 255), 2, cv::LINE_AA);}cv::imshow("Source", gray); // 显示灰度图或原彩色图cv::imshow("Detected Lines (Probabilistic Hough)", src);cv::waitKey(0);return 0;
}

2. 霍夫圆变换 (Hough Circle Transform) ⭕

霍夫圆变换用于检测图像中的圆形。圆的方程是 ( x − a ) 2 + ( y − b ) 2 = r 2 (x-a)^2 + (y-b)^2 = r^2 (xa)2+(yb)2=r2,其中 ( a , b ) (a,b) (a,b) 是圆心, r r r 是半径。因此,参数空间是三维的。OpenCV 使用一种称为霍夫梯度法 (Hough Gradient Method) 的两阶段算法,它首先检测圆心,然后找到最佳半径。

函数原型:

void cv::HoughCircles(cv::InputArray image,         // 输入图像 (8位单通道灰度图像)cv::OutputArray circles,      // 输出向量,存储检测到的圆 (cv::Vec3f 表示 x, y, radius 或 cv::Vec4f x, y, radius, votes)int method,                   // 检测方法,目前仅支持 cv::HOUGH_GRADIENT 和 cv::HOUGH_GRADIENT_ALTdouble dp,                    // 累加器图像分辨率与输入图像分辨率的反比。例如,如果 dp=1,则累加器具有与输入图像相同的分辨率。如果 dp=2,累加器的宽度和高度只有一半。对于 HOUGH_GRADIENT_ALT,推荐值为 dp=1.5。double minDist,               // 检测到的圆心之间的最小距离。如果参数太小,除了真实的圆之外,可能还会错误地检测到多个邻近的圆。如果太大,可能会漏掉一些圆。double param1 = 100,          // Canny边缘检测器的高阈值 (低阈值是其一半)。对于 HOUGH_GRADIENT_ALT,这是推荐的霍夫变换累加器阈值。double param2 = 100,          // 圆心检测的累加器阈值。它越小,就越容易检测到假圆。对于 HOUGH_GRADIENT_ALT,这是圆的 "完美度" 度量。越接近1,检测到的圆形状越好。int minRadius = 0,            // 圆的最小半径int maxRadius = 0             // 圆的最大半径 (如果 <= 0, 则使用图像的最大维度;如果 < 0, 则返回圆心而不寻找半径)
);

注意: cv::HOUGH_GRADIENT_ALT 通常能提供更好的结果,但可能较慢。

主要步骤:

  1. 图像预处理:通常转换为灰度图,并进行平滑处理(如高斯模糊 cv::GaussianBlur 或中值滤波 cv::medianBlur)以减少噪声。
  2. 应用 cv::HoughCircles
  3. 遍历检测到的圆,并在原图上绘制。

示例代码:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>int main() {cv::Mat src = cv::imread("your_image_with_circles.png", cv::IMREAD_COLOR);if (src.empty()) {std::cerr << "Error: Could not load image." << std::endl;return -1;}cv::Mat gray;cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY); // 1. 转换为灰度图// 1. 平滑处理以减少噪声,避免错误检测cv::medianBlur(gray, gray, 5); // 中值滤波对于椒盐噪声效果好std::vector<cv::Vec3f> circles; // (x, y, radius)// 2. 霍夫圆变换// 参数需要根据具体图像进行仔细调整cv::HoughCircles(gray, circles, cv::HOUGH_GRADIENT,1,          // dp: 累加器分辨率与图像分辨率的反比gray.rows / 8, // minDist: 圆心之间的最小距离 (可调整)100,        // param1: Canny边缘检测的高阈值30,         // param2: 圆心累加器阈值 (值越小,检测到的圆越多,也可能包括假圆)10,         // minRadius: 最小半径100         // maxRadius: 最大半径 (根据你的图像调整));// 3. 绘制检测到的圆for (size_t i = 0; i < circles.size(); i++) {cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));int radius = cvRound(circles[i][2]);// 绘制圆心cv::circle(src, center, 3, cv::Scalar(0, 255, 0), -1, 8, 0);// 绘制圆轮廓cv::circle(src, center, radius, cv::Scalar(0, 0, 255), 2, 8, 0);}cv::imshow("Source", src); // 在原彩色图上绘制cv::imshow("Detected Circles", src);cv::waitKey(0);return 0;
}

3. 重要提示与技巧 💡

  • 参数调整:霍夫变换的参数(如 threshold, rho, theta, minDist, param1, param2, minRadius, maxRadius 等)对检测结果影响很大。通常需要根据具体的应用场景和图像特性进行仔细调整和实验。
  • 预处理
    • 对于直线检测cv::Canny 边缘检测是必不可少的步骤,其阈值也会影响最终结果。
    • 对于圆检测,适当的平滑处理(如 cv::medianBlurcv::GaussianBlur)有助于减少噪声,从而提高检测的准确性。
  • 图像质量:输入图像的质量直接影响霍夫变换的性能。清晰、对比度好的图像更容易获得好的检测结果。
  • 选择合适的变换类型
    • 如果需要检测到精确的线段端点并且关心效率,cv::HoughLinesP (概率霍夫变换) 通常是更好的选择。
    • 如果需要图像中所有可能的直线信息(参数形式),则使用 cv::HoughLines (标准霍夫变换)。
  • cv::HOUGH_GRADIENT_ALT:对于圆检测,可以尝试使用 method = cv::HOUGH_GRADIENT_ALT,它可能提供更鲁棒的检测结果,但其参数(特别是 param1param2)的含义与 cv::HOUGH_GRADIENT 不同,需要查阅文档并进行调整。

4. 总结 🚀

OpenCV 中的霍夫变换为直线和圆形的检测提供了强大而灵活的工具。理解其基本原理和各个参数的含义,结合适当的图像预处理,可以有效地在各种计算机视觉应用中识别这些基本几何形状。实践和参数调整是掌握霍夫变换的关键。

相关文章:

  • LLM 使用 MCP 协议及其原理详解
  • Glide NoResultEncoderAvailableException异常解决
  • 安装启动Mosquitto以及问题error: cjson/cJSON.h: No such file or directory解决
  • leetcode:7. 整数反转(python3解法,数学相关算法题)
  • Python学习(5) ----- Python的JSON处理
  • IDEA 在公司内网配置gitlab
  • 室内VR全景助力房产营销及装修
  • 敏捷开发在AI团队的适配研究
  • Android 开发 Kotlin 全局大喇叭与广播机制
  • STM32G4 电机外设篇(二) VOFA + ADC + OPAMP
  • 云原生DMZ架构实战:基于AWS CloudFormation的安全隔离区设计
  • Spring生命周期中织入代理逻辑
  • 数据在AI中扮演什么角色?为什么“数据是新的石油”?
  • 智慧景区一体化建设方案
  • Lyra学习笔记2 GFA_AddComponents与ULyraPlayerSpawningManagerComponent
  • 主流 AI IDE 之一的 Windsurf 使用入门
  • 修改Docker镜像源
  • 如何迁移SOS数据库和修改sos服务的端口号
  • Linux操作系统之进程(四):命令行参数与环境变量
  • mac mini m4命令行管理员密码设置
  • 没有logo可以做网站的设计吗/seo关键词排名优化怎样
  • 网站转移空间备案是不是就没有了/长春网站制作
  • 网站开发用户登录前 登录后/百度词条
  • 苏州做网站知识的分享/网站百度关键词排名软件
  • 网站如何做关/长沙百度提升排名
  • wordpress中文旅游模板下载/郑州seo管理