一、提取直线、轮廓和区域

1.1 canny边缘检测

二值边缘分布图有两个主要缺点:第一,检测到的边缘过厚,这加大了识别物体边界的难度;第二,也是更重要的,通常不可能找到既低到足以检测到图像中所有重要边缘,又高到足以避免产生太多无关紧要边缘的阈值。这是一个难以权衡的问题,Canny 算法试图解决这个问题。

简单的来说Canny 算法就是在各方向求导,找到局部最大值。实现步骤:

  1. 用高斯滤波器平滑图像
  2. 用Sobel等梯度算子计算梯度幅值和方向
  3. 对梯度幅值进行非极大值抑制
  4. 用双阈值算法检测和连接边缘

非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素,可以理解为局部最大搜索。这个局部代表的是一个邻域,邻域有两个参数可变,一是邻域的维数,二是邻域的大小。就是把非极大值过滤掉(抑制)。

canny算法opencv实现

// 应用 Canny 算法
cv::Mat contours;
cv::Canny(image, // 灰度图像
contours, // 输出轮廓
125, // 低阈值
350); // 高阈值

1.2 霍夫变换直线检测

霍夫变换(Hough Transform)是图像处理领域内从图像中检测几何形状的基本方法之一。霍夫变换是一种在图像中寻找直线,圆及其他简单形状的方法。 opencv支持两种不同的霍夫变换:标准霍夫变换(SHT)和累积概率霍夫变换(PPHT)。经典霍夫变换用来检测图像中的直线,后来霍夫变换经过扩展可以进行任意形状物体的识别,例如圆和椭圆。

霍夫变换运用两个坐标空间之间的变换,将在一个空间中具有相同形状的曲线或直线映射到另一个坐标空间的一个点上形成峰值,从而把检测任意形状的问题转化为统计峰值问题。

在霍夫变换中,用这个方程式表示直线:

参数 ρ是直线与图像原点(左上角)的距离,θ是直线与垂直线间的角度。在这种表示法中,
图像中的直线有一个 0~π(弧度)的角 θ,而半径 ρ 的最大值是图像对角线的长度。

像直线 1 这样的垂直线,其角度值 θ等于 0,而水平线(例如直线 5)的 θ等于 π/2。因此直
线 3 的 θ等于 π/4,直线 4 大约是 0.7π。为了表示[0, π]范围内的所有 θ值,半径值可以用负数表
示——例如直线 2,它的 θ等于 0.8π,ρ是负数。

如果对位于同一直线上的n个点进行变换,原图像空间的n个点在参数空间对应得到有n条正弦曲线,并且这些曲线相交于一点。

霍夫变换的步骤:

1.彩色图像->灰度图
2.去噪(高斯核)
3.边缘提取(梯度算子、拉普拉斯算子、canny、sobel)
4.二值化(判断此处是否为边缘点,就看灰度值==255)
5.映射到霍夫空间(准备两个容器,一个用来展示hough-space概况,一个数组hough-space用来储存voting的值,因为投票过程往往有某个极大值超过阈值,多达几千,不能直接用灰度图来记录投票信息)
6.取局部极大值,设定阈值,过滤干扰直线
7.绘制直线、标定角点

Opencv霍夫变换实现:

概率霍夫变换,在 OpenCV中通过 cv::HoughLinesP 函数实现。

