canny 算子代码
void CreatGauss(double sigma, double **pdKernel, int *pnWidowSize);
void GaussianSmooth(SIZE sz, LPBYTE pGray, LPBYTE pResult, double sigma);
void Grad(SIZE sz, LPBYTE pGray, int *pGradX, int *pGradY, int *pMag);
void NonmaxSuppress(int *pMag, int *pGradX, int *pGradY, SIZE sz, LPBYTE pNSRst);
void EstimateThreshold(int *pMag, SIZE sz, int *pThrHigh, int *pThrLow, LPBYTE pGray,
double dRatHigh, double dRatLow);
void Hysteresis(int *pMag, SIZE sz, double dRatLow, double dRatHigh, LPBYTE pResult);
void TraceEdge(int y, int x, int nThrLow, LPBYTE pResult, int *pMag, SIZE sz);
void Canny(LPBYTE pGray, SIZE sz, double sigma, double dRatLow,
double dRatHigh, LPBYTE pResult);
#include "afx.h"
#include "math.h"
#include "canny.h"
// 一维高斯分布函数,用于平滑函数中生成的高斯滤波系数
void CreatGauss(double sigma, double **pdKernel, int *pnWidowSize)
{
LONG i;
//数组中心点
int nCenter;
//数组中一点到中心点距离
double dDis;
//中间变量
double dValue;
double dSum;
dSum = 0;
// [-3*sigma,3*sigma] 以内数据,会覆盖绝大部分滤波系数
*pnWidowSize = 1+ 2*ceil(3*sigma);
nCenter = (*pnWidowSize)/2;
*pdKernel = new double[*pnWidowSize];
//生成高斯数据
for(i=0;i<(*pnWidowSize);i++)
{
dDis = double(i - nCenter);
dValue = exp(-(1/2)*dDis*dDis/(sigma*sigma))/(sqrt(2*3.1415926)*sigma);
(*pdKernel)[i] = dValue;
dSum+=dValue;
}
//归一化
for(i=0;i<(*pnWidowSize);i++)
{
(*pdKernel)[i]/=dSum;
}
}
//用高斯滤波器平滑原图像
void GaussianSmooth(SIZE sz, LPBYTE pGray, LPBYTE pResult, double sigma)
{
LONG x, y;
LONG i;
//高斯滤波器长度
int nWindowSize;
//窗口长度
int nLen;
//一维高斯滤波器
double *pdKernel;
//高斯系数与图像数据的点乘
double dDotMul;
//滤波系数总和
double dWeightSum;
double *pdTemp;
pdTemp = new double[sz.cx*sz.cy];
//产生一维高斯数据
CreatGauss(sigma, &pdKernel, &nWindowSize);
nLen = nWindowSize/2;
//x 方向滤波
for(y=0;y=0 && (i+x)=0 && (i+y)< sz.cy)
{
dDotMul += (double)pdTemp[(y+i)*sz.cx+x]*pdKernel[nLen+i];
dWeightSum += pdKernel[nLen+i];
}
}
pResult[y*sz.cx+x] = (unsigned char)dDotMul/dWeightSum;
}
}
delete []pdKernel;
pdKernel = NULL;
delete []pdTemp;
pdTemp = NULL;
}
// 方向导数,求梯度
void Grad(SIZE sz, LPBYTE pGray,int *pGradX, int *pGradY, int *pMag)
{
LONG y,x;
//x 方向的方向导数
for(y=1;y
dSqt2 = pGradY[y*sz.cx + x]*pGradY[y*sz.cx + x];
pMag[y*sz.cx+x] = (int)(sqrt(dSqt1+dSqt2)+0.5);
}
}
}
//非最大抑制
void NonmaxSuppress(int *pMag, int *pGradX, int *pGradY, SIZE sz, LPBYTE pNSRst)
{
LONG y,x;
int nPos;
//梯度分量
int gx;
int gy;
//中间变量
int g1,g2,g3,g4;
double weight;
double dTmp,dTmp1,dTmp2;
//设置图像边缘为不可能的分界点
for(x=0;x
pNSRst[nPos] = 0;
}
else
{
//当前点的梯度幅度
dTmp = pMag[nPos];
//x,y 方向导数
gx = pGradX[nPos];
gy = pGradY[nPos];
//如果方向导数 y 分量比 x 分量大,说明导数方向趋向于 y 分量
if(abs(gy) > abs(gx))
{
//计算插值比例
weight = fabs(gx)/fabs(gy);
g2 = pMag[nPos-sz.cx];
g4 = pMag[nPos+sz.cx];
//如果 x,y 两个方向导数的符号相同
//C 为当前像素,与 g1-g4 的位置关系为:
//g1 g2
//
//
if(gx*gy>0)
{
C
g4 g3
g1 = pMag[nPos-sz.cx-1];
g3 = pMag[nPos+sz.cx+1];
}
//如果 x,y 两个方向的方向导数方向相反
//C 是当前像素,与 g1-g4 的关系为:
//
//
//
else
{
g2 g1
C
g3 g4
g1 = pMag[nPos-sz.cx+1];
g3 = pMag[nPos+sz.cx-1];
}
}
//如果方向导数 x 分量比 y 分量大,说明导数的方向趋向于 x 分量
else
{
//插值比例
weight = fabs(gy)/fabs(gx);
g2 = pMag[nPos+1];
g4 = pMag[nPos-1];
//如果 x,y 两个方向的方向导数符号相同
//当前像素 C 与 g1-g4 的关系为
//
//
//
if(gx * gy > 0)
{
g3
g4 C g2
g1
g1 = pMag[nPos+sz.cx+1];
g3 = pMag[nPos-sz.cx-1];
}
//如果 x,y 两个方向导数的方向相反
// C 与 g1-g4 的关系为
//
//
//
else
{
g1
g4 C g2
g3
g1 = pMag[nPos-sz.cx+1];
g3 = pMag[nPos+sz.cx-1];
}
}
//利用 g1-g4 对梯度进行插值
{
dTmp1 = weight*g1 + (1-weight)*g2;
dTmp2 = weight*g3 + (1-weight)*g4;
//当前像素的梯度是局部的最大值
//该点可能是边界点
if(dTmp>=dTmp1 && dTmp>=dTmp2)
{
pNSRst[nPos] = 128;
}
else
{
//不可能是边界点
pNSRst[nPos] = 0;
}
}
}
}
}
}
// 统计 pMag 的直方图,判定阈值
void EstimateThreshold(int *pMag, SIZE sz, int *pThrHigh, int *pThrLow, LPBYTE pGray,
double dRatHigh, double dRatLow)
{
LONG y,x,k;
//该数组的大小和梯度值的范围有关,如果采用本程序的算法
//那么梯度的范围不会超过 pow(2,10)
int nHist[256];
//可能边界数
int nEdgeNum;
//最大梯度数
int nMaxMag;
int nHighCount;
nMaxMag = 0;
//初始化
for(k=0;k<256;k++)
{
nHist[k] = 0;
}
//统计直方图,利用直方图计算阈值
for(y=0;y