边缘检测概述

作用

边缘检测可以提取图像重要轮廓信息, 减少图像内容, 可以用于分割图像、做特征提取等

一般步骤

滤波—-(滤出噪声対检测边缘的影响)
增强—-(可以将像素邻域强度变化凸显出来—梯度算子)
检测—-(阈值方法确定边缘)

边缘检测算子

Canny算子
Sobel算子
Scharr算子
Laplacian算子
Roberts 算子、Prewitt算子… …

Canny边缘检测

Canny边缘检测算子是John F.Canny于1986 年开发出来的一个多级边缘检测算法, Canny边缘检测算法以Canny的名字命名, 被很多人推崇为当今最优的边缘检测的算法。

步骤

  1. 消除噪声
    一般情况使用高斯平滑滤波器卷积降噪
  2. 计算梯度幅值和方向
    安装Sobel滤波器的步骤操作
  3. OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_opencv

  4. 非极大值抑制
    排除非边缘像素
  5. 滞后阈值
    滞后阈值需要两个阈值(高阈值和低阈值)

Canny()

函数原型

void Canny( InputArray image, OutputArray edges,
            double threshold1, double threshold2,
            int apertureSize = 3, bool L2gradient = false );
  • src: 输入原图像(一般为单通道8位图像)
  • dst: 输出边缘图像要求和src一样的尺寸和类型(单通道)
  • threshold1: 滞后阈值低阈值(用于边缘连接)
  • threshold2: 滞后阈值高阈值(控制边缘初始段)
    推荐高低阈值比值在2:1到3:1之间
  • apertureSize: 表示Sobel算子孔径大小, 默认值3
  • L2gradient: 计算图像梯度幅值的标识

代码

Mat srcImg = imread("1.jpg", 0);
/*均值滤波---可以平滑图像,进行降噪处理,去除图像内部变化比较突兀的点*/
blur(srcImg, srcImg, Size(5, 5));
imshow("src", srcImg);
Mat dstImg;
/*边缘检测---设置两个阈值*/
Canny(srcImg, dstImg, 30, 80);
imshow("Canny", dstImg);
waitKey(0);

运行结果

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_默认值_02

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_opencv_03

注意

在实际应用中,可以使用trackbar来控制canny的两个参数,动态观察变化

sobel边缘检测

基本概念

Sobel算子是一个主要用于边缘检测的离散微分算子, 它结合了高斯平滑和微分求导, 用来计算图像灰度函数的近似梯度。

步骤

分别在x和y两个方向求导

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_边缘检测_04

sobel()函数

函数原型

void Sobel( InputArray src, OutputArray dst, int ddepth,
            int dx, int dy, int ksize = 3,
            double scale = 1, double delta = 0,
            int borderType = BORDER_DEFAULT );

src: 输入原图像

dst: 输出图像要求和src一样的尺寸和类型

ddepth: 输出图像的深度, 支持如下组合:

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_ci_05

dx: X方向上的差分阶数
dy: Y方向上的差分阶数
ksize: 默认值3, 表示Sobel核大小, 1,3,5,7
scale: 计算导数值时的缩放因子, 默认值1, 表示不缩放
delta(δ): 表示在结果存入目标图之前可选的delta值, 默认值0
borderType: 边界模式, 一般采用默认

代码

Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y , dst;

Mat src = imread("2.png", 0);
imshow("src", src);

Sobel(src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
imshow("X", abs_grad_x);

Sobel(src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
convertScaleAbs(grad_y, abs_grad_y);
imshow("Y", abs_grad_y);

addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
imshow("ALL ", dst);

waitKey(0);
destroyAllWindows();

知识点
1.CV_16S

Sobel(src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
imshow("X", abs_grad_x);

将图片的sobel检测以16位有符号的来进行存储,然后再将16位有符号数转为16位无符号数
2.读入以灰度图读入

Mat src = imread("2.png", 0);

运行结果

原图像

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_opencv_06

X方向

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_opencv_07

Y方向

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_OpenCV 抠图项目实战边缘检测报告_08

X+Y方向

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_ci_09

应用

计算摄像头聚焦程度

int FocusDetect0(Mat image){
    Mat gray;
    Mat grad_x,grad_y;
    Mat abs_grad_x,abs_grad_y;
    dst=img.clone();
    int rowNumber=image.rows();
    int colNumber=image.cols();
    float result=0;
    cvtColor(image,gray,COLOR_BGR2GRAY);//灰度转换

    /*X方向梯度*/
    Sobel(gray,grad_x,CV_16S,1,0,3,1,1,BORDER_DEFAULT);
    convertScaleAbs(grad_x,abs_grad_x);

    /*Y方向梯度*/
    Sobel(gray,grad_y,CV_16S,0,1,3,1,1,BORDER_DEFAULT);
    convertScaleAbs(grad_y,abs_grad_y);

    addWeighted(abs_grad_x,0.5,abs_grad_y,0.5,0,dst);
    imshow("Sobel",dst);

    /*访问像素*/
    for(int i=0;i<rowNumber;i++){
        uchar* data=dst.ptr<uchar>(i);//获取第i行的首地址
        for(int j=0;j<colNumber;j++){
            result+=float(data[j]);
        }
    }

    res_num=result/(rowNumber*colNumber);

    result=0;

}

对上面函数的引用

FocusDetect0(img);
sprintf(Num,"%0.2f",res_num);
Point org(35,35);
putText(frame,Num,org,CV_FONT_HERSHEY_SIMPLEX,1.2f,CV_RGB(0,255,0),2);

Laplacian边缘检测

基本概念

Laplacian算子是n维欧几里德中的一个二阶微分算子。

Laplacian算子的定义

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_边缘检测_10

Laplacian函数

函数原型

void Laplacian( InputArray src, OutputArray dst, int ddepth,
                int ksize = 1, double scale = 1, double delta = 0,
                int borderType = BORDER_DEFAULT );

src: 输入原图像(单通道8位图像)
dst: 输出边缘图像要求和src一样的尺寸和通道数
ddepth: 目标图像的深度
Ksize: 用于计算二阶导数的滤波器孔径大小, 须为正奇数, 默认值1
scale: 可选比例因子, 默认值1
delta: 可选参数δ, 默认值0
borderType: 边界模式, 一般采用默认值

代码

Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y, dst;
Mat abs_dst;

Mat src = imread("1.jpg", 0);
imshow("src", src);

Laplacian(src, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);
convertScaleAbs(dst, abs_dst);

imshow("Laplacian", abs_dst);

waitKey(0);
destroyAllWindows();

运行结果

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_OpenCV 抠图项目实战边缘检测报告_11

OpenCV 抠图项目实战边缘检测报告 opencv边缘检测算子_ci_12