opencv(17)---霍夫变换以及应用

本文详细介绍霍夫变换在图像处理中的应用,包括霍夫线变换、霍夫圆变换等技术,并提供OpenCV实现代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本概念

  • 霍夫变换(Hough Transform)是图像处理中的一种特征提取技术, 该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换的结果。

  • 霍夫变换在OpenCV中主要分两种:
    霍夫线变换—检测直线(线段)
    霍夫圆变换—检测圆

  • 用到的函数:
    HoughLines()—标准霍夫变换、多尺度霍夫变换
    HoughLinesP()—累计概率霍夫变换
    HoughCricles()—霍夫圆变换

霍夫线变换

基本概念

霍夫线变换是一种寻找直线的方法, 一般在使用霍夫变换前首先将图像进行边缘检测处理, 一般霍夫变换的输入为边缘二值图。

OpenCV支持三种不同的霍夫线变换

  • 标准霍夫变换(SHT)
  • 多尺度霍夫变换(MSHT)——是SHT在多尺度下的一个变种
  • 累计概率霍夫变换(PPHT)——是SHT的改进, 在一定范围内进行霍夫变换(减少 计算时间和运算量)

使用函数对应关系

  • 标准霍夫变换(SHT)——HoughLines()函数
  • 多尺度霍夫变换(MSHT)——HoughLines()函数
  • 累计概率霍夫变换(PPHT)——HoughLinesP()函数

原理

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

霍夫线变换__标准霍夫变换—HoughLines()

函数原型

void HoughLines( InputArray image, OutputArray lines,
                 double rho, double theta, int threshold,
                 double srn = 0, double stn = 0,
                 double min_theta = 0, double max_theta = CV_PI );
  • src: 输入原图像(一般为8位单通道二值图像)
  • lines: 经过霍夫变换后检测线条的输出矢量, 每一条线由两个元素的矢量(ρ, Θ)表示, 其中ρ是离坐标原点的距离, Θ是弧度线条旋转角度(0表示垂直线, π/2度表示水平线)
  • rho: 以像素为单位的距离精度, 另一种表述方式是直线搜索时的进步尺寸的单位半径
  • theta: 以弧度为单位的角度精度, 另一种表述方式是直线搜索时的进步尺寸的角度单位
  • threshold: 累加平面的阈值参数, 即识别某部分为一条直线时它在累加平面中必须达到的值, 大于阈值threshold的线段才可以被检测通过并返回到结果中
  • srn: 默认值0, 对于多尺度的霍夫变换, 这是第三个参数进步尺寸rho的除数距离
  • stn: 默认值0, 对于多尺度霍夫变换, 表示单位角度theta
  • @param min_theta For standard and multi-scale Hough transform, minimum angle to check for lines.
    Must fall between 0 and max_theta.
  • @param max_theta For standard and multi-scale Hough transform, maximum angle to check for lines.
    Must fall between min_theta and CV_PI.

代码

  Mat cannyImg;
    Mat src = imread("D:\\1.png");
    Mat dstImg = src.clone();
    imshow("src", src);

    //将图像转为灰度图
    cvtColor(src, src, CV_BGR2GRAY);
    //边缘检测
    Canny(src, cannyImg, 50, 200, 3);
    imshow("Canny", cannyImg);
    //定义矢量结构lines用于存放得到的线段矢量集合
    vector<Vec2f> lines;
    //霍夫变换
    HoughLines(cannyImg, lines, 1, CV_PI/180, 150, 0, 0);

    //lines上有很多条线,线的个数为lines.size()
    for(size_t i = 0; i<lines.size(); i++)
    {
        float rho = lines[i][0], theta = lines[i][1];
        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));
        line(dstImg, pt1, pt2, Scalar(0, 0, 255), 1, CV_AA);
    }
    imshow("dst", dstImg);

    waitKey(0);
    destroyAllWindows();

运行结果

这里写图片描述

这里写图片描述

这里写图片描述

霍夫线变换__累计概率霍夫变换—HoughLinesP()

函数原型

void HoughLinesP( InputArray image, OutputArray lines,
                  double rho, double theta, int threshold,
                  double minLineLength = 0, double maxLineGap = 0 );
  • src: 输入原图像(一般为8位单通道二值图像)
  • lines: 经过霍夫变换后检测线条的输出矢量, 每一条线由4个元素矢量(x_1,y_1,x_2,y_2)表示, 其中(x_1,y_1)和(x_2,y_2)是检测到线段的结束点
    rho: 以像素为单位的距离精度, 另一种表述方式是直线搜索时的进步尺寸的单位半径
  • theta: 以弧度为单位的角度精度, 另一种表述方式是直线搜索时的进步尺寸的角度单位
  • threshold: 累加平面的阈值参数, 即识别某部分为一条直线时它在累加平面中必须达到的值, 大于阈值threshold的线段才可以被检测通过并返回到结果中
  • minLineLength: 默认值0, 表示最低线段的长度, 小于则不显示
  • maxLineGap: 默认值0, 允许将同一行点与点之间连接起来的最大距离

