基于OpenCV实现霍夫变换

霍夫变换概述

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

霍夫线检测

霍夫线变换是一种寻找直线的方法,在寻找霍夫变换之前,要对图像进行边缘检测,即霍夫线的输入为二值图像。

原理

这里写图片描述

其意思就是,直线在极坐标中的表示形式为:r=x*cos(θ)+y*sin(θ),即每一对通过(r,θ)代表了一条通过(x,y)的直线。

这里写图片描述

如果给定一个点(8,6)则r=8*cos(θ)+6*sin(θ)对应与一条正弦曲线。

这里写图片描述

对图像中的所有点都进行上述的操作,如果两个不同点进行操作得到的曲线在平面(θ,r)上相交,则意味正他们通过一条直线,因此我们可以通过设置直线上点的阈值来定义多少条曲线相交于一点,这要才认为检测到了一条直线。

OpenCV中霍夫变换

介绍两种霍夫线变换,标准霍夫线变换和累计概率霍夫线变换。

Standard Hough Line Transform的原型为:
void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )

image: 输入图像,类型为二进制图像
lines:lines类型,存储了矢量(p,θ)
rho:以像素为单位的距离精度
theta:以弧度为单位的角度精度
threshold:阈值,即识别为直线时他在累加平面中必须达到的值
srn:默认为0
stn默认为0,关于更多,请查看官方文档

Probabilistic Hough Line Transform

累计霍夫变换是对标准霍夫变换的一种改进,他在一定的范围内进行霍夫变换,计算单独线段的方向以及范围,从而减少计算了,缩短了时间。

void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0 )

不同点在最后的两个参数。

minLineLength:表示最低线段的长度,比此小的都不能显示出来
maxLineGap:允许同一行点与点之间连接起来的最大距离

下面对累加霍夫变换进行展示C++代码:

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int thre, minLineLength, maxLineGap;
Mat src, dst;
void on_HoughLines(int, void *);
int main() {
    Mat ori = imread("road.jpg");
    namedWindow("dst");
    imshow("origin", ori);
    Canny(ori, src, 50, 200,3);
    cvtColor(src, dst, CV_GRAY2BGR);
    imshow("canny image", src);
    thre = 80;
    minLineLength = 50;
    maxLineGap=10;
    createTrackbar("threshold:", "dst", &thre, 300, on_HoughLines);
    createTrackbar("minLine  :", "dst", &minLineLength, 300, on_HoughLines);
    createTrackbar("maxGap   :", "dst", &maxLineGap, 20, on_HoughLines);

    on_HoughLines(thre, 0);
    on_HoughLines(minLineLength, 0);
    on_HoughLines(maxLineGap, 0);
    /*HoughLinesP(src, lines, 1, CV_PI / 180, 50, 60, 10);
    for (size_t i = 0; i < lines.size(); i++) {
        Vec4i l = lines[i];
        line(dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186,88, 255));
    }*/
    //imshow("dst image", dst);
    waitKey(0);
}
//
void on_HoughLines(int, void *) {
    vector<Vec4i> lines;
    Mat dstImage = dst.clone();
    Mat srcImage = src.clone();
    HoughLinesP(srcImage, lines, 1, CV_PI / 180, thre, minLineLength, maxLineGap);
    for (size_t i = 0; i < lines.size(); i++) {
        Vec4i l = lines[i];
        line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255),2);
    }
    imshow("dst", dstImage);
}

可以调整参数使得检测到道路的直线段,效果如下:
原图和canny算子进行边缘检测的结果图:

这里写图片描述

直线检测效果图:

这里写图片描述

霍夫圆检测

一条直线可以以极坐标的方式进行表示(r,θ),一个圆需要三个参数(x,y,r)进行表示,通常用霍夫梯度法来解决圆变换的问题。

霍夫梯度法

霍夫梯度法的原理是首先对图像进行边缘检测,用canny,然后考虑边缘图像中的每一个非0点,考虑其局部梯度,通过Sobel函数计算x,y方向上的sobel一阶导数得到梯度,利用得到的梯度,由斜率制定直线上的每一个点都在累加器中被累加,然后从累加器中这些点钟选择候选的中心画圆。

opencv中的霍夫圆检测:

C++: void HoughCircles(InputArray image, OutputArray circles, int method, double dp, double minDist, double param1=100, double param2=100, int minRadius=0, int maxRadius=0 )

image: 输入图像,类型为二进制图像
circles:经调用后存储检测到的圆的输出矢量(x,y,radius)
method:检测的方法,位霍夫梯度法
dp:用来检测原型的累加器图像的分辨率与输入图像之比的道说,dp=1,累加器和输入图像具有相同的分辨率。
minDist:检测到的圆圆心的最小距离,即让算法能够区分不同圆直径的距离
param1:默认100,表示传递给canny边缘算子的高阈值
param2:表示在检测阶段圆心的累计其阈值,他越小,就越可以检测到更多根本不存在的预案,越大的话,检测的预案就更加接近完美圆
minRadius:表示半径的最小值
maxRadiux:表示半径的最大值

C++版本的示例:

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
    Mat src = imread("planet_glow.jpg");
    namedWindow("origin");
    imshow("origin", src);
    //转出灰度图,并进行平滑,因为要进行边缘检测,最好进行平滑
    Mat gray;
    cvtColor(src, gray, CV_BGR2GRAY);
    imshow("gray", gray);;
    Mat dst;
    medianBlur(gray, dst, 5);;
    imshow("median filter", dst);
    vector<Vec3f> circles;
    HoughCircles(dst, circles, HOUGH_GRADIENT,1,120,100,30,0,0);
    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(src, center, 2, Scalar(0, 255, 0), 2);
        //绘制轮廓
        circle(src, center, radius, Scalar(0, 255, 0), 2);
    }
    imshow("result", src);
    waitKey(0);
}

Python版本:

import cv2
import numpy as np

planets = cv2.imread('planet_glow.jpg')
gray_img = cv2.cvtColor(planets, cv2.COLOR_BGR2GRAY)
img = cv2.medianBlur(gray_img, 5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)

circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,120,
                            param1=100,param2=30,minRadius=0,maxRadius=0)

circles = np.uint16(np.around(circles))

for i in circles[0,:]:
    # draw the outer circle
    cv2.circle(planets,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv2.circle(planets,(i[0],i[1]),2,(0,0,255),3)

cv2.imwrite("planets_circles.jpg", planets)
cv2.imshow("HoughCirlces", planets)
cv2.waitKey()
cv2.destroyAllWindows()

结果如下所示:

这里写图片描述

  • 12
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值