opencv霍夫变换检测圆cvHoughCircles和直线cvHoughLines2的应用

1)cvHonghLines2:直线

2)cvHoughCircles:该函数用Hough变换在二值图像中中寻找圆

3)cvCircle:是指绘制圆形的一个程序函数

4)cvLine:简单的绘制直线函数

5)cvLoadImage:载入图像的函数

霍夫变换是一种在图像中寻找直线、圆及其他简单形状的方法。原始的霍夫变换是一种直线变换,即在二值图像中寻找直线的一种相对快速的方法。

变换可以推广到其他普通的情况,而不仅仅是简单的直线,对于图像中共线的点集{(x0,y0), (x1,y1), ...}都经过直线y=kx+b,先在我们换一个说法,“斜率为k,截距为b的直线y=kx+b包含了所有在该直线上的点”。

一种强调的是图像中的点集,另一种强调的是直线的参数k和b,通过直线的点集去描述这条直线明显没有直接通过k,b两个参数去描述那样直接方便。而Hough变换就是将我们“点共线”的思维转化到参数空间{k,b}进行描述,图像空间中所有经过y=kx+b的点经过Hough变换后在参数空间都会相交于点(k,b),这样,通过Hough变换,就可以将图像空间中直线的检测转化为参数空间中对点的检测。我们不妨将y=kx+b进行一下变形:

这就是Hough变换将图像空间坐标(x,y)转化为参数空间(k,b)的Hough变换式。

Hough变换的步骤(执行过程):

  1. 在参数空间中建立一个二维(分别对应k,b)计数器,实际就是二维数组kbcnt,k维度为图像中直线斜率可能范围,b维度为图像中截距可能范围;数组中所有值都初始化为0;

  2. 扫描图像空间中的所有点(xi,yi),Hough变换式进行图像空间到参数空间的变换(ki,bi),计数kbcnt(ki,bi)++

  3. 设定阈值thr(图像中有多少个点共线才认为存在直线),kbcnt(ki,bi)>thr的ki,bi组成图像中的直线y=ki*x+bi

然而,上面的检测直线的方案貌似还有些问题:如果图像中存在竖直的直线呢,那kbcnt的k维度岂不是要无穷大!因此,才有了另一种参数空间的方案:利用极坐标参数而非“斜率-截距式”描述直线。

极坐标中的直线表示

极坐标中的直线方程为

将其改写成Hough变换式,即自变量(x,y)到参数变量(r,theta)的映射:

使用极坐标参数空间,Hough变换的步骤不变,只不过将kbcnt替换成rthcnt,r范围是图像对角线的长度,th范围是0~2*pi。因为图像是离散的,所以r和th都有一个步进值dr和dth。

Hough变换除了检测直线,还可用来检测任何能用数学表达式表示的形状,如最常见的圆、椭圆,基本原理都是将图像空间的像素转变到参数空间,然后在参数空间中对共线/圆/椭圆的点进行统计,最后通过阈值判决是否是符合要求的形状。

1)cvHonghLines2:此函数是opencv图像变换函数中的一个,主要用来访问霍夫变换的两个算法———标准霍夫变换(SHT)和累计概率霍夫变换(PPHT)。
CvSeq* cvHonghLines2(CvArr* image,void* line_storage,int mehtod,
double rho,double theta,int threshold,double param1 =0,double param2 =0);
参数说明:
image
输入 8-比特、单通道 (二值) 图像,当用CV_HOUGH_PROBABILISTIC方法检测的时候其内容会被函数改变。
line_storage
检测到的线段存储仓. 可以是内存存储仓 (此种情况下,一个线段序列在存储仓中被创建,并且由函数返回),或者是包含线段参数的特殊类型(见下面)的具有单行/单列的矩阵(CvMat*)。矩阵头为函数所修改,使得它的cols/rows 将包含一组检测到的线段。如果 line_storage 是矩阵,而实际线段的数目超过矩阵尺寸,那么最大可能数目的线段被返回(线段没有按照长度、可信度或其它指标排序).

method
Hough 变换变量,是下面变量的其中之一
CV_HOUGH_STANDARD - 传统或标准 Hough 变换. 每一个线段由两个浮点数 (ρ, θ) 表示,其中 ρ 是直线与原点 (0,0) 之间的距离,θ 线段与 x-轴之间的夹角。因此,矩阵类型必须是 CV_32FC2 type.

