0
点赞
收藏
分享

微信扫一扫

Opencv——霍夫变换以及遇到的一些问题


目录

  • ​​问题1 :颜色空间转换函数参数问题:CV_BGR2GRAY vs CV_GRAY2BGR​​
  • ​​问题2:cvRound()、cvFloor()、cvCeil()函数用法​​
  • ​​霍夫变换的含义​​
  • ​​标准霍夫直线变换​​
  • ​​霍夫线变换函数参数讲解​​
  • ​​累计概率霍夫变换​​
  • ​​霍夫变换圆变换​​
  • ​​原理和算法步骤:​​
  • ​​霍夫圆变换函数参数讲解​​
  • ​​霍夫变换总结​​
  • ​​参考链接​​

问题1 :颜色空间转换函数参数问题:CV_BGR2GRAY vs CV_GRAY2BGR

OpenCV的颜色空间转换函数:

void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )

dstCn现在已经改成COLOR_GRAY2BGR之类的以COLOR开头的。
CV_BGR2GRAY :将RGB图转换成GRAY图
CV_GRAY2BGR:将GRAY图转换成RGB图
浅墨源码
cvtColor(midImage, dstImage, COLOR_GRAY2BGR);
//将canny算子扫描后的二值图转化为RGB图,原因是后面你可视化霍夫变换效果时,画的曲线是彩色的。

问题2:cvRound()、cvFloor()、cvCeil()函数用法

cvRound():返回跟参数最接近的整数值,即四舍五入;
cvFloor():返回不大于参数的最大整数值,即向下取整;
cvCeil():返回不小于参数的最小整数值,即向上取整;

霍夫变换的含义

这个我在边缘的文章中有涉及过,直接贴链接:
​​​javascript:void(0)​​​ 还有我参考的一个链接:
​​javascript:void(0)​​

标准霍夫直线变换

霍夫线变换函数参数讲解

●第一个参数,InputArray类型的image, 输入图像,即源图像。需为8位的单通道二进制图像
●第二个参数,InputArray类型的lines,经过调用HoughLines函数后储存了霍 夫线变换检测到线条的输出矢量。每一条线由具有两个元素的矢量( ρ, 0) 表示,其中,ρ是离坐标原点(0,0) (也就是图像的左上角)的距离,θ是弧度线条旋转角度(0度表示垂直线,π/2 度表示水平线)。
●第三个参数,double类型的rho,以像素为单位的距离精度。另-种表述方
式是直线搜索时的进步尺寸的单位半径。(Latex 中/rho即表示ρ )
●第四个参数,double 类型的theta,
以弧度为单位的角度精度。另一种表述 方式是直线搜索时的进步尺寸的单位角度。
●第五个参数,int类型的threshold,累加平面的阈值参数,即识别某部分为 图中的一条直线时它在累加平面中必须达到的值。大于國值threshold的线段才可以被检测通过并返回到结果中。
●第六个参数,double类型的srn,, 有默认值0。对于多尺度的霍夫变换,这 是第三个参数进步尺寸rho的除数距离。粗略的累加器进步尺寸直接是第三个参数rho,而精确的累加器进步尺寸为rho/sm。
●第七个参数,double 类型的stn, 有默认值0,对于多尺度霍夫变换,sm表示第四个参数进步尺寸的单位角度theta的除数距离。且如果sr和 stn同时为0,就表示使用经典的霍夫变换。否则,这两个参数应该都为正数。

理解:在XY平面,直线有两个参数:K、B(斜率和截距),可视化直线,需要构造x,y轴,假设XY轴的最小精度为1,则勾画出的直线其实是一系列离散的点。随着XY精度升高,所可视化出来的数据将越来越像一条线。
同理,在rho/theta平面,一条直线对应平面上以rho为横坐标,tehta为纵坐标的一个点。
rho/theta的精度越高,所表示的直线越精准。我想这边是第三参数和第四参数的含义。
我们一般以rho=1,theta=1度的精度来构造投票空间。

#include <opencv2/opencv.hpp>
#include <iostream>
#include "windows.h"
#include <stdio.h>
#define WINDOW_NAME "【程序窗口】" //为窗口标题定义的宏

using namespace cv;
using namespace std;
//==================================标准霍夫变换============================================
int main()
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN); //字体为绿色

Mat srcImage = imread("D:\\opencv_picture_test\\霍夫变换.png");
//判断图像是否加载成功
if (srcImage.empty())
{
cout << "图像加载失败!" << endl;
return -1;
}
else
cout << "图像加载成功!" << endl << endl;
Mat midImage,dstImage;
Canny(srcImage, midImage, 50, 200, 3);//进行一此canny边缘检测
//【3】进行霍夫线变换
vector<Vec2f> lines;//定义一个矢量结构lines用于存放得到的线段矢量集合
HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);
//【4】依次在图中绘制出每条线段
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(midImage, pt1, pt2, Scalar(255,255,255),1, LINE_AA);
}

//【5】显示原始图
imshow("【原始图】", srcImage);

//【6】边缘检测后的图
imshow("【边缘检测后的图】", midImage);

//【7】显示效果图
//imshow("【效果图】", dstImage);
waitKey(0);
return 0;
}

累计概率霍夫变换

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