class LineFinder
{
private:
// 原始图像
cv::Mat img;
// 包含被检测直线的端点的向量
std::vector<cv::Vec4i> lines;
// 累加器分辨率参数
double deltaRho;
double deltaTheta;
// 确认直线之前必须收到的最小投票数
int minVote;
// 直线的最小长度
double minLength;
// 直线上允许的最大空隙
double maxGap;
public:
// 默认累加器分辨率是 1 像素,1 度
// 没有空隙,没有最小长度
LineFinder() : deltaRho(1), deltaTheta(PI/180),
minVote(10), minLength(0.), maxGap(0.) {}
// 设置累加器的分辨率
void setAccResolution(double dRho, double dTheta) {deltaRho= dRho;deltaTheta= dTheta;
}
// 设置最小投票数
void setMinVote(int minv) {minVote= minv;
}
// 设置直线长度和空隙
void setLineLengthAndGap(double length, double gap) {minLength= length;maxGap= gap;
}
// 应用概率霍夫变换
std::vector<cv::Vec4i> findLines(cv::Mat& binary) {lines.clear();cv::HoughLinesP(binary,lines,deltaRho, deltaTheta, minVote,minLength, maxGap);return lines;
}
// 在图像上绘制检测到的直线
void drawDetectedLines(cv::Mat &image,
cv::Scalar color=cv::Scalar(255,255,255)) {// 画直线std::vector<cv::Vec4i>::const_iterator it2= lines.begin();while (it2!=lines.end()) {cv::Point pt1((*it2)[0],(*it2)[1]);cv::Point pt2((*it2)[2],(*it2)[3]);cv::line( image, pt1, pt2, color);++it2;}
}// 创建 LineFinder 类的实例
LineFinder finder;
// 设置概率霍夫变换的参数
finder.setLineLengthAndGap(100,20);
finder.setMinVote(60);
// 检测直线并画线
std::vector<cv::Vec4i> lines= finder.findLines(contours);
finder.drawDetectedLines(image);

1.3 提取连续区域

提取轮廓的算法很简单,它系统地扫描图像,直到找到连续区域。从区域的起点开始,沿着
它的轮廓对边界像素做标记。处理完这个轮廓后,就从上个位置继续扫描,直到发现新的区域。

OpenCV 提供了一个简单的函数,可以提取出图像中连续区域的轮廓,这个函数就是
cv::findContours :

/ 用于存储轮廓的向量
std::vector<std::vector<cv::Point>> contours;
cv::findContours(image,
contours, // 存储轮廓的向量
cv::RETR_EXTERNAL, // 检索外部轮廓
cv::CHAIN_APPROX_NONE); // 每个轮廓的全部像素

函数输入是二值图像。输出的是一个存储轮廓的向量,每个轮廓用一个cv::Point 类型的向量表示。

可通过cv::drawContours函数可在图像(这里用白色图像)上画出那些区域的轮廓 :

// 在白色图像上画黑色轮廓
cv::Mat result(image.size(),CV_8U,cv::Scalar(255));
cv::drawContours(result,contours,
-1, // 画全部轮廓
0, // 用黑色画
2); // 宽度为 2

1.4 计算区域的轮廓描述算子

连续区域通常代表着场景中的某个物体。为了识别该物体,或将它与其他图像元素做比较,
需要对此区域进行测量,以提取出部分特征。

在表示和定位图像中区域的方法中,边界框可能是最简洁的。它的定义是:能完整包含该形
状的最小垂直矩形。比较边界框的高度和宽度,可以获得物体在垂直或水平方向的特征(例如可
以通过计算高度与宽度的比例,分辨出一幅图像是汽车还是行人)。

二、各模块opencv实现

2.1 HSV特定颜色提取

 Mat img = imread("test.jpg",1);Mat imgHSV; cvtColor(img, imgHSV, COLOR_BGR2HSV);//转为HSV
//颜色提取int iLowH = 100 /2;  int iHighH = 120 /2;  int iLowS = 50 *255/100;   int iHighS = 70 *255/100;  int iLowV = 40 *255/100;  int iHighV = 50 *255/100; Mat imgThresholded;inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), imgThresholded);

2.3 霍夫变换

2.3.1 canny边缘检测

void Canny( InputArray image, OutputArray edges,double threshold1, double threshold2,int apertureSize = 3, bool L2gradient = false );
  • src输入图像,必须是8-bits;
  • edges输出的图像边缘
  • threshold1, threshold2对应于上述的T1,T2T1,T2;
  • apertureSizeSobel算子的大小;
  • L2gradient表示计算梯度值时是否使用L2L2(就是默认的计算方式);

2.3.2 霍夫变换

在OpenCV3.0及以上版本中,霍夫直线检测算法定义了两个函数:HoughLines、HoughLinesP,

(1)HoughLines:标准霍夫变换、多尺度霍夫变换

HoughLines函数输出检测到直线的矢量表示集合,每一条直线由具有两个元素的矢量(ρ, θ)表示,其中ρ表示直线距离原点(0, 0)的长度,θ表示直线的角度(以弧度为单位)。
HoughLines函数无法输出图像空间中线段的长度,这也是霍夫变换本身的弱点。

CV_EXPORTS_W 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 );//InputArray image:输入图像,必须是8位单通道图像。 //OutputArray lines:检测到的线条参数集合。 //double rho:以像素为单位的距离步长。 //double theta:以弧度为单位的角度步长。 //int threshold:累加计数值的阈值参数,当参数空间某个交点的累加计数的值超过该阈值,则认为该交点对应了图像空间的一条直线。 //double srn:默认值为0,用于在多尺度霍夫变换中作为参数rho的除数,rho=rho/srn。 //double stn:默认值为0,用于在多尺度霍夫变换中作为参数theta的除数,theta=theta/stn。//如果srn和stn同时为0,就表示HoughLines函数执行标准霍夫变换,否则就是执行多尺度霍夫变换。