CV_HOUGH_PROBABILISTIC - 概率 Hough 变换(如果图像包含一些长的线性分割,则效率更高). 它返回线段分割而不是整个线段。每个分割用起点和终点来表示,所以矩阵(或创建的序列)类型是 CV_32SC4.

CV_HOUGH_MULTI_SCALE - 传统 Hough 变换的多尺度变种。线段的编码方式与 CV_HOUGH_STANDARD 的一致。

rho
与象素相关单位的距离精度

theta
弧度测量的角度精度

threshold
阈值参数。如果相应的累计值大于 threshold, 则函数返回的这个线段.

param1
第一个方法相关的参数:
对传统 Hough 变换,不使用(0).
对概率 Hough 变换,它是最小线段长度.
对多尺度 Hough 变换,它是距离精度 rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / param1 ).

param2
第二个方法相关参数:
对传统 Hough 变换,不使用 (0).
对概率 Hough 变换,这个参数表示在同一条直线上进行碎线段连接的最大间隔值(gap), 即当同一条直线上的两条碎线段之间的间隔小于param2时,将其合二为一。

对多尺度 Hough 变换,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 theta / param2).

2)cvHoughCircles:该函数用Hough变换在二值图像中中寻找圆,成功时返回CvSeq指针

CvSeq *cvHoughCircles(CvArr *image,void *circle_storage,int method,double dp,
double min_dist,double param1,double param2,int min_radius,int max_radius)

image:输入8bit(灰度)图像,其内容可被函数所改变

circle_storage:检测到的圆存储仓,可以是内存存储仓 (此种情况下,一个线段序列在存储仓中被创建,并且由函数返回)或者是包含圆参数的特殊类型的具有单行/单列的CV_32FC3型矩阵(CvMat*). 矩阵头为函数所修改,使得它的 cols/rows 将包含一组检测到的圆。如果 circle_storage 是矩阵,而实际圆的数目超过矩阵尺寸,那么最大可能数目的圆被返回,每个圆由三个浮点数表示:圆心坐标(x,y)和半径.).

method:Hough 变换方式,目前只支持CV_HOUGH_GRADIENT, which is basically 21HT, described in [Yuen03].

dp:寻找圆弧圆心的累计分辨率,这个参数允许创建一个比输入图像分辨率低的累加器。(这样做是因为有理由认为图像中存在的圆会自然降低到与图像宽高相同数量的范畴)。如果dp设置为1,则分辨率是相同的;如果设置为更大的值(比如2),累加器的分辨率受此影响会变小(此情况下为一半)。dp的值不能比1小。

min_dist:该参数是让算法能明显区分的两个不同圆之间的最小距离。

param1:用于Canny的边缘阀值上限,下限被置为上限的一半。

param2:累加器的阀值。

The second method-specific parameter. In case of CV_HOUGH_GRADIENT it is accumulator threshold at the center detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first.

min_radius:最小圆半径。

max_radius:最大圆半径。

3)cvCircle:是指绘制圆形的一个程序函数。 中文意思 Circle,即圆形。cvCircle是指绘制圆形的一个程序函数。

cvCircle(CvArr* img, CvPoint center, int radius, CvScalar color,

int thickness=1, int lineType=8, int shift=0)

img为图像指针,单通道多通道都行,不需要特殊要求

center为画圆的圆心坐标

radius为圆的半径

color为设定圆的颜色,比如用CV_RGB(255, 0,0)设置为红色

thickness为设置圆线条的粗细,值越大则线条越粗,为负数则是填充效果

4)cvLine:简单的绘制直线函数

void cvPolyLine( CvArr* img, CvPoint* pt1, CvPoint* pt2, CvScalar color,

int thickness=1,int line_type=8,int shift=0);

img 图像。

pt1 线段的第一个端点。

pt2 线段的第二个端点。

color 线段的颜色。

thickness 线段的粗细程度。

line_type 线段的类型。 8 (or 0) - 8-connected line(8邻接)连接 线。 4 - 4-connected line(4邻接)连接线。