第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
第二个参数,InputArray类型的lines,经过调用HoughLinesP函数后后存储了检测到的线条的输出矢量,每一条线由具有四个元素的矢量(x_1,y_1, x_2, y_2) 表示,其中,(x_1, y_1)和(x_2, y_2) 是是每个检测到的线段的结束点。
第三个参数,double类型的rho,以像素为单位的距离精度。另一种形容方式是直线搜索时的进步尺寸的单位半径。
第四个参数,double类型的theta,以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度。
第五个参数,int类型的threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。大于阈值threshold的线段才可以被检测通过并返回到结果中。
第六个参数,double类型的minLineLength,有默认值0,表示最低线段的长度,比这个设定参数短的线段就不能被显现出来。
第七个参数,double类型的maxLineGap,有默认值0,允许将同一行点与点之间连接起来的最大的距离。

通过设定直线长度阈值,对过长或过短的直线不予理会。

//==================================累计概率霍夫变换============================================
int main()
{
//读取原图片
Mat Image = imread("D:\\opencv_picture_test\\霍夫变换.png");
//显示原图片
namedWindow("【原图】");
imshow("【原图】", Image);

Mat srcImage = Image.clone();
Mat midImage, dstImage;
//进行边缘检测和转化为将灰度图转为RGB图
Canny(srcImage, midImage, 50, 200, 3);
cvtColor(midImage, dstImage, COLOR_GRAY2BGR);
//定义矢量结构lines用于存放得到的线段矢量集合
vector<Vec4i> lines;
//进行霍夫变换
HoughLinesP(midImage, lines, 1, CV_PI / 180, 80, 50, 10);
//依次在图中绘制每条线段
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(0, 0, 255), 1, LINE_AA);
}

imshow("【边缘检测后的图】", midImage);
imshow("【效果图】", dstImage);

waitKey(0);
return 0;
}

霍夫变换圆变换

原理和算法步骤:

Opencv——霍夫变换以及遇到的一些问题_算法

霍夫圆变换函数参数讲解

cvHoughCircles( CvArr* image, void* circle_storage, int method, double dp, double min_dist, double param1=100, double param2=100, int min_radius=0, int max_radius=0 );

输入:输入 8-bit、单通道灰度图像. circle_storage:检测到的圆存储仓. 可以是内存存储仓 (此种情况下,一个线段序列在存储仓中被创建,并且由函数返回)或者是包含圆参数的特殊类型的具有单行/单列的CV_32FC3型矩阵(CvMat*).矩阵头为函数所修改,使得它的 cols/rows 将包含一组检测到的圆。如果 circle_storage是矩阵,而实际圆的数目超过矩阵尺寸,那么最大可能数目的圆被返回。 每个圆由三个浮点数表示:圆心坐标(x,y)和半径.
method:Hough 变换方式,目前 只支持HOUGH_GRADIENT
dp:累加器图像的分辨率。这个参数允许创建一个比输入图像分辨率低的累加器。(这样做是因为有理由认为图像中存在的圆会自然降低到与图像宽高相同数量的范畴)。如果dp设置为1,则分辨率是相同的;如果设置为更大的值(比如2),累加器的分辨率受此影响会变小(此情况下为一半)。dp的值不能比1小。
min_dist:该参数是让算法能明显区分的两个不同圆之间的最小距离。
param1:用于Canny的边缘阀值上限,下限被置为上限的一半。
param2:累加器的阀值。
min_radius:最小圆半径。
max_radius:最大圆半径。

==================================霍夫变换圆变换============================================

int main()
{
//载入原始图和Mat变量定义
Mat srcImage = imread("D:\\opencv_picture_test\\形态学操作\\孔洞.png");
Mat midImage, dstImage;
//显示原始图
imshow("【原始图】", srcImage);

//转为灰度图,进行图像平滑
cvtColor(srcImage, midImage, COLOR_BGR2GRAY);//转化边缘检测后的图为灰度图
GaussianBlur(midImage, midImage, Size(9, 9), 2, 2); //模糊去噪

//进行霍夫圆变换
vector<Vec3f> circles; //圆存储器,存储圆的数量,圆心坐标和半径
HoughCircles(midImage, circles,HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);
//inputImage circle_storage 霍夫变换的方式 累加器图像的分辨率 两个不同圆之间的距离
//依次在图中绘制出圆
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(srcImage, center, 3, Scalar(0, 0, 255), 3, 8, 0);
//绘制圆轮廓
circle(srcImage, center, radius, Scalar(0, 0, 255), 3, 8, 0);
}

//显示效果图
imshow("【效果图】", srcImage);

while ((char)waitKey(1) != 'q') {}
return 0;
}

霍夫变换总结

1、为什么在霍夫变换求直线方程时,要用极坐标的形式
斜截式不能表示垂直于x轴的直线,而极坐标形式可以表达。
2、霍夫变换求直线方程,和使用最小二乘法求直线最小方程相比,有什么优缺点
优点:当出现离群采样点时最小二乘法会有很大误差而霍夫变换不会
缺点:时间复杂度和空间复杂度都很高,只能检测线段的方向,而不能确定线段的长度

参考链接

​​https://blog.csdn.net/OliverkingLi/article/details/54754814?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158565498519724835852132%2522%252C%2522scm%2522%253A%252220140713.130056874…%2522%257D&request_id=158565498519724835852132&biz_id=0&utm_source=distribute.pc_search_result.none-task​​

​​http://www.manongjc.com/article/42132.html​​​​https://stackoverflow.com/questions/5929125/opencv-houghcircles-param1-param2​​​​javascript:void(0)​​​​浅墨大神博客​​


举报

相关推荐

0 条评论