用来表达微分的最常用的操作是Sobel微分算子。Sobel算子包含任意阶的微分以及融合偏导。
http://blog.csdn.net/tonyshengtan/article/details/43698711 这个帖关于Sobel的卷积算子怎么推导的有很详细的介绍;
下面我们看一下函数原型
CVAPI(void) cvSobel( const CvArr* src, CvArr* dst,
int xorder, int yorder,
int aperture_size CV_DEFAULT(3));
其中高src和dst分别是输入图像和输出图像,xorder和yorder是求到的阶数。通常只可能用到0,1,最多是2。值为0表示在这个方向上没有求导。
aperture_size参数是方形滤波器的宽(或高)并且应该是奇数。目前,该参数支持1,3,5,7。
如果愿图像src是八位的。为避免益处,目标图像的深度必须是IPL_DEPTH_16S。
Sobel导数有一个非常好的性质,即可以定义任意大小的核,并且这些核可以用快速且迭代的方式构造。大核对导数有更好的逼近,因为小核对噪声更敏感。
Sobel导数并不是真正的导数,因为Sobel算子定义于一个离散空间上。Sobel算子真正表示的是多项式拟合,也就是说,x方向上的二阶Sobel导数并不是真正的二阶导数。它是对抛物线的拟合。
练习:用一个3✖️3的中孔,对图像运行并显示一阶x和y方向的导数,然后将中孔大小增加到5 ✖️ 5 , 9 ✖️ 9 描述结果;
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
int main(int argc, const char * argv[]) {
/*1、加载一幅灰度图像*/
const char filename[] = "/Users/linwang/Downloads/4.png";
IplImage * Img = cvLoadImage(filename,CV_LOAD_IMAGE_GRAYSCALE);
/*2、缩小一倍*/
IplImage *out = cvCreateImage(cvSize(Img->width/2,Img->height/2), Img->depth, Img->nChannels);
cvResize(Img, out);
cvShowImage("1/2 Src", out);
/*3、Sobel分别在x方向求导数*/
IplImage *dst_x = cvCloneImage(out);
cvSetZero(dst_x);
cvSobel(out, dst_x, 1, 0, 3);
cvShowImage("Sobel_X_3", dst_x);
/*4、Sobel分别在y方向求导数*/
IplImage *dst_y = cvCloneImage(out);
cvSetZero(dst_y);
cvSobel(out, dst_y, 0, 1, 5);
cvShowImage("Sobel_Y_5", dst_y);
/*5、Sobel在x和y同时求导数*/
IplImage * dst_xy = cvCloneImage(out);
cvSetZero(dst_xy);
cvSobel(out, dst_xy, 1, 1 ,9);
cvShowImage("Sobel_XY_9", dst_xy);
cvWaitKey(0);
cvReleaseImage(&Img);
cvReleaseImage(&dst_x);
cvReleaseImage(&dst_y);
cvReleaseImage(&dst_xy);
return 0;
}