CV_AA - antialiased 线条。

代码

#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <opencv2/legacy/legacy.hpp>
//#pragma comment(lib, "opencv_legacy2411.lib")
using namespace cv;
using namespace std;
int main()
{
    char * soutceFile = "D:\\VC98\\C++项目\\opencv\\hough\\hough\\a4.jpg";
    IplImage * image_Resource = cvLoadImage(soutceFile, CV_LOAD_IMAGE_GRAYSCALE);
    assert(image_Resource);
    cvNamedWindow("原始图像", CV_WINDOW_AUTOSIZE);
    cvNamedWindow("题目_a", CV_WINDOW_AUTOSIZE);
   cvShowImage("原始图像", image_Resource);
    //---------------------------a:开始--------------------------------//
IplImage *img1 = cvCreateImage (cvGetSize(image_Resource), IPL_DEPTH_8U, 1);//处理的图像必须是八位单通道的
cvZero(img1);
if (image_Resource->nChannels == 1)
{
img1 = cvCloneImage (image_Resource);
}
else
{
cvCvtColor (image_Resource, img1, CV_RGB2GRAY); //转为单通道
}
    CvMemStorage* storage = cvCreateMemStorage(0);
cvSmooth(img1,img1,CV_GAUSSIAN,5,5);//高斯平滑滤波,降噪处理
cvThreshold(img1,img1,100,100,CV_THRESH_TRUNC);//二值化
    CvSeq* results = cvHoughCircles(//cvHoughCircles函数需要估计每一个像素梯度的方向,
//因此会在内部自动调用cvSobel,而二值边缘图像的处理是比较难的
        img1,//输入可以是灰度图
        storage,
        CV_HOUGH_GRADIENT,
        1,//累加器图像分辨率,增大则分辨率变小
        image_Resource->width / 10,//两个圆之间最小距离
        100,//边缘阀值,canny算法的阈值上限,下限为一半(即100以上为边缘点,50以下抛弃,中间视是否相连而定)
25,//决定成圆的多寡 ,一个圆上的像素超过这个阈值,则成圆,否则丢弃
10,//最小圆半径,这个可以通过图片确定你需要的圆的区间范围
150//最大圆半径
        );
IplImage *image_Result_a = cvCreateImage (cvGetSize(img1), IPL_DEPTH_8U, 3); //用一个三通道的图片来显示红色的圆圈
cvZero(image_Result_a);
cvCvtColor (img1, image_Result_a, CV_GRAY2RGB); //转为3通道
    for (int i = 0; i < results->total; i++)
    {
        float* p = (float*)cvGetSeqElem(results, i);
        CvPoint pt = cvPoint(cvRound(p[0]), cvRound(p[1]));//圆心坐标(p(0),p(1))
        cvCircle(
            image_Result_a,
            pt,//确定圆心
            cvRound(p[2]),//确定半径
            CV_RGB(255,0,0),
3
            );
    }
    cvShowImage("题目_a",image_Result_a);
cvSaveImage("result.jpg",image_Result_a);
    //---------------------------a:结束--------------------------------//    
    //---------------------------b:开始--------------------------------//
    soutceFile = "D:\\VC98\\C++项目\\opencv\\hough\\hough\\house1.png";
    image_Resource = cvLoadImage(soutceFile, CV_LOAD_IMAGE_UNCHANGED);
    assert(image_Resource);
    int i;
    IplImage* dst = cvCreateImage(cvGetSize(image_Resource), 8, 1);
    IplImage* color_dst = cvCreateImage(cvGetSize(image_Resource), 8, 3);
    CvMemStorage* storage2 = cvCreateMemStorage(0);
    CvSeq* lines = 0;
    IplImage* src1 = cvCreateImage(cvSize(image_Resource->width, image_Resource->height), IPL_DEPTH_8U, 1);
    cvCvtColor(image_Resource, src1, CV_BGR2GRAY);
    cvCanny(src1, dst, 50, 200, 3);
    cvCvtColor(dst, color_dst, CV_GRAY2BGR);
    lines = cvHoughLines2(dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 80, 30, 10);
    for (i = 0; i < lines->total; i++)
    {
        CvPoint* line = (CvPoint*)cvGetSeqElem(lines, i);
        cvLine(color_dst, line[0], line[1], CV_RGB(255, 0, 0), 2, 8);
    }
    cvNamedWindow("Source", CV_WINDOW_NORMAL);
    cvShowImage("Source", image_Resource);
    cvNamedWindow("Hough", CV_WINDOW_NORMAL);
    cvShowImage("Hough", color_dst);
cvSaveImage("result1.jpg",color_dst);
    //---------------------------b:结束--------------------------------//    
    cvWaitKey(0);
    cvReleaseImage(&image_Resource);
    cvReleaseImage(&image_Result_a);
    cvReleaseImage(&color_dst);
cvReleaseImage(&img1);
    cvDestroyAllWindows();
    return 0;
}