代码

Mat cannyImg;
Mat src = imread("D:\\B.jpg");
Mat dstImg = src.clone();
imshow("src", src);

cvtColor(src, src, CV_BGR2GRAY);
Canny(src, cannyImg, 50, 200, 3);
vector<Vec4i> lines;  //定义矢量结构lines用于存放得到的线段矢量集合
HoughLinesP(cannyImg, lines, 1, CV_PI/180, 150, 50, 10);

for(size_t i = 0; i<lines.size(); i++)
{
   Vec4i l = lines[i];
   line(dstImg, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 255, 0), 2, CV_AA);
}
imshow("dst", dstImg);
waitKey(0);
destroyAllWindows();

运行结果

这里写图片描述

这里写图片描述

霍夫圆变换

霍夫圆变换的基本原理和霍夫线变换大体上类似, 只是点对应的二维极径极角空间被三维的圆心点x, y和半径r空间取代, 如果用完全一样的方法运算量较大, 运行速度较慢, 所以采用“霍夫梯度法”来做圆变换。

原理

这里写图片描述

霍夫梯度法的缺点

  1. 可能在输出结果中产生噪声
  2. 如果累加器阈值设置较低, 算法需要较长时间, 每一个中心只选择一个圆, 对于同心圆只选择一个
  3. 如果新的中心很接近已接受的中心, 则不会被保留下来

函数原型

HoughCircles( InputArray image, OutputArray circles,
              int method, double dp, double minDist,
              double param1 = 100, double param2 = 100,
              int minRadius = 0, int maxRadius = 0 );
  1. src: 输入原图像(一般为8位单通道图像)

  2. circles: 经过霍夫变换后检测圆的输出矢量, 每个矢量包含三个元素的浮点矢量(x, y, radius)

  3. dp: 用来检测圆心的累加器图像的分辨率与输入图像之比的倒数, 且此参数允许创建一个比输入图像分辨率低的累加器。
    dp=1, 累加器和输入如下具有相同分辨率;
    dp=2, 累加器只有输入图像一半大的宽度和高度

  4. minDist: 霍夫变换检测到圆的圆心之间的最小距离, 分辨两个不同圆

  5. param1: 默认值100, 它是第三个参数method设置的对应参数, 表示传递给Canny边缘算子的高阈值, 低阈值是高阈值的一半

  6. param2: 默认值100,它是第三个参数method设置的对应参数, 表示检测阶段圆心累加器阈值, 越小, 则会检测到越多不存在的圆, 越大, 更多真正的圆被检测到

  7. minRadius/maxRadius: 表示圆半径的最小值/最大值

代码

Mat src = imread("D:\\2.png");
Mat dst = src.clone();
imshow("src", src);

cvtColor(src, src, CV_BGR2GRAY);
GaussianBlur(src, src, Size(9, 9), 2, 2);

vector<Vec3f> circles;
HoughCircles(src, circles, CV_HOUGH_GRADIENT, 2, 30, 200, 100, 10, 200);
for(size_t i = 0; i<circles.size(); i++)
{
     Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
     int radius = cvRound(circles[i][2]);
     circle(dst, center, 3, Scalar(0, 0, 255), -1, 8, 0);
     circle(dst, center, radius, Scalar(0, 255, 0), 3, 8, 0);
}
imshow("dst", dst);
waitKey(0);

运行结果

这里写图片描述

这里写图片描述

应用

1.角点检测:检测四边形
2.直线:检测车道
3.圆:交通灯检测

