【OpenCV学习笔记】之边缘检测

本文详细介绍了Canny边缘检测算法的原理与实现过程,包括高斯滤波、梯度计算、非极大值抑制及双阈值检测等步骤,并通过实例展示了良好的边缘检测效果。

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

一、边缘检测

边缘(edge)是指图像局部强度变化最显著的部分。主要存在于目标与目标、目标与背景、区域与区域(包括不同色彩)之间,是图像分割、纹理特征和形状特征等图像分析的重要基础。

图像强度的显著变化可分为:

  • 阶跃变化函数,即图像强度在不连续处的两边的像素灰度值有着显著的差异;
  • 线条(屋顶)变化函数,即图像强度突然从一个值变化到另一个值,保持一较小行程后又回到原来的值。

图像的边缘有方向和幅度两个属性,沿边缘方向像素变化平缓,垂直于边缘方向像素变化剧烈.边缘上的这种变化可以用微分算子检测出来,通常用一阶或二阶导数来检测边缘。

 (a)(b)分别是阶跃函数和屋顶函数的二维图像;                             (c)(d)是阶跃和屋顶函数的函数图象;

                          (e)(f)对应一阶倒数;                                                          (g)(h)是二阶倒数。

二、梯度算子 Gradient operators

函数f(x,y)在(x,y)处的梯度为一个向量:

                                                         

计算这个向量的大小为:

                                                         

近似为:

                                                         

梯度的方向角为:

                                                        

常见的sobel,拉普拉斯、scharr算子在前面记录过了:

这里重点分析canny算子;(一般的边缘检测的过程:滤波-增强-检测-定位)

三、Canny边缘检测的原理: 

Canny算子与MarrLoG)边缘检测方法类似(Marr大爷号称计算机视觉之父),也属于是先平滑后求导数的方法。John Canny研究了最优边缘检测方法所需的特性,给出了评价边缘检测性能优劣的三个指标:

1  好的信噪比,即将非边缘点判定为边缘点的概率要低,将边缘点判为非边缘点的概率要低;

高的定位性能,即检测出的边缘点要尽可能在实际边缘的中心;

对单一边缘仅有唯一响应,即单个边缘产生多个响应的概率要低,并且虚假响应边缘应该得到最大抑制。

Canny法就是基于满足这3个指标的最优解实现的,在对图像中物体边缘敏感性的同时,也可以抑制或消除噪声的影响。

Canny算子求边缘点具体算法步骤如下:

1. 用高斯滤波器平滑图像.

2. 用一阶偏导有限差分计算梯度幅值和方向

3. 对梯度幅值进行非极大值抑制

4. 用双阈值算法检测和连接边缘.

(1)灰度化和去噪

         Canny算法通常处理的都是灰度图像,因此先把图像转变为灰度图像。

高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,特别是对抑制或消除服从正态分布的噪声非常有效。滤波可以消除或降低图像中噪声的影响,使用高斯滤波器主要是基于在滤波降噪的同时也可以最大限度保留边缘信息的考虑。

(2)用一阶偏导的有限差分来计算梯度的幅值和方向。

    高斯模糊的目的主要为了整体降低图像噪声,目的是为了更准确计算图像梯度及边缘计算梯度值和方向,幅值。计算图像梯度可以选择算子有Robot算子、Sobel算子、Prewitt算子等。

图像灰度值的梯度一般使用一阶有限差分来进行近似,这样就可以得图像在x和y方向上偏导数的两个矩阵。

                     

这里采用更加简单明了的2x2的算子,其数学表达如下:

                  

(3)对梯度幅值进行非极大值抑制。

       非极大值抑制是进行边缘检测的一个重要步骤,通俗意义上是指寻找像素点局部最大值。沿着梯度方向,比较它前面和后面的梯度值进行了。

                  

(4)用双阈值算法检测和连接边缘。

非最大信号抑制以后,输出的幅值如果直接显示结果可能会少量的非边缘像素被包含到结果中,所以要通过选取阈值进行取舍,传统的基于一个阈值的方法如果选择的阈值较小起不到过滤非边缘的作用,如果选择的阈值过大容易丢失真正的图像边缘,Canny提出基于双阈值(Fuzzy threshold)方法很好的实现了边缘选取,在实际应用中双阈值还有边缘连接的作用。双阈值选择与边缘连接方法通过假设两个阈值其中一个为高阈值TH另外一个为低阈值TL则有,

a.对于任意边缘像素低于TL的则丢弃

b.对于任意边缘像素高于TH的则保留

c.对于任意边缘像素值在TL与TH之间的,如果能通过边缘连接到一个像素大于TH而且边缘所有像素大于最小阈值TL的则保留,否则丢弃。

Opencv里面API介绍:

Canny算法介绍 – 五步:                                                                                                                                                             

  1. 高斯模糊 - GaussianBlur
  2. 灰度转换 - cvtColor
  3. 计算梯度 – Sobel/Scharr
  4. 非最大信号抑制
  5. 高低阈值输出二值图像
C++ void  Canny(
                    InputArray src, // 8-bit的输入图像
                    OutputArray edges,// 输出边缘图像, 一般都是二值图像,背景是黑色
                    double threshold1,// 低阈值,常取高阈值的1/2或者1/3
                    double threshold2,// 高阈值
                    int aptertureSize,// Soble算子的size,通常3x3,取值3
                    bool L2gradient // 选择 true表示是L2来归一化,否则用L1归一化)


示例程序:

//canny边缘检测,canny算法:
//1、高斯模糊 - GaussianBlur
//2、灰度转换 - cvtColor
//3、计算梯度 – Sobel / Scharr
//4、非最大信号抑制
//5、高低阈值输出二值图像

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace cv;
int T1_value = 40;
int max_value = 255;
Mat src, dst, gray_src, dst1, dst2;
const char*result = "canny detection image";
void canny_demo(int, void*);
int main(int argc, char*argv)
{
	src = imread("C:\\Users\\59235\\Desktop\\imag\\girl1.jpg");
	if (!src.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	char input[] = "input image";
	namedWindow(input, CV_WINDOW_AUTOSIZE);
	namedWindow(result, CV_WINDOW_AUTOSIZE);
	imshow(input, src);

	GaussianBlur(src, dst, Size(3, 3), 0, 0);//高斯滤波
	cvtColor(dst, gray_src, CV_BGR2GRAY);//转换为灰度图像
	createTrackbar("threshold value", result, &T1_value, max_value, canny_demo);
	canny_demo(0, 0);

	waitKey(0);
	return 0;
}

void canny_demo(int, void*)
{
	//canny算法API
	Canny(gray_src, dst1, T1_value, 2 * T1_value, 3, false);
	//InputArray src, // 8-bit的输入图像;OutputArray edges,// 输出边缘图像, 一般都是二值图像,背景是黑色; double threshold1,// 低阈值,常取高阈值的1/2或者1/3 ;double threshold2,// 高阈值;int aptertureSize,// Soble算子的size,通常3x3,取值3;bool L2gradient // 选择 true表示是L2来归一化,否则用L1归一化
	imshow(result, ~dst1);

	dst2.create(src.size(), src.type());
	//使用遮罩层,只有非零的元素才被copy的模板中
	dst2 = Scalar::all(0);
	src.copyTo(dst2, dst1);

	imshow("添加颜色的result", dst2);
}

效果图:

                                            canny算子检测边缘结果)

分析:由结果图看出,通过canny算子检测得到的图像边缘确实效果很好,基本上能过很好的体现图像的边缘信息。

### 关于OpenCV中霍夫圆检测的学习教程 #### 霍夫圆检测简介 霍夫圆检测是一种用于识别图像中圆形物体的技术。该方法通过参数空间累加投票的方式找到可能存在的圆心位置及其半径大小[^1]。 #### 实现过程概述 为了实现霍夫圆检测,通常遵循以下几个主要步骤: - **转换为灰度图**:对于彩色输入图片来说,第一步是要将其转化为单通道的灰度形式以便后续处理。 - **降噪预处理**:采用诸如高斯滤波的方法去除不必要的细节干扰,使得边缘更加清晰明显[^3]。 - **提取轮廓线**:利用像Canny这样的算子来进行边界捕捉操作,从而获得目标对象的大致外形特征。 - **执行Hough变换**:调用`cv2.HoughCircles()`函数完成实际的圆周定位工作;此阶段涉及设定多个重要参数以控制精度和效率之间的平衡关系。 - **可视化结果**:最后一步是在原图中标记出所发现的所有符合条件的圆形区域供进一步分析或展示用途。 下面是具体的Python代码实例来说明如何运用上述流程进行简单的霍夫圆检测任务: ```python import cv2 import numpy as np # 加载测试样本并调整尺寸方便显示 img = cv2.imread('coins.jpg') output = img.copy() gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 应用轻微模糊效果降低随机噪声影响 blurred = cv2.GaussianBlur(gray, (9, 9), 2) # 执行边缘探测算法得到初步形状线索 edges = cv2.Canny(blurred, threshold1=50, threshold2=150) # 进行霍夫变换查找潜在的圆形结构 circles = cv2.HoughCircles(edges, method=cv2.HOUGH_GRADIENT_ALT, dp=1.5, minDist=80, param1=400, param2=0.85, minRadius=20, maxRadius=100) if circles is not None: detected_circles = np.uint16(np.around(circles)) for circle in detected_circles[0]: center_x, center_y, radius = circle # 绘制外接矩形框包围每一个被确认下来的圈状物 cv2.circle(output, (center_x, center_y), radius, color=(0, 255, 0), thickness=2) # 同时也标记中心点坐标作为辅助参考信息 cv2.circle(output, (center_x, center_y), 2, color=(0, 0, 255), thickness=-1) # 展示最终成果给用户查看 cv2.imshow("Detected Circles", output) cv2.waitKey(0) cv2.destroyAllWindows() ``` 这段脚本展示了完整的从读取文件直至渲染图形输出整个链条上的各个环节,并且包含了必要的配置选项让读者能够轻松复制运行起来观察具体行为表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值