程序说明:

(5)cvLoadImage():载入图像的函数

原型:CVAPI(IplImage*) cvLoadImage( const char* filename, int iscolor CV_DEFAULT(CV_LOAD_IMAGE_COLOR));

第一个参数是:指向文件名称的指针(不可修改);

第二个参数是:读入图像的颜色和深度;

enum
{
/* 8bit, color or not */
    CV_LOAD_IMAGE_UNCHANGED  =-1,
/* 8bit, gray */
    CV_LOAD_IMAGE_GRAYSCALE  =0,
/* ?, color */
    CV_LOAD_IMAGE_COLOR      =1,
/* any depth, ? */
    CV_LOAD_IMAGE_ANYDEPTH   =2,
/* ?, any color */
    CV_LOAD_IMAGE_ANYCOLOR   =4
};

指定的颜色可以将输入的图片转为3信道(CV_LOAD_IMAGE_COLOR)也即彩色(>0), 单信道 (CV_LOAD_IMAGE_GRAYSCALE)也即灰色(=0),或者保持不变(CV_LOAD_IMAGE_ANYCOLOR)(=4)。

深度指定输入的图像是否转为每个颜色信道每象素8位,(OpenCV的早期版本一样),或者同输入的图像一样保持不变。
选中CV_LOAD_IMAGE_ANYDEPTH,则输入图像格式可以为8位无符号,16位无符号,32位有符号或者32位浮点型。
如果输入有冲突的标志,将采用较小的数字值。比如CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYCOLOR 将载入3信道图。CV_LOAD_IMAGE_ANYCOLOR和CV_LOAD_IMAGE_UNCHANGED是等值的。但是,CV_LOAD_IMAGE_ANYCOLOR有着可以和CV_LOAD_IMAGE_ANYDEPTH同时使用的优点,所以CV_LOAD_IMAGE_UNCHANGED不再使用了。
如果想要载入最真实的图像,选择CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR。
另:通常用cvLoadimage()函数进行读图像,参数选择上建议大家选择CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR,这样的参数组合读出的图像信息保持了原是图像的信息(包括通道信息和位深信息)。其中像素深度指每个通道用多少位来表示,通道就是指每个像素的颜色数了。而我们一般在图像处理书上看到的图像的像素的bit数,在这里应该是:通道*像素深度。可以看出像素的bit数和像素深度不是同一个概念。

效果图:

检测圆的原图:

结果:

检测直线的原图:

结果:

