图像处理基础及OpenCV实现(五)
五、 图像锐化
图像锐化与图像去噪的操作相反,是为了凸显图像一些轮廓和边缘,从而更好的对图像中的目标进行分割和识别,同样这样的操作也会增强噪声,故需要抑制一些噪声的方法。图像锐化的空域方法是利用微分实现的,常见的有一阶微分和二阶微分。因为图像边界信息往往是位于高频部分,利用频域的低通滤波来得到图像的高频信息也可以提取到边界信息。
1、 一阶微分法
图像的微分是利用梯度来实现的,而数字图像的微分运算一般使用差分来代替。
Roberts算子
水平和垂直方向的模板如下图:
将水平和垂直模板分别与图像卷积,最后计算的梯度可以表示为它们的平方平均或近似为它们的绝对值之和,如下式所示:
g(x,y)=|f(x,y)-f(x-1,y-1)|+|f(x-1,y)-f(x,y-1)|
Prewitt算子
考虑到目标像素周围的点,先求平均,再进行差分,水平和垂直方向的模板如下图:
Sobel算子
考虑到对距离的加权平均,一定程度的抑制噪声,水平和垂直方向的模板如下图:
其他模板如各向同性sobel算子、方向梯度模板等不再赘述可自行百度。
Opencv函数
CVAPI(void) cvSobel( const CvArr* src, CvArr* dst,
int xorder, int yorder,
int aperture_size CV_DEFAULT(3));
参数一:源图像
参数二:输出图像
参数三:x 方向上的差分阶数
参数四:y 方向上的差分阶数
参数五:核的大小,必须是1、3、5、7 。等于1时使用 3x1 或 1x3 内核。特殊变量 CV_SCHARR (=-1),对应 3x3 Scharr 滤波器, Scharr 滤波器系数是:
注1:sobel算子卷积出的结果会存在负号,因此源图像为8位无符号,输出图像应该保存为16位有符号数,然后再进行转换。代码如下:
IplImage *src, *dst;
src = cvCreateImage(cvGetSize(m_ipl), IPL_DEPTH_8U, 1);
cvCvtColor(m_ipl, src, CV_RGB2GRAY);
dst = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
dst_sobelX = cvCreateImage(cvGetSize(src), IPL_DEPTH_16S, 1);
cvSobel(src, dst_sobelX, 1, 0, 3);
cvConvertScaleAbs(dst_sobelX, dst, 1, 0);
注2:xorder和yorder只能取0,1,2的值且不能同时取0;一般xorder=1,yorder=0,表示水平的sobel算子,xorder=0,yorder=1,表示垂直的sobel算子。如下图分别是两个方向下的结果。
注3:xorder=1时边界像素值从低到高和从高到低卷积出来的结果符号相反,而xorder=2时避免了这种情况。下图分别为参数是2和它们之间的差的情况。
注4:在xorder和yorder同时有值的情况下,类似于先对图像求x方向的边界,再对图像求y方向的边界,而不是将x方向的边界结果与y方向边界结果绝对值相加。下图分别是xorder=1,yorder=1和先xorder=1,再将yorder=1的情况。可以看出它们的轮廓相同,但由于计算方式不同,后者的边界计算更宽。
注5:要求包含x方向和y方向的边界,可用上面求绝对值之和的方式来计算,代码如下:
cvSobel(src, dst_sobelX, 1, 0, 3);
cvConvertScaleAbs(dst_sobelX, dst, 1, 0);
cvNamedWindow(_T("dst_sobelX"));
cvShowImage(_T("dst_sobelX"), dst);
cvSobel(src, dst_sobelY, 0, 1, 3);
cvConvertScaleAbs(dst_sobelY, dst, 1, 0);
cvNamedWindow(_T("dst_sobelY"));
cvShowImage(_T("dst_sobelY"), dst);
cvAbs(dst_sobelX, dst_sobelXAbs);
cvAbs(dst_sobelY, dst_sobelYAbs);
cvAdd(dst_sobelXAbs, dst_sobelYAbs, dst_sobelAdd);
cvConvertScaleAbs(dst_sobelAdd, dst, 1, 0);
cvNamedWindow(_T("dst_sobelAdd"));
cvShowImage(_T("dst_sobelAdd"), dst);
输出结果如下:
最后用lena图实验:
2、 二阶微分法
二阶导数在边缘处过零点,而在边缘两旁的二阶导数异号,对图像的边缘细节响应更强,但同时也放大了噪声。
Laplace算子
Laplace算子是一个二阶微分算子,比较常见的模板如下:
图像锐化后可以使边缘更加鲜明。
Opencv函数
CVAPI(void) cvFilter2D( const CvArr* src, CvArr* dst,
const CvMat* kernel,
CvPoint anchor CV_DEFAULT(cvPoint(-1,-1)));
参数一:源图像
参数二:输出图像
参数三:核函数
参数四:默认是以核图像的中心做卷积
代码如下:
IplImage *g_src, *dst;
g_src = cvCreateImage(cvGetSize(m_ipl), IPL_DEPTH_8U, 1);
cvCvtColor(m_ipl, g_src, CV_RGB2GRAY);
cvNamedWindow(_T("源图像"));
cvShowImage(_T("源图像"), g_src);
dst = cvCreateImage(cvGetSize(g_src), IPL_DEPTH_8U, 1);
float m[9] = { 0,-1,0,-1,4,-1,0,-1,0 };
CvMat kernel = cvMat(2, 3, CV_32F, m);
cvFilter2D(g_src, dst, &kernel, cvPoint(-1, -1));
cvNamedWindow(_T("锐化后的图像"));
cvShowImage(_T("锐化后的图像"), dst);
cvReleaseImage(&g_src);
cvReleaseImage(&dst);
输出结果如下: