数字图像的边缘检测

边缘检测算子

Sobel算子

常用的Sobel边缘检测算子有两种,一种是常用的,另一种的改进的,就是对Sobel算子中的2取其平方根作为新的值,也就是如下:
通常的Sobel算子:
水平检测算子:
-1     -2    -1
0    0    0
1    2    1
垂直检测算子:
-1    0    1
-2    0    2
-1    0    1
改进后的各向同性的Sobel算子:
水平检测算子:
-1    -sqrt(2)    -1
0    0    0
1    sqrt(2)    1
垂直检测算子:
-1    0    1
-sqrt(2)    0    sqrt(2)
-1    0    1

LOG算子

也就是高斯拉普拉斯算子,也可以叫做墨西哥草帽检测算子,有3*3和5*5两种,比较常用的是5*5的。算子如下:
double *Temp=new double[25];
 Temp[0]=Temp[4]=-2;
 Temp[1]=Temp[2]=Temp[3]=-4;
 Temp[5]=-4;
 Temp[6]=0;
 Temp[7]=8;
 Temp[8]=0;
 Temp[9]=Temp[10]=-4;
 Temp[11]=8;
 Temp[12]=24;
 Temp[13]=8;
 Temp[14]=-4;
 Temp[15]=-4;
 Temp[16]=0;
 Temp[17]=8;
 Temp[18]=0;
 Temp[19]=-4;
 Temp[20]=-2;
 Temp[21]=Temp[22]=Temp[23]=-4;
 Temp[24]=-2;

对图像进行模板操作的函数

要对图像进行的很多操作,其实都可以归结到对图形进行模板操作上面,比如图像的锐化和滤波,当然还有经典的边缘检测算子了,就是Sobel、LOG算子等。所以,我们有必要写一个对图形进行模板操作的函数,这样后面就能避免不少的麻烦。另外,我这里的模板程序种只考虑了8位的位图,对于24位的位图需要先转化为24位的灰度图,然后对其进行边缘检测。不过我想如果分别对RGB各分量进行边缘检测的结果会如何呢?还真的不知道,有时间尝试下。目前我们所说的边缘检测,通常都是对灰度图像来说的。
#include "math.h"
/******************************************************************************
*函数功能:对一副图像进行模板操作
*函数声明:void TemplateTIM(
     BYTE* srcImage,  -指向源图像像素数据的指针
     BYTE* dstImage,  -指向目的图像像素数据的指针
     LONG imageWidth,  -源图像的宽度
     LONG imageHeight, -源图像的高度
     int nTempSize,  -模板的大小
     double* TempData, -指向模板数组的指针
     double TempCoef,  -模板的系数
     BYTE BitCount,  -图片的位数
     )
******************************************************************************/
void TemplateTIM(BYTE* srcImage,BYTE *dstImage,LONG imageWidth,LONG imageHeight,
     int nTempSize,double* TempData,double TempCoef,BYTE BitCount=8)
{
 //检查模板的大小不能为偶数,且不为1
 if(nTempSize%2==0 || nTempSize==1)
 {
  AfxMessageBox("模板的大小需为奇数且不为1");
  return;
 }
 //计算应该除去的图像边缘的列数
 int n=(nTempSize-1)/2;
 //保存计算的像素值加权后的值
 double res;
 if(BitCount==8)
 {
  //从图像的左下角进行模板操作
  for(int i=n;i<imageHeight-n;i++)
  {
   for(int j=n;j<imageWidth-n;j++)
   {
    //设置累计变量的值为0
    res=0.0;
    //计算模板内的各像素点的值
    for(int k=0;k<nTempSize;k++)
    {
     for(int l=0;l<nTempSize;l++)
     {
      BYTE pixel=*(srcImage+imageWidth*(i+n-k)+(j-n+l));
      res+=pixel*TempData[k*nTempSize+l];
     }
    }
    //根据模板系数计算新的像素值
    res*=TempCoef;
    res=(double)fabs(res);
    if(res>255)
    {
     *(dstImage+imageWidth*i+j)=255;
    }
    else
    {
     *(dstImage+imageWidth*i+j)=(BYTE)(res+0.5);
    }
   }
  }
 }
 else if(BitCount==24)
 {
  AfxMessageBox("暂时不支持24位图片");
  return;
 }
 else
 {
  AfxMessageBox("暂时只能处理8或24位图片");
  return;
 }
 
}

Visual C++6.0中进行数字图像的边缘检测试验

新建一个基于对话框的MFC应用程序

如何创建在这里就不啰嗦了。当然,创建之后需要添加按钮,而且还需要一个选择用哪个Sobel算子的对话框,这里不会详细的说明,主要在于模板操作函数和如何调用该函数。至于其他的繁琐的操作都是基本功,不说了。

Sobel检测算子按钮下的程序

void CICETIMDlg::OnBtnSobeledge()
{
 // TODO: Add your control notification handler code here
 if(m_dib.GetHeight()==0)
 {
  AfxMessageBox("请先打开图片");
  return;
 }
 
 int sel;
 CSobelArgumentDlg *dlg=new CSobelArgumentDlg();
 if(dlg->DoModal()==IDOK)
 {
  sel=dlg->m_sel;
 }
 else
 {
  return;
 }
 delete dlg;
 double *Temp=new double[9];
 switch(sel)
 {
 case 1:
  Temp[0]=-1;
  Temp[1]=-2;
  Temp[2]=-1;
  Temp[3]=0;
  Temp[4]=0;
  Temp[5]=0;
  Temp[6]=1;
  Temp[7]=2;
  Temp[8]=1;
  break;
 case 2:
  Temp[0]=-1;
  Temp[1]=0;
  Temp[2]=1;
  Temp[3]=-2;
  Temp[4]=0;
  Temp[5]=2;
  Temp[6]=-1;
  Temp[7]=0;
  Temp[8]=1;
  break;
 case 3:
  Temp[0]=-1;
  Temp[1]=-sqrt(2);
  Temp[2]=-1;
  Temp[3]=0;
  Temp[4]=0;
  Temp[5]=0;
  Temp[6]=1;
  Temp[7]=sqrt(2);
  Temp[8]=1;
  break;
 case 4:
  Temp[0]=-1;
  Temp[1]=0;
  Temp[2]=1;
  Temp[3]=-sqrt(2);
  Temp[4]=0;
  Temp[5]=sqrt(2);
  Temp[6]=-1;
  Temp[7]=0;
  Temp[8]=1;
  break;
 default:
  Temp[0]=-1;
  Temp[1]=-2;
  Temp[2]=-1;
  Temp[3]=0;
  Temp[4]=0;
  Temp[5]=0;
  Temp[6]=1;
  Temp[7]=2;
  Temp[8]=1;
  break;
 }
 if(m_dib.GetBitCount()==8)
 {
  BYTE* newImage=new BYTE[m_dib.GetHeight()*m_dib.GetLineBytes()];
  TemplateTIM(m_dib.GetDibData(),newImage,m_dib.GetWidth(),m_dib.GetHeight(),3,Temp,(double)1);
  m_dib.SetDibData(newImage);
  ShowImage(m_dib,"SOBEL边缘检测");
  delete[] Temp;
 }
 else
 {
  AfxMessageBox("暂时只处理8位位图");
  return;
 }
}

LOG检测算子按钮下的程序

void CICETIMDlg::OnBtnLogedge()
{
 // TODO: Add your control notification handler code here
 if(m_dib.GetHeight()==0)
 {
  AfxMessageBox("请先打开图片");
  return;
 }
 double *Temp=new double[25];
 Temp[0]=Temp[4]=-2;
 Temp[1]=Temp[2]=Temp[3]=-4;
 Temp[5]=-4;
 Temp[6]=0;
 Temp[7]=8;
 Temp[8]=0;
 Temp[9]=Temp[10]=-4;
 Temp[11]=8;
 Temp[12]=24;
 Temp[13]=8;
 Temp[14]=-4;
 Temp[15]=-4;
 Temp[16]=0;
 Temp[17]=8;
 Temp[18]=0;
 Temp[19]=-4;
 Temp[20]=-2;
 Temp[21]=Temp[22]=Temp[23]=-4;
 Temp[24]=-2;
 if(m_dib.GetBitCount()==8)
 {
  BYTE* newImage=new BYTE[m_dib.GetHeight()*m_dib.GetLineBytes()];
  TemplateTIM(m_dib.GetDibData(),newImage,m_dib.GetWidth(),m_dib.GetHeight(),5,Temp,(double)1);
  m_dib.SetDibData(newImage);
  ShowImage(m_dib,"LOG边缘检测");
  delete[] Temp;
 }
 else
 {
  AfxMessageBox("暂时只处理8位位图");
  return;
 }
}
 

选择Sobel检测算子对话框

在OnInitialDialog函数中需要设置默认选项:
BOOL CSobelArgumentDlg::OnInitDialog()
{
 CDialog::OnInitDialog();
 
 // TODO: Add extra initialization here
 ((CButton*)GetDlgItem(IDC_RADIO2))->SetCheck(true);
 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
需要新建一个整形的成员变量m_sel,然后在每个单选按钮下面写下如下的程序:
void CSobelArgumentDlg::OnRadio2()
{
 // TODO: Add your control notification handler code here
 m_sel=1;
}
void CSobelArgumentDlg::OnRadio3()
{
 // TODO: Add your control notification handler code here
 m_sel=2;
}
void CSobelArgumentDlg::OnRadio4()
{
 // TODO: Add your control notification handler code here
 m_sel=3;
}
void CSobelArgumentDlg::OnRadio5()
{
 // TODO: Add your control notification handler code here
 m_sel=4;
}

程序运行时截图

Sobel检测算子

原始图片如下,是8位的位图。

LOG边缘检测算子

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值