OpenCV中的Sobel算子

OpenCV中的Sobel算子

刚开始第一次接触这个东西的时候也是感觉一脸懵逼,这是什么鬼。完全看不懂。今天再次接触到,感觉理解的透彻了一点。
首先来看一下Sobel算子是个什么东西:

-101
-202
-101

这个就是Sobel算子中的一个,就以这个为例。可以看出来这个就是之前说的那个核。用这个核去和原图像进行卷积操作。那根据核可以知道,卷积过后得到的输出图像中每个点的像素值,为两列差的和,回想一下求导的定义式,函数的差值/自变量的差值。所以这里得到的输出图像的每个点的值,可以看成原图像在该点的导数。因为图像的是二维的,所以以上所说都是在X方向。
根据这个理论,不难知道,在边缘处像素值发生了显著的变化,表示这一变化一个方法就是利用导数。
Y方向的算子:

-1-2-1
000
121

道理和X方向的相同。
下面看一下X方向的导数的手动实现吧!

Mat Soble(const Mat src,const Mat_<int> kernel)
{
    Mat dst,temp,s;
    temp = Mat::zeros(src.size(),src.type());
    src.copyTo(dst);
    kernel.copyTo(s);
    int height = src.rows;
    int width = src.cols;
    int size = kernel.rows;
    int add = (size-1)/2;

    uchar* pre;
    uchar* cur;
    uchar* next;
    int* ker = s.ptr<int>(0);

    for(int row = 0;row < height-1;row++)
    {
        pre = dst.ptr<uchar>(row-1);
        cur = dst.ptr<uchar>(row);
        next = dst.ptr<uchar>(row+1);
        for(int col = 0;col < width - 1;col++)
        {
            temp.at<uchar>(row,col) = saturate_cast<uchar>(pre[col-1]*ker[0] + pre[col]*ker[1] + pre[col+1]*ker[2]
                                                          +cur[col-1]*ker[3] + cur[col]*ker[4] + cur[col+1]*ker[5]
                                                          +next[col-1]*ker[6] + next[col]*ker[7] + next[col+1]*ker[8]
                                                        );
        }
    }
    imshow("temp",temp);
    return temp;

}

编写的流程与自定义线性滤波器那块是一样的。
同样的OpenCV为了我们方便,也提供了相应的API:

Sobel(
	输入图像,
	输出图像,
	图像深度,CV_16S防止外溢
	x方向的导数的阶数,
	y方向的导数的阶数,
	scale,默认为1,
	delta,默认为0;
	BORDER_DEFAULT	
);

下面是完整的代码:

#include <ros/ros.h>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;


Mat Soble(const Mat src,const Mat_<int> kernel);

int main(int argc, char *argv[])
{
    Mat src,dst;
    src = imread("/home/dynamicw/Project/C++_Project/opencvtest/src/lesson01/source/map.png",0);
    imshow("src",src);
    GaussianBlur(src,src,Size(3,3),0,0,BORDER_DEFAULT);
    Mat_<int> kernel = (Mat_<int>(3,3) << -1,0,1,-2,0,2,-1,0,1);
    Soble(src,kernel);
    Sobel(src,dst,CV_16S,1,0,3,1,0,BORDER_DEFAULT);
    imshow("apt",dst);
    convertScaleAbs(dst,src);
    imshow("api",src);
    waitKey(0);
    return 0;
}

Mat Soble(const Mat src,const Mat_<int> kernel)
{
    Mat dst,temp,s;
    temp = Mat::zeros(src.size(),src.type());
    src.copyTo(dst);
    kernel.copyTo(s);
    int height = src.rows;
    int width = src.cols;
    int size = kernel.rows;
    int add = (size-1)/2;

    uchar* pre;
    uchar* cur;
    uchar* next;
    int* ker = s.ptr<int>(0);

    for(int row = 0;row < height-1;row++)
    {
        pre = dst.ptr<uchar>(row-1);
        cur = dst.ptr<uchar>(row);
        next = dst.ptr<uchar>(row+1);
        for(int col = 0;col < width - 1;col++)
        {
            temp.at<uchar>(row,col) = saturate_cast<uchar>(pre[col-1]*ker[0] + pre[col]*ker[1] + pre[col+1]*ker[2]
                                                          +cur[col-1]*ker[3] + cur[col]*ker[4] + cur[col+1]*ker[5]
                                                          +next[col-1]*ker[6] + next[col]*ker[7] + next[col+1]*ker[8]
                                                        );
        }
    }
    imshow("temp",temp);
    return temp;

}

其中,通常在进行Sobel时,要先进行高斯模糊,具体原因未知。
其次,求完导数以后,得到的图像中部分像素会是负值,或者超过了255,所以利用convertScaleAbs(src,dst)来将图像的每个像素变为0~255之间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值