(2)HoughLinesP:渐进概率式霍夫变换

HoughLinesP能够检测出线端,即能够检测出图像中直线的两个端点,确切地定位图像中的直线。
HoughLinesP函数输出检测到直线的矢量表示集合,每一条直线由具有四个元素的矢量(x1, y1, x2, y2)表示,其中(x1, y1)表示线段的起点,(x2, y2)表示线段的终点。

CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength = 0, double maxLineGap = 0 ); //InputArray image:输入图像,必须是8位单通道图像。 //OutputArray lines:检测到的线条参数集合。 //double rho:直线搜索时的距离步长,以像素为单位。 //double theta:直线搜索时的角度步长,以弧度为单位。 //int threshold:累加计数值的阈值参数,当参数空间某个交点的累加计数的值超过该阈值,则认为该交点对应了图像空间的一条直线。 //double minLineLength:默认值为0,表示最小线段长度阈值(像素)。 //double maxLineGap:线段上最近两点之间的阈值.默认值为0,表示直线断裂的最大间隔距离阈值。即如果有两条线段是在一条直线上,但它们之间有间隙,那么如果这个间隔距离小于该值,则被认为是一条线段,否则认为是两条线段。

三、测试效果

 //读取待处理图片Mat image = imread("alarm.jpg");Mat gray = imread("alarm.jpg", IMREAD_GRAYSCALE);//提取灰度图像//转换为HSV 格式Mat imgHSV;cvtColor(image, imgHSV,COLOR_BGR2HSV);//HSV颜色提取,提取红色int iLowH = 0;int iHighH = 10;int iLowS = 43;int iHighS = 255;int iLowV = 46;int iHighV = 255;Mat imgThresholded;inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), imgThresholded);//中值滤波Mat medainBlurImg;medianBlur(imgThresholded, medainBlurImg,21);//直线检测Mat afterCanny;Canny(medainBlurImg, afterCanny,20,250);//阈值1,用于将间断的边缘连接起来; 阈值2 用于检测图像中明显的边缘int  line = 4;int  minLineLength = 50;int  maxLineGap = 150;vector<Vec4i> lines;HoughLinesP(afterCanny, lines,1, CV_PI / 180,line, minLineLength, maxLineGap);for (size_t i = 0; i < lines.size(); i++){line(color_dst, Point(lines[i][0], lines[i][1]),Point(lines[i][2], lines[i][3]), Scalar(0, 0, 255), 1, 8);}//轮廓检测//旋转图片

参考文献:

【1】python+opencv图像处理(提取矩形方框 提取颜色 滤波 轮廓检测 直线检测)python+opencv图像处理(提取矩形方框 提取颜色 滤波 轮廓检测 直线检测)_若风的博客-CSDN博客_opencv矩形轮廓检测

【2】三分钟带你快速学习RGB、HSV和HSL颜色空间: 三分钟带你快速学习RGB、HSV和HSL颜色空间 - 知乎

【3】 【OpenCV3经典编程100例】(18)线段检测:概率霍夫线变换HoughLinesP()函数:

【OpenCV3经典编程100例】(18)线段检测:概率霍夫线变换HoughLinesP()函数_MisterJiaJia的博客-CSDN博客

【4】OpenCV——霍夫变换(直线检测、圆检测) :OpenCV——霍夫变换(直线检测、圆检测) - 一抹烟霞 - 博客园

【5】opencv学习(四十)之寻找图像轮廓findContours(): opencv学习(四十)之寻找图像轮廓findContours()_烟雨博客-CSDN博客

【6】Canny边缘检测算法的原理与实现: Canny边缘检测算法的原理与实现_QQ哥的专栏-CSDN博客_canny边缘检测算法

【7】为什么梯度反方向是函数值局部下降最快的方向?: 为什么梯度反方向是函数值局部下降最快的方向? - 知乎

【8】霍夫变换直线检测(Line Detection)原理及示例:霍夫变换直线检测(Line Detection)原理及示例_leonardohaig的博客-CSDN博客_霍夫直线检测

【9】利用OpenCV提取图像中的矩形区域(PPT屏幕等) :https://segmentfault.com/a/1190000013925648

