1)sobel算子
计算机视觉领域的一种重要处理方法。主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。在技术上,它是一个离散的一阶差分算子,用来计算图像亮度函数的一阶梯度之近似值。在图像的任何一点使用此算子,将会产生该点对应的梯度矢量或是其法矢量。
该算子是由两个卷积核与对原图像进行卷积运算而得到的。其数学表达式为:
实际上Sobel边缘算子所采用的算法是先进行加权平均,然后进行微分运算,我们可以用差分代替一阶偏导,算子的计算方法如下:
(6)
Sobel算子垂直方向和水平方向的模板如图(B)所示,前者可以检测出图像中的水平方向的边缘,后者则可以检测图像中垂直方向的边缘。实际应用中,图像中的每一个像素点都用这两个卷积核进行卷积运算,取其最大值作为输出。运算结果是一幅体现边缘幅度的图像。
图(B)Sobel算子模板
该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经纵向向及横向边缘检测的图像,其公式如下:
图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。
然后可用以下公式计算梯度方向。
在以上例子中,如果以上的角度Θ等于零,即代表图像该处拥有纵向边缘,左方较右方暗。
在边缘检测中,常用的一种模板是Sobel 算子。Sobel 算子有两个,一个是 检测水平边缘 的 ;另一个是 检测垂直边缘 的 。与Prewitt算子相比,Sobel算子对于象素的位置的影响做了加权,可以降低边缘模糊程度,因此效果更好。
Sobel算子另一种形式是各向同性Sobel(Isotropic Sobel)算子,也有两个,一个是检测水平边缘的 ,另一个是检测垂直边缘的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。将Sobel算子矩阵中的所有2改为根号2,就能得到各向同性Sobel的矩阵。
由于Sobel算子是滤波算子的形式,用于提取边缘,可以利用快速卷积函数, 简单有效,因此应用广泛。美中不足的是,Sobel算子并没有将图像的主体与背景严格地区分开来,换言之就是Sobel算子没有基于图像灰度进行处理,由于Sobel算子没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。 在观测一幅图像的时候,我们往往首先注意的是图像与背景不同的部分,正是这个部分将主体突出显示,基于该理论,我们给出了下面阈 值化轮廓提取算法,该算法已在数学上证明当像素点满足正态分布时所求解是最优的。
void cvSobel( CvArr* src,CvArr* dst, int xorder,int yorder,int aperture_size = 3);
src 输入图像.
dst 输出图像.
xorder和yorder是求导的阶数,
aperture_size 核大小.函数。
Sobel导数有一个很好的性质,可以定义任意大小的核,并且这些核可以用快速且迭代的方式构造。大核对导数有更好的逼近,小核对噪声更敏感。
函数 cvSobel 通过对图像用相应的内核进行卷积操作来计算图像差分:
由于Sobel 算子结合了 Gaussian 平滑和微分,所以,其结果或多或少对噪声有一定的鲁棒性。通常情况,函数调用采用如下参数 (xorder=1, yorder=0, aperture_size=3) 或 (xorder=0, yorder=1, aperture_size=3) 来计算一阶 x- 或 y- 方向的图像差分。Sobel导数有一个很好的性质,可以定义任意大小的核,并且这些核可以用快速且迭代的方式构造。大核对导数有更好的逼近,小核对噪声更敏感。
函数 cvSobel 通过对图像用相应的内核进行卷积操作来计算图像差分:
由于Sobel 算子结合了 Gaussian 平滑和微分,所以,其结果或多或少对噪声有一定的鲁棒性。通常情况,函数调用采用如下参数 (xorder=1, yorder=0, aperture_size=3) 或 (xorder=0, yorder=1, aperture_size=3) 来计算一阶 x- 或 y- 方向的图像差分。
核则依赖于图像原点的定义 (origin 来自 IplImage 结构的定义)。由于该函数不进行图像尺度变换,所以和输入图像(数组)相比,输出图像(数组)的元素通常具有更大的绝对数值(译者注:即象素的深度)。为防止溢出,当输入图像是 8 位的,要求输出图像是 16 位的。当然可以用函数cvConvertScale 或 cvConvertScaleAbs 转换为 8 位的。除了 8-比特 图像,函数也接受 32-位 浮点数 图像。所有输入和输出图像都必须是单通道的,并且具有相同的图像尺寸或者ROI尺寸。
2)cvCmpS函数 比较图像的像素点与value
void cvCmpS(const CvArr* src1, //输入图像
double value, //给定像素值
CvArr* dst, //输出图像
int cmp_op,)//比较方法
3)cvAvg计算数组平均像素值
CvScalar cvAvg(const CvArr* arr, const CvArr* mask =NULL);
计算数组arr的平均像素值,如果mask为非空,那么平均值仅由那些mask值为非0的元素相对应的像素算出。
代码:
#include
#include
#include
#include
using namespace std;
const CvSize size = cvSize(200,200);
const int aperture[] = {3,5,9,11,13,17};//滤波器的核
int main()
{
IplImage *src = cvCreateImage(size,8,1);
cvZero(src);
//cvPoint(0,size.height - 1) 45度直线
//cvPoint(size.width -1 , 0)
cvLine(src,cvPoint(0,0),cvPoint(size.width - 1, size.height - 1),
CV_RGB(255,255,255),3);
cvShowImage("src",src);
cvSaveImage("src.jpg",src);
IplImage *deriv_x = cvCreateImage(size,IPL_DEPTH_32F,1);
IplImage *deriv_y = cvCreateImage(size,IPL_DEPTH_32F,1);
IplImage *magnitude = cvCreateImage(size,IPL_DEPTH_32F,1);
IplImage *angle = cvCreateImage(size,IPL_DEPTH_32F,1);
IplImage *mask = cvCreateImage(size,IPL_DEPTH_8U,1);
for(int i=0;i {
cvSobel(src,deriv_x,1,0,aperture[i]);//x横坐标方向进行一阶求导
cvSobel(src,deriv_y,0,1,aperture[i]);//y纵坐标方向进行一阶求导
cvCartToPolar(deriv_x,deriv_y,magnitude,angle,1);//将坐标从普通坐标转化为极坐标
cvSave("x.xml",deriv_x);
cvSave("y.xml",deriv_y);
cvSave("magnitude.xml",magnitude);
cvSave("angle.xml",angle);
double max_mag ,min_mag ,max_angle , min_angle;
cvMinMaxLoc(magnitude,&min_mag,&max_mag);//幅值求最大最小
cvMinMaxLoc(angle,&min_angle,&max_angle);//角度求最大最小
cout<<"magnitude: max = "<cout<<"angle : max = "<
cvCmpS(magnitude,max_mag*3/4,mask,CV_CMP_GT);//比较图像的像素点与max_mag*3/4的值
cvShowImage("mask",mask);
cvSaveImage("mask.jpg",mask);
CvScalar scalar = cvAvg(angle,mask);//计算数组平均像素值
cout<<"aperture = "<cvWaitKey();
}
cvReleaseImage(&src);
cvReleaseImage(&magnitude);
cvReleaseImage(&angle);
cvReleaseImage(&mask);
cvDestroyAllWindows();
}
效果:
由于水平有限原因,暂时还不能很好的解析输出结果之间的差异和比较的结果。具体分析等理解之后再更新。
在以上例子中,如果以上的角度Θ等于零,即代表图像该处拥有纵向边缘,左方较右方暗。