边缘检测
边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像像中亮度变化明显的点。图像属性
中
的显著变化通常反映了属性的重要事件和变化。
本文主要介绍Roberts cross算子,prewitt算子,canny算子,sobel算子和laplace算子
稍后我将所以代码放在最后,也可以在:http://download.csdn.net/detail/yuansanwan123/7053677下载
Roberts cross 算子
Roberts边缘检测算子是一种利用局部差分算子寻找边缘的算子,Robert算子图像处理后结果边缘不是很平滑。经分
析,由于Robert算子通常会在图像边缘附近的区域内 产生较宽的响应,故采用上述算子检测的边缘图像常需做细化
处理,边缘定位的精度不是很高。
卷积核:
robert水平算子
robert垂直算子
核心代码如下:
1 | 0 |
0 | -1 |
robert垂直算子
0 | 1 |
-1 | 0 |
void on_trackbar_roberts(int thresold)
{
int Gx=0,Gy=0,Zxy=0;
for(int i=0;i<g_imgGray->height-1;i++)
for(int j=0;j<g_imgGray->width-1;j++)
{
Gx = cvGet2D(g_imgGray,i,j).val[0]-cvGet2D(g_imgGray,i+1,j+1).val[0];
Gy = cvGet2D(g_imgGray,i,j+1).val[0]-cvGet2D(g_imgGray,i+1,j).val[0];
Zxy=(int)sqrt(Gx*Gx+Gy*Gy*1.0);
if(Zxy>thresold)
cvSet2D(g_imgRobert,i,j,cvScalar(Zxy));
else
cvSet2D(g_imgRobert,i,j,cvScalar(0));
}
cvShowImage(psWindowRobertTitle,g_imgRobert);
}
prewitt算子
Prewitt算子是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边
缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成
的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。
水平算子
1 | 1 | 1 |
0 | 0 | 0 |
-1 | -1 | -1 |
-1 | 0 | 1 |
-1 | 0 | 1 |
-1 | 0 | 1 |
void on_trackbar_Prewitt(int thresold)
{
int Gx=0,Gy=0,Zxy=0;
for(int i=1;i<g_imgGray->height-1;i++)
for(int j=1;j<g_imgGray->width-1;j++)
{
Gx = cvGet2D(g_imgGray,i,j+1).val[0]+cvGet2D(g_imgGray,i+1,j+1).val[0]+cvGet2D(g_imgGray,i-1,j+1).val[0]-
cvGet2D(g_imgGray,i,j-1).val[0]-cvGet2D(g_imgGray,i+1,j-1).val[0]-cvGet2D(g_imgGray,i-1,j-1).val[0];
Gy = cvGet2D(g_imgGray,i-1,j-1).val[0]+cvGet2D(g_imgGray,i-1,j+1).val[0]+cvGet2D(g_imgGray,i-1,j).val[0]-
cvGet2D(g_imgGray,i+1,j-1).val[0]-cvGet2D(g_imgGray,i+1,j).val[0]-cvGet2D(g_imgGray,i+1,j+1).val[0];
Zxy = (int)sqrt(Gx*Gx+Gy*Gy*1.0);
if(Zxy>thresold)
cvSet2D(g_imgPrewitt,i,j,cvScalar(Zxy));
else
cvSet2D(g_imgPrewitt,i,j,cvScalar(0));
}
cvShowImage(psWindowPrewittTitle,g_imgPrewitt);
}
sobel 算子
是一离散性差分算子,用来运算图像亮度函数的梯度之近似值。在图像的任何一点使用此算子,将会产生对应的梯
度矢量或是其法矢量
卷积核:
水平算子
-1 | -2 | -1 |
0 | 0 | 0 |
1 | 2 | 1 |
-1 | 0 | 1 |
-2 | 0 | 2 |
-1 | 0 | 1 |
void on_trackbar_sobel(int thresold)
{
int Gx=0,Gy=0,Zxy=0;
for(int i=1;i<g_imgGray->height-1;i++)
for(int j=1;j<g_imgGray->width-1;j++)
{
Gx = 2*cvGet2D(g_imgGray,i,j+1).val[0]+cvGet2D(g_imgGray,i+1,j+1).val[0]+cvGet2D(g_imgGray,i-1,j+1).val[0]-
2*cvGet2D(g_imgGray,i,j-1).val[0]-cvGet2D(g_imgGray,i+1,j-1).val[0]-cvGet2D(g_imgGray,i-1,j-1).val[0];
Gy = cvGet2D(g_imgGray,i-1,j-1).val[0]+cvGet2D(g_imgGray,i-1,j+1).val[0]+2*cvGet2D(g_imgGray,i-1,j).val[0]-
cvGet2D(g_imgGray,i+1,j-1).val[0]-2*cvGet2D(g_imgGray,i+1,j).val[0]-cvGet2D(g_imgGray,i+1,j+1).val[0];
Zxy = (int)sqrt(Gx*Gx+Gy*Gy*1.0);
if(Zxy>thresold)
cvSet2D(g_imgSobel,i,j,cvScalar(Zxy));
else
cvSet2D(g_imgSobel,i,j,cvScalar(0));
}
cvShowImage(psWindowSobelTitle,g_imgSobel);
}
canny算子
给大家推荐个网址:morewindows的博客:http://blog.csdn.net/morewindows/article/details/8239625
laplace算子
同样推荐个网址:小魏的修行路的博客:http://blog.csdn.net/xiaowei_cqu/article/details/7829481
好了,其他的不多说了,将所有代码贴上,在一个程序里查看各个算子的优劣。大家找个图,换一下路径并在vs2012
里运行就可以了(当然得装下opencv库)
代码如下:
//边缘检测
//by yuansanwan123
#include <iostream>
#include<opencv2/opencv.hpp>
#include <cmath>
IplImage *g_imgSrc = cvLoadImage("f:\\carlicense\\10.jpg");
IplImage *g_imgGray = cvCreateImage(cvGetSize(g_imgSrc),g_imgSrc->depth,1);
IplImage *g_imgRobert = cvCreateImage(cvGetSize(g_imgSrc),g_imgSrc->depth,1);
IplImage *g_imgCanny = cvCreateImage(cvGetSize(g_imgSrc),g_imgSrc->depth,1);
IplImage *g_imgPrewitt = cvCreateImage(cvGetSize(g_imgSrc),g_imgSrc->depth,1);
IplImage *g_imgSobel = cvCreateImage(cvGetSize(g_imgSrc),g_imgSrc->depth,1);
IplImage *g_imgLaplace = cvCreateImage(cvGetSize(g_imgSrc),g_imgSrc->depth,1);
char *psWindowRobertTitle = "robert算子边缘检测图";
char *psWindowCannyTitle = "Canny算子边缘检测图";
char *psWindowPrewittTitle = "Prewitt算子边缘检测图";
char *psWindowSobelTitle = "Sobel算子边缘检测图";
char *psWindowLaplaceTitle = "Laplace算子边缘检测图";
char *psWindowSrcTitle="源图像";
//cvCreateTrackbar的回调函数
void on_trackbar_roberts(int thresold)
{
int Gx=0,Gy=0,Zxy=0;
for(int i=0;i<g_imgGray->height-1;i++)
for(int j=0;j<g_imgGray->width-1;j++)
{
Gx = cvGet2D(g_imgGray,i,j).val[0]-cvGet2D(g_imgGray,i+1,j+1).val[0];
Gy = cvGet2D(g_imgGray,i,j+1).val[0]-cvGet2D(g_imgGray,i+1,j).val[0];
Zxy=(int)sqrt(Gx*Gx+Gy*Gy*1.0);
if(Zxy>thresold)
cvSet2D(g_imgRobert,i,j,cvScalar(Zxy));
else
cvSet2D(g_imgRobert,i,j,cvScalar(0));
}
cvShowImage(psWindowRobertTitle,g_imgRobert);
}
void on_trackbar_canny(int thresold)
{
cvCanny(g_imgGray,g_imgCanny,thresold,thresold*3);
cvShowImage(psWindowCannyTitle,g_imgCanny);
}
void on_trackbar_Prewitt(int thresold)
{
int Gx=0,Gy=0,Zxy=0;
for(int i=1;i<g_imgGray->height-1;i++)
for(int j=1;j<g_imgGray->width-1;j++)
{
Gx = cvGet2D(g_imgGray,i,j+1).val[0]+cvGet2D(g_imgGray,i+1,j+1).val[0]+cvGet2D(g_imgGray,i-1,j+1).val[0]-
cvGet2D(g_imgGray,i,j-1).val[0]-cvGet2D(g_imgGray,i+1,j-1).val[0]-cvGet2D(g_imgGray,i-1,j-1).val[0];
Gy = cvGet2D(g_imgGray,i-1,j-1).val[0]+cvGet2D(g_imgGray,i-1,j+1).val[0]+cvGet2D(g_imgGray,i-1,j).val[0]-
cvGet2D(g_imgGray,i+1,j-1).val[0]-cvGet2D(g_imgGray,i+1,j).val[0]-cvGet2D(g_imgGray,i+1,j+1).val[0];
Zxy = (int)sqrt(Gx*Gx+Gy*Gy*1.0);
if(Zxy>thresold)
cvSet2D(g_imgPrewitt,i,j,cvScalar(Zxy));
else
cvSet2D(g_imgPrewitt,i,j,cvScalar(0));
}
cvShowImage(psWindowPrewittTitle,g_imgPrewitt);
}
void on_trackbar_sobel(int thresold)
{
int Gx=0,Gy=0,Zxy=0;
for(int i=1;i<g_imgGray->height-1;i++)
for(int j=1;j<g_imgGray->width-1;j++)
{
Gx = 2*cvGet2D(g_imgGray,i,j+1).val[0]+cvGet2D(g_imgGray,i+1,j+1).val[0]+cvGet2D(g_imgGray,i-1,j+1).val[0]-
2*cvGet2D(g_imgGray,i,j-1).val[0]-cvGet2D(g_imgGray,i+1,j-1).val[0]-cvGet2D(g_imgGray,i-1,j-1).val[0];
Gy = cvGet2D(g_imgGray,i-1,j-1).val[0]+cvGet2D(g_imgGray,i-1,j+1).val[0]+2*cvGet2D(g_imgGray,i-1,j).val[0]-
cvGet2D(g_imgGray,i+1,j-1).val[0]-2*cvGet2D(g_imgGray,i+1,j).val[0]-cvGet2D(g_imgGray,i+1,j+1).val[0];
Zxy = (int)sqrt(Gx*Gx+Gy*Gy*1.0);
if(Zxy>thresold)
cvSet2D(g_imgSobel,i,j,cvScalar(Zxy));
else
cvSet2D(g_imgSobel,i,j,cvScalar(0));
}
cvShowImage(psWindowSobelTitle,g_imgSobel);
}
void on_trackbar_laplace(int thresold)
{
int Gx=0,Gy=0,Zxy=0;
for(int i=1;i<g_imgGray->height-1;i++)
for(int j=1;j<g_imgGray->width-1;j++)
{
Gy = 2*cvGet2D(g_imgGray,i,j).val[0]-cvGet2D(g_imgGray,i-1,j).val[0]-cvGet2D(g_imgGray,i+1,j).val[0];
Gx = 2*cvGet2D(g_imgGray,i,j).val[0]-cvGet2D(g_imgGray,i,j-1).val[0]-cvGet2D(g_imgGray,i,j+1).val[0];
Zxy=Gx+Gy;
//或者直接计算
//Zxy= 4*cvGet2D(g_imgGray,i,j).val[0]-cvGet2D(g_imgGray,i,j+1).val[0]-cvGet2D(g_imgGray,i,j-1).val[0]-
//cvGet2D(g_imgGray,i-1,j).val[0]-cvGet2D(g_imgGray,i+1,j).val[0];
if(Zxy>thresold)
cvSet2D(g_imgLaplace,i,j,cvScalar(Zxy));
else
cvSet2D(g_imgLaplace,i,j,cvScalar(0));
}
cvShowImage(psWindowLaplaceTitle,g_imgLaplace);
}
int main( int argc, char** argv )
{
//对图像灰度化
cvCvtColor(g_imgSrc,g_imgGray,CV_BGR2GRAY);
cvZero(g_imgRobert);
cvZero(g_imgCanny);
cvZero(g_imgPrewitt);
cvZero(g_imgSobel);
cvZero(g_imgLaplace);
//创建窗口
cvNamedWindow(psWindowRobertTitle);
cvNamedWindow(psWindowSrcTitle);
cvNamedWindow(psWindowCannyTitle);
cvNamedWindow(psWindowPrewittTitle);
cvNamedWindow(psWindowSobelTitle);
cvNamedWindow(psWindowLaplaceTitle);
//创建滑动条
char *trackbar="robert_thresold",*trackbar_Canny="Canny_thresold",*trackbar_Prewitt="Prewitt_thresold";
char *trackbar_Sobel="Sobel_thresold",*trackbar_Laplace="Laplace_thresold";
int value=1;
cvCreateTrackbar(trackbar_Laplace,psWindowLaplaceTitle,&value,255,on_trackbar_laplace);
cvCreateTrackbar(trackbar_Sobel,psWindowSobelTitle,&value,255,on_trackbar_sobel);
cvCreateTrackbar(trackbar_Prewitt,psWindowPrewittTitle,&value,255,on_trackbar_Prewitt);
cvCreateTrackbar(trackbar_Canny,psWindowCannyTitle,&value,255,on_trackbar_canny);
cvCreateTrackbar(trackbar,psWindowRobertTitle,&value,255,on_trackbar_roberts);
on_trackbar_roberts(1);
on_trackbar_canny(1);
on_trackbar_Prewitt(1);
on_trackbar_sobel(1);
on_trackbar_laplace(1);
//在指定窗口中显示图像
cvShowImage(psWindowSrcTitle,g_imgSrc);
//等待按键事件
cvWaitKey(0);
//释放内存
cvDestroyAllWindows();
cvReleaseImage(&g_imgRobert);
cvReleaseImage(&g_imgGray);
cvReleaseImage(&g_imgSrc);
cvReleaseImage(&g_imgCanny);
cvReleaseImage(&g_imgLaplace);
cvReleaseImage(&g_imgPrewitt);
cvReleaseImage(&g_imgSobel);
return 0;
}