Opencv实战5-实现提取目标框图像相关推荐

  1. OpenCV实战——使用MSER提取特征区域

    OpenCV实战--使用MSER提取特征区域 0. 前言 1. MSER 算法原理 2. 实现 MSER 算法 3. 完整代码 相关链接 0. 前言 在分水岭算法一节中,我们了解了如何通过创建分水岭将 ...

  2. 【OpenCV】OpenCV实战从入门到精通之 -- 访问图像中的像素

    目录 1.图像在内存之中的存储方式 2.颜色空间缩减 3.LUT函数:Look up table操作 4.计时函数 5.访问图像中像素的三类方法 5.1.指针访问像素 5.2.迭代器操作像素 5.3. ...

  3. 【OpenCV】OpenCV实战从入门到精通之 -- 基本图像绘制

    目录 1.DrawEllipse()函数的写法 2.DrawFilledCircle()函数的写法 3.DrawPolygon()函数的写法 4.DrawLine()函数的写法 基本绘制图形代码: m ...

  4. OpenCV实战(14)——图像线条提取

    OpenCV实战(14)--图像线条提取 0. 前言 1. 检测图像轮廓 1.1 图像轮廓 1.2 使用 Canny 算子检测图像轮廓 2. 使用霍夫变换检测图像中的线条 2.1 线条的表示 2.2 ...

  5. 基于OpenCV实战:3步实现图像降噪

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 在本文中,我们将展示如何通过三个简单的步骤来实现降噪.我们将使用机 ...

  6. 基于OpenCV实战:绘制图像轮廓(附代码)

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 山区和地形图中海拔高的区域划出的线称为地形轮廓,它们提供了地形的高 ...

  7. 基于OpenCV实战:提取中心线

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自|AI算法与图像处理 问题 前几天有个人问了我一个问题,问 ...

  8. OpenCV实战——提取视频中的前景对象

    OpenCV实战--提取视频中的前景对象 0. 前言 1. 提取视频中的前景对象 2. 混合高斯方法 3. 完整代码 相关链接 0. 前言 当固定摄像机观察场景时,背景基本保持不变.在这种情况下,我们 ...

  9. pythonopencv提取圆内图像_python – 使用OpenCV从图像中提取多边形给定...

    使用cv2.fillConvexPoly以便您可以指定2D点阵列并定义一个蒙版,该蒙版填充由这些点定义的形状在蒙版中为白色.如果多边形中定义的点是凸的(因此名称为fillConvexPoly),则应该 ...

最新文章

  1. 咕泡-装饰器 decorator 设计模式笔记
  2. CentOS 6.2下log4cplus的使用
  3. MySQL Replication--多线程复制MTS
  4. Windows不同版本的解释
  5. c语言两个数组按位合并,合并两个线性表(数组)并按照非递减排序输出,有点问题过来看看...
  6. mysql or会用到索引吗_mysql or条件可以使用索引而避免全表
  7. swiper移入暂停_react中swiper注意事项及鼠标划入停止轮播
  8. Docker Dirty Cow逃逸
  9. oracle conneciton properties,在WAS Liberty连接池中,我可以验证借用连接吗?
  10. C++_类和对象_C++运算符重载_左移运算符重载_链式编程_实现直接打印对象---C++语言工作笔记056
  11. 快应用不会取代 App,未来将赋能 IoT!
  12. JavaWeb——Servlet(入门必备,web请求与响应的底层)
  13. java easyui 模板_漂亮easyui皮肤组件html模板下载A 最新 最全
  14. c语言注释部分两侧的分界符号分别是,单片机C语言练习题
  15. UE4官网文档关于多人局域网游戏
  16. 初学者必看的JavaScript 七大点!
  17. skywalking本地配置探针 打TID
  18. 计算图像每行占用的字节数
  19. 那么手机网站关键词优化排名该怎样做?
  20. excel拖动滑动滚动条卡死问题解决办法

热门文章

  1. Java基础~Java DateTimeFormatter类
  2. 中国鱼胶原蛋白肽市场趋势报告、技术动态创新及市场预测
  3. Wincc RT Professional第三讲-两台电脑通信
  4. 华为防火墙SSL虚拟专网配置客户端所有访问流量路由全部走公司网络
  5. matlab导出html,怎么将MATLAB代码导出到Word
  6. 我与掘金合作出了源码共读第一期,首发超400人报名,快来参与~
  7. 添加对System.ComponentModel.DataAnnotations.Schema;的引用
  8. Android 10深色主题适配踩坑记录
  9. vscode ESLint格式不正确老是报错 more than 1 blank line not allowed
  10. Mysql——》varchar