opencv霍夫变换检测圆cvHoughCircles和直线cvHoughLines2的应用相关推荐

  1. 霍夫变换检测圆c 语言,c++ 霍夫变换检测直线

    通常这是一幅边缘图像,比如来自 Canny算子.cv:: Houghlines函数的输出是 cV::Vec2f向量,每个元素都是一对代表检测到的直线的浮点数(p,0).在下例中 我们首先应用 Cann ...

  2. Canny算子与霍夫变换检测圆与直线

    目录 引言 一.canny算子 二.canny算子代码 三.霍夫变换检测直线 四.霍夫变换检测直线代码 五.霍夫变换检测直线效果 六.霍夫变换检测圆 七.霍夫变换检测圆代码 八.霍夫变换检测圆效果 引 ...

  3. 霍夫变换MATLAB怎么实现,做过Matlab关于霍夫变换检测圆的高手请进

    Hough变换对圆的检测 Hough变换的基本原理在于,利用点与线的对偶性,将图像空间的线条变为参数空间的聚集点,从而检测给定图像是否存在给定性质的曲线. Hough对圆的检测程序如下  完整的程序及 ...

  4. OpenCV霍夫变换查找圆的实例(附完整代码)

    OpenCV霍夫变换查找圆的实例 OpenCV霍夫变换查找圆的实例 OpenCV霍夫变换查找圆的实例 #include "opencv2/imgcodecs.hpp" #inclu ...

  5. Matlab findcircle函数实现 霍夫变换——检测圆

    Matlab findcircle函数实现 霍夫变换--检测圆 实现了基于霍夫变换的findcircle函数,function[circlefind]=findcircle(img,minr,maxr ...

  6. opencv 霍夫变换检测直线和圆

    霍夫变换 霍夫变换原理及python实现 opencv 霍夫直线变换 OpenCV中用cv.HoughLines()在二值图上实现霍夫变换,函数返回的是一组直线的(r,θ)数据: 函数中: 参数1:要 ...

  7. OpenCvSharp手绘ROI区域+模板匹配+霍夫变换检测圆的边界

    最终效果如下: 左侧为检测图片.右侧为模板,右下角textbox为轮毂中心的像素坐标 操作步骤: 1.点击打开图像选择一张比较不错的图片,用于画模板: 2.在picturebox中画取ROI区域生成模 ...

  8. 霍夫变换检测圆c 语言,c – 使用Hough变换检测圆

    我正在尝试使用霍夫变换来检测圆圈. 使用我当前的代码,我可以检测到下面的代码 但我想在我发现的圆圈内找到黑洞. 然而,改变houghcircle方法的参数对我没有帮助.实际上它找到了不存在的圆圈. 此 ...

  9. 理解霍夫变换及圆检测

    近日在做小球动力特性识别过程中,用到了opencv中的霍夫变换圆检测来识别图像中的小球,从而确定小球的位置.但是在调节参数的过程中不能明确各参数的真正含义,无法达到最优的识别效果. 所以想深入理解霍夫 ...

最新文章

  1. mysql 批处理文件传参_如何实现批处理文件传参数给SQLPLUS
  2. 基于加权投票的尖峰神经活动数据高效解码
  3. 《CCNP安全防火墙642-618认证考试指南》——1.4节防火墙技术
  4. linux游戏欢迎界面,制作Linux登录欢迎界面
  5. React技术栈——webpack
  6. 计算机组成原理 陈泽,江西师范大学-计算机组成原理的期末复习.doc
  7. ibatis解决sql注入问题
  8. 面试题分享【不断更新】
  9. Unhandled event loop exception PermGen space
  10. mysql 与gemfire的同步_(转)分布式缓存GemFire架构介绍
  11. matlab找距离最近的元素,如何用MATLAB找到给定坐标的最近点?
  12. 继续推荐几款VisualStudio的插件
  13. 浪潮服务器u盘安装系统未找到任何驱动器,u盘重装win10时找不到任何驱动器
  14. 按值传递时 php必须复制值,PHP开发笔试题及答案(一)
  15. 传统的DOM渲染方式?
  16. 搜狗linux 命令行,linux 安装搜狗输入法非caodan命令行方式
  17. 「武汉理工大学 软件工程复习」第三章 | 软件需求
  18. 数字宫殿110位数字对照物
  19. 2022施工员-土建方向-通用基础(施工员)理论题库模拟考试平台操作
  20. 神武2手游服务器等级限制影响,《神武2》手游开放新等级!不再为修炼等级操心...

热门文章

  1. java throwable_java中怎么捕获异常?Throwable类的方法有哪些?
  2. 什么是工控主机?工控主机安卓主板有哪些配置?
  3. UNetbootin制作u盘启动安装 ubuntu11.04
  4. VC6.0 在WIN10专业版下如何完美运行。(附西红柿助手)
  5. RabbitMQ消息持久化
  6. Android 显示 一、 Vsync
  7. 最新VLC命令行参数大全(一)
  8. mysql报196271错误_错误:Microsoft Knowledge Base Article 196271
  9. android手机照片导出来,华为手机相册怎么导出到电脑?华为手机相册批量导出电脑的三种方法...
  10. Oracle和PlSql的完全卸载