图像的边缘检测

物体边缘是图像中重要信息,提取图像中边缘信息对于分析图像中内容,以及实现图像中物体的分割、定位具有重要的作用

图像边缘提取算法已经非常成熟,OpenCV4中提供了多个用于边缘检测的函数

边缘检测原理convertScaleAbs()

图像的边缘指的是图像中像素灰度值突然发生变化的区域,如果将图像的每一列、每一行像素都描述成一个关于灰度值的函数

那么图像的边缘对应在灰度值函数中是函数值突然变大的区域,函数值的变化趋势可以用函数的导数描述

当函数值突然变大时,导数也必然会突然变大,而函数值变化较为平缓区域,导数值也比较小,因此可以通过寻找导数值较大的区域

寻找函数中突然变化的区域,进而确定图像中的边缘区域

对灰度值曲线求取一阶导数可以得到图像,通过该曲线可以看出,该曲线的最大值所在区域就是图像中边缘所在区域

对灰度值曲线求取一阶导数可以得到图像,通过该曲线可以看出,该曲线的最大值所在区域就是图像中边缘所在区域

由于图像是离散的信号,因此可以用临近的两个像素差值表示灰度值函数的导数,这种对x轴方向求导对应滤波器为[-1,1]

但是这种求导方式的计算结果最接近两个像素中间位置的梯度,而两个临近的像素中间不再由任何的像素

改进的求导方式对应的滤波器在X方向滤波器为[-0.5,0,0.5]

在计算45°方向的梯度,寻找不同方向的边缘

XY = |1 0| YX = |0 1|

|0 -1| |-1 0|

图像的边缘有可能是由高像素值变为低像素值,也有可能是由低像素值变为高像素值,因此为了在图像中同时表示出这两种边缘信息

需要将计算的结果求取绝对值

OpenCV4提供了convertScaleAbs()函数用于计算矩阵中所有数据的绝对值

convertScaleAbs()函数原型:

void convertScaleAbs(InputArray src,
                     OutputArray dst,
                     double alpha = 1,
                     double beta = 0
                     )
  • src:输入矩阵
  • dst:计算绝对值后输出矩阵
  • alpha:缩放因子,默认参数为只求取绝对值而不进行缩放
  • beta:在原始数据上添加偏值,默认参数表示不增加偏值

该函数可以求取矩阵中所有数据的绝对值,前两个参数为输入、输出矩阵,可以是相同的变量

第三、四个参数为对绝对值的缩放和原始数据上的偏移

图像的边缘包含x轴方向的边缘和y轴方向的边缘,因此,在分别求取两个方向的边缘后,对两个方向的边缘求取并集就是整幅图像的边缘

即将图像的两个方向边缘结果相加得到整幅的边缘信息

示例程序:利用filter2D()函数实现图像边缘检测的算法,由于求取边缘的结果可能由负数,不在CV_8U的数据类型内

因此,滤波后的图像数据类型应该改为CV_16S

示例:

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
    //创建边缘滤波器
    Mat kernel1 = (Mat_<float>(1,2) << 1,-1); //X方向边缘检测滤波器
    Mat kernel2 = (Mat_<float>(1,3) << 1,0,-1); //X方向边缘检测滤波器
    Mat kernel3 = (Mat_<float>(3,1) << 1,0,-1); //Y方向边缘检测滤波器
    Mat kernelXY = (Mat_<float>(2,2) << 1,0,0,-1); //由左上到右下方向边缘检测滤波器
    Mat kernelYX = (Mat_<float>(2,2) << 0,-1,1,0); //由右上到左下方向边缘检测滤波器
    //读取图像,黑白图像边缘检测结果较为明显
    Mat img = imread("E:\\CLion\\opencv_xin\\SG\\SG_0.jpg",IMREAD_ANYCOLOR);
    if (img.empty())
    {
        cout << "error" << endl;
        return -1;
    }
    Mat result1,result2,result3,result4,result5,result6;
    //检测图像边缘
    //以[1 -1]检测水平方向方向边缘
    filter2D(img,result1,CV_16S,kernel1);
    convertScaleAbs(result1,result1);
    //以[1 0 -1]检测水平方向方向边缘
    filter2D(img,result2,CV_16S,kernel2);
    convertScaleAbs(result2,result2);
    //以[1 0 -1]检测垂直方向方向边缘
    filter2D(img,result3,CV_16S,kernel3);
    convertScaleAbs(result3,result3);
    //整幅图像的边缘
    result6 = result2 + result3;
    //检测由左上到右下方向边缘
    filter2D(img,result4,CV_16S,kernelXY);
    convertScaleAbs(result4,result4);
    //检测由右上到左下方向边缘
    filter2D(img,result5,CV_16S,kernelYX);
    convertScaleAbs(result5,result5);
    //显示边缘检测结果
    imshow("result1",result1);
    imshow("result2",result2);
    imshow("result3",result3);
    imshow("result4",result4);
    imshow("result5",result5);
    imshow("result6",result6);
    waitKey(0);
    return 0;
}

results matching ""

    No results matching ""