<think>好的,用户想用OpenCV-Python实现霍夫变换来检测图像中的矩形。首先,我需要回忆一下霍夫变换的相关知识。霍夫变换通常用于检测直线和圆形,检测矩形可能需要结合直线检测和一些后处理步骤。 用户提供的参考内容里提到了轮廓检测和直线检测,比如使用cv2.findContours和cv2.HoughLines。这可能对解决问题有帮助。首先,应该考虑图像预处理,比如灰度化、边缘检测。Canny边缘检测是常用的方法,参考内容里也有提到。 接下来,使用霍夫直线检测来找到图像中的直线。OpenCV的HoughLines或HoughLinesP函数可以检测直线,其中HoughLinesP是概率霍夫变换,效率更高,适合实时应用。检测到直线后,需要将这些直线组合成矩形。这可能需要计算直线的交点,或者寻找四边形的轮廓。 不过,用户提到的是检测矩形,或许另一种方法是先检测所有轮廓,然后筛选出四边形的轮廓,并进一步验证其是否为矩形。参考内容中的cv2.findContours和轮廓近似方法可能适用。比如,使用cv2.approxPolyDP来近似轮廓,如果近似后的轮廓有四个顶点,且角度接近直角,则可以认为是矩形。 需要结合两种方法:霍夫变换检测直线,然后找出四条直线形成矩形;或者使用轮廓检测直接找四边形。用户明确提到霍夫变换,所以可能需要优先考虑直线检测的方法。但霍夫变换检测直线后如何组合成矩形,这可能需要计算直线的交点和角度,找出相互垂直且闭合的四边形。 同时,注意图像预处理的重要性,比如降噪、二值化等,参考内容里提到使用二值化来提取硬币轮廓,可能同样适用于矩形检测。此外,处理后的边缘图像质量直接影响霍夫变换的效果。 然后,编写代码步骤可能包括:读取图像,转为灰度,高斯模糊,Canny边缘检测,霍夫变换检测直线,处理直线数据,寻找四个边组成矩形,绘制结果。或者,检测所有直线后,通过筛选水平和垂直的直线,再组合成矩形。 需要注意的是,霍夫变换可能会检测到很多直线,如何筛选出构成矩形的四条是一个挑战。可能需要计算直线之间的交点和角度关系,或者使用其他几何条件来过滤。 另外,用户提供的引用中提到cv.RETR_EXTERNAL和轮廓填充,这可能与轮廓检测方法相关。如果使用轮廓检测,步骤可能更简单:找到轮廓,近似多边形,筛选四个点的轮廓,计算角度是否为直角,面积是否足够大等。 不过用户明确要求使用霍夫变换,所以可能需要将两种方法结合,比如用霍夫检测直线,然后找到四个直线形成矩形,或者用霍夫检测矩形的方法。不过OpenCV中是否有直接的霍夫矩形检测函数?我记得HoughLines和HoughLinesP主要用于直线,而矩形检测可能需要其他处理。 综合以上思考,解决方案可能是:预处理图像,检测边缘,使用霍夫变换检测直线,然后通过直线之间的几何关系筛选出可能的矩形边,最后验证并绘制矩形。或者,检测直线后,寻找闭合的四边形。 现在需要将这些步骤转化为具体的代码示例,并确保正确引用用户提供的参考资料中的方法,比如使用cv2.findContours中的参数,或者边缘检测的处理步骤。同时,注意回答的结构,按照用户的要求,分步骤说明,并生成相关问题。</think>以下是用OpenCV-Python实现霍夫变换检测矩形的分步说明: ### 霍夫变换检测矩形步骤 1. **图像预处理** ```python import cv2 import numpy as np # 读取图像并转为灰度 img = cv2.imread('rect.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 高斯模糊降噪 blur = cv2.GaussianBlur(gray, (5,5), 0) # Canny边缘检测(参数根据实际情况调整) edges = cv2.Canny(blur, 50, 150) ``` 2. **霍夫直线检测** ```python # 概率霍夫变换检测直线 lines = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180, threshold=50, minLineLength=50, maxLineGap=10) # 绘制所有检测到的直线 if lines is not None: for line in lines: x1,y1,x2,y2 = line[0] cv2.line(img, (x1,y1), (x2,y2), (0,255,0), 2) ``` 3. **直线后处理(关键步骤)** - **筛选水平和垂直线**:计算直线角度,保留0°、90°、45°等特定角度的直线 - **寻找交点**:通过直线方程计算交点,组合成四边形 - **几何验证**:验证四边形内角是否接近90°,边长比例是否符合矩形特征 4. **替代方案:轮廓检测法** ```python # 查找轮廓并筛选矩形 contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: # 轮廓近似 epsilon = 0.02*cv2.arcLength(cnt,True) approx = cv2.approxPolyDP(cnt,epsilon,True) # 筛选四边形 if len(approx) == 4: # 计算角度验证直角 cv2.drawContours(img, [approx], 0, (0,0,255), 3) ``` 5. **结果显示** ```python cv2.imshow('Result', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` > 注意:实际应用中需要根据具体图像调整参数,建议结合两种方法: > 1. 先用霍夫变换检测直线 > 2. 再用轮廓分析验证几何特征[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值