请问谁有关于Canny算子边缘检测的代码及相关资料吗?(C#的)(最好的中文的) 本人现在在做一个对图像进行边缘提取程序,在网上找了好多有关这方面的资料,但我对图像处理这方面的知识是初学的!请高手朋友们能给一个意见、方法或Canny算子或其它算子方法和原理给小弟产参考参考!先谢谢了 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 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<sz.cy;y++) { for(x=0;x<sz.cx;x++) { dDotMul = 0; dWeightSum = 0; for(i=(-nLen);i<=nLen;i++) { //判断是否在图像内部 if((i+x)>=0 && (i+x)<sz.cx) { dDotMul+=(double)pGray[y*sz.cx+(i+x)] * pdKernel[nLen+i]; dWeightSum += pdKernel[nLen+i]; } } pdTemp[y*sz.cx+x] = dDotMul/dWeightSum; } } //y方向滤波 for(x=0; x<sz.cx;x++) { for(y=0; y<sz.cy; y++) { dDotMul = 0; dWeightSum = 0; for(i=(-nLen);i<=nLen;i++) { if((i+y)>=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<sz.cy-1;y++) { for(x=1;x<sz.cx-1;x++) { pGradX[y*sz.cx +x] = (int)( pGray[y*sz.cx+x+1]-pGray[y*sz.cx+ x-1] ); } } //y方向方向导数 for(x=1;x<sz.cx-1;x++) { for(y=1;y<sz.cy-1;y++) { pGradY[y*sz.cx +x] = (int)(pGray[(y+1)*sz.cx +x] - pGray[(y-1)*sz.cx +x]); } } //求梯度 //中间变量 double dSqt1; double dSqt2; for(y=0; y<sz.cy; y++) { for(x=0; x<sz.cx; x++) { //二阶范数求梯度 dSqt1 = pGradX[y*sz.cx + x]*pGradX[y*sz.cx + x]; 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<sz.cx;x++) { pNSRst[x] = 0; pNSRst[(sz.cy-1)*sz.cx+x] = 0; } for(y=0;y<sz.cy;y++) { pNSRst[y*sz.cx] = 0; pNSRst[y*sz.cx + sz.cx-1] = 0; } for(y=1;y<sz.cy-1;y++) { for(x=1;x<sz.cx-1;x++) { //当前点 nPos = y*sz.cx + x; //如果当前像素梯度幅度为0,则不是边界点 if(pMag[nPos] == 0) { 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 // C // g4 g3 if(gx*gy>0) { g1 = pMag[nPos-sz.cx-1]; g3 = pMag[nPos+sz.cx+1]; } //如果x,y两个方向的方向导数方向相反 //C是当前像素,与g1-g4的关系为: // g2 g1 // C // g3 g4 else { 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的关系为 // g3 // g4 C g2 // g1 if(gx * gy > 0) { g1 = pMag[nPos+sz.cx+1]; g3 = pMag[nPos-sz.cx-1]; } //如果x,y两个方向导数的方向相反 // C与g1-g4的关系为 // g1 // g4 C g2 // g3 else { 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<sz.cy;y++) { for(x=0;x<sz.cx;x++) { if(pGray[y*sz.cx+x]==128) { nHist[pMag[y*sz.cx+x]]++; } } } nEdgeNum = nHist[0]; nMaxMag = 0; //统计经过“非最大值抑制”后有多少像素 for(k=1;k<256;k++) { if(nHist[k] != 0) { nMaxMag = k; } //梯度为0的点是不可能为边界点的 //经过non-maximum suppression后有多少像素 nEdgeNum += nHist[k]; } //梯度比高阈值*pThrHigh 小的像素点总书目 nHighCount = (int)(dRatHigh * nEdgeNum + 0.5); k=1; nEdgeNum = nHist[1]; //计算高阈值 while((k<(nMaxMag-1)) && (nEdgeNum < nHighCount)) { k++; nEdgeNum += nHist[k]; } *pThrHigh = k; //低阈值 *pThrLow = (int)((*pThrHigh) * dRatLow + 0.5);}//利用函数寻找边界起点void Hysteresis(int *pMag, SIZE sz, double dRatLow, double dRatHigh, LPBYTE pResult){ LONG y,x; int nThrHigh,nThrLow; int nPos; //估计TraceEdge 函数需要的低阈值,以及Hysteresis函数使用的高阈值 EstimateThreshold(pMag, sz,&nThrHigh,&nThrLow,pResult,dRatHigh,dRatLow); //寻找大于dThrHigh的点,这些点用来当作边界点, //然后用TraceEdge函数跟踪该点对应的边界 for(y=0;y<sz.cy;y++) { for(x=0;x<sz.cx;x++) { nPos = y*sz.cx + x; //如果该像素是可能的边界点,并且梯度大于高阈值, //该像素作为一个边界的起点 if((pResult[nPos]==128) && (pMag[nPos] >= nThrHigh)) { //设置该点为边界点 pResult[nPos] = 255; TraceEdge(y,x,nThrLow,pResult,pMag,sz); } } } //其他点已经不可能为边界点 for(y=0;y<sz.cy;y++) { for(x=0;x<sz.cx;x++) { nPos = y*sz.cx + x; if(pResult[nPos] != 255) { pResult[nPos] = 0; } } }}//根据Hysteresis 执行的结果,从一个像素点开始搜索,搜索以该像素点为边界起点的一条边界的//一条边界的所有边界点,函数采用了递归算法// 从(x,y)坐标出发,进行边界点的跟踪,跟踪只考虑pResult中没有处理并且可能是边界// 点的像素(=128),像素值为0表明该点不可能是边界点,像素值为255表明该点已经是边界点void TraceEdge(int y, int x, int nThrLow, LPBYTE pResult, int *pMag, SIZE sz){ //对8邻域像素进行查询 int xNum[8] = {1,1,0,-1,-1,-1,0,1}; int yNum[8] = {0,1,1,1,0,-1,-1,-1}; LONG yy,xx,k; for(k=0;k<8;k++) { yy = y+yNum[k]; xx = x+xNum[k]; if(pResult[yy*sz.cx+xx]==128 && pMag[yy*sz.cx+xx]>=nThrLow ) { //该点设为边界点 pResult[yy*sz.cx+xx] = 255; //以该点为中心再进行跟踪 TraceEdge(yy,xx,nThrLow,pResult,pMag,sz); } }}// Canny算子void Canny(LPBYTE pGray, SIZE sz, double sigma, double dRatLow, double dRatHigh, LPBYTE pResult){ //经过高斯滤波后的图像 LPBYTE pGaussSmooth; pGaussSmooth = new unsigned char[sz.cx*sz.cy]; //x方向导数的指针 int *pGradX; pGradX = new int[sz.cx*sz.cy]; //y方向 int *pGradY; pGradY = new int[sz.cx*sz.cy]; //梯度的幅度 int *pGradMag; pGradMag = new int[sz.cx*sz.cy]; //对原图高斯滤波 GaussianSmooth(sz,pGray,pGaussSmooth,sigma); //计算方向导数和梯度的幅度 Grad(sz,pGaussSmooth,pGradX,pGradY,pGradMag); //应用非最大抑制 NonmaxSuppress(pGradMag,pGradX,pGradY,sz,pResult); //应用Hysteresis,找到所有边界 Hysteresis(pGradMag,sz,dRatLow,dRatHigh,pResult); delete[] pGradX; pGradX = NULL; delete[] pGradY; pGradY = NULL; delete[] pGradMag; pGradMag = NULL; delete[] pGaussSmooth; pGaussSmooth = NULL; }/*void CChildWnd::OnCanny() { if (! m_fOpenFile) { return; } m_fDone = TRUE; RGBToGray(szImg, aRGB, aGray, BPP); Canny(aGray,szImg,0.1,0.9,0.76,aBinImg); ShowGrayImage("l",szImg,aBinImg);}//*/ 参考:http://search.codesoso.com/Search?q=canny+%E7%AE%97%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B+%E4%B8%AD%E6%96%87%E8%B5%84%E6%96%99&btnc=%E6%90%9C%E7%B4%A2http://www.codesoso.com/code/Canny_Edge_Extract.aspxhttp://firsttiger.bokee.com/6701029.htmlhttp://zh.wikipedia.org/wiki/%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8Bhttp://download.csdn.net/source/182505 菜鸟的问题 在函数中使某一控件的事件触发,该怎么做? 关于IE异步可插入协议 低级问题,dataview按钮列对应行的取值问题。 请各位推存几个好的c#论坛或网站。 创建C#程序出现“无效的过程调用或参数”错误 请问一个关于将B窗体数据回传到A窗体的问题---在线急等!! 求压缩算法 如何判断UltraGrid中列的数据是否重复?急!!! 关于J#.net的问题(不是C#) AutoCAD图在Winform中的显示和数据库保存问题 请问如何让datagridview显示最后一条数据?
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<sz.cy;y++)
{
for(x=0;x<sz.cx;x++)
{
dDotMul = 0;
dWeightSum = 0;
for(i=(-nLen);i<=nLen;i++)
{
//判断是否在图像内部
if((i+x)>=0 && (i+x)<sz.cx)
{
dDotMul+=(double)pGray[y*sz.cx+(i+x)] * pdKernel[nLen+i];
dWeightSum += pdKernel[nLen+i];
}
}
pdTemp[y*sz.cx+x] = dDotMul/dWeightSum;
}
} //y方向滤波
for(x=0; x<sz.cx;x++)
{
for(y=0; y<sz.cy; y++)
{
dDotMul = 0;
dWeightSum = 0;
for(i=(-nLen);i<=nLen;i++)
{
if((i+y)>=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<sz.cy-1;y++)
{
for(x=1;x<sz.cx-1;x++)
{
pGradX[y*sz.cx +x] = (int)( pGray[y*sz.cx+x+1]-pGray[y*sz.cx+ x-1] );
}
} //y方向方向导数
for(x=1;x<sz.cx-1;x++)
{
for(y=1;y<sz.cy-1;y++)
{
pGradY[y*sz.cx +x] = (int)(pGray[(y+1)*sz.cx +x] - pGray[(y-1)*sz.cx +x]);
}
} //求梯度 //中间变量
double dSqt1;
double dSqt2; for(y=0; y<sz.cy; y++)
{
for(x=0; x<sz.cx; x++)
{
//二阶范数求梯度
dSqt1 = pGradX[y*sz.cx + x]*pGradX[y*sz.cx + x];
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<sz.cx;x++)
{
pNSRst[x] = 0;
pNSRst[(sz.cy-1)*sz.cx+x] = 0; }
for(y=0;y<sz.cy;y++)
{
pNSRst[y*sz.cx] = 0;
pNSRst[y*sz.cx + sz.cx-1] = 0;
} for(y=1;y<sz.cy-1;y++)
{
for(x=1;x<sz.cx-1;x++)
{
//当前点
nPos = y*sz.cx + x; //如果当前像素梯度幅度为0,则不是边界点
if(pMag[nPos] == 0)
{
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
// C
// g4 g3
if(gx*gy>0)
{
g1 = pMag[nPos-sz.cx-1];
g3 = pMag[nPos+sz.cx+1];
} //如果x,y两个方向的方向导数方向相反
//C是当前像素,与g1-g4的关系为:
// g2 g1
// C
// g3 g4
else
{
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的关系为
// g3
// g4 C g2
// g1
if(gx * gy > 0)
{
g1 = pMag[nPos+sz.cx+1];
g3 = pMag[nPos-sz.cx-1];
}
//如果x,y两个方向导数的方向相反
// C与g1-g4的关系为
// g1
// g4 C g2
// g3
else
{
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<sz.cy;y++)
{
for(x=0;x<sz.cx;x++)
{
if(pGray[y*sz.cx+x]==128)
{
nHist[pMag[y*sz.cx+x]]++;
}
}
} nEdgeNum = nHist[0];
nMaxMag = 0; //统计经过“非最大值抑制”后有多少像素
for(k=1;k<256;k++)
{
if(nHist[k] != 0)
{
nMaxMag = k;
} //梯度为0的点是不可能为边界点的
//经过non-maximum suppression后有多少像素
nEdgeNum += nHist[k]; } //梯度比高阈值*pThrHigh 小的像素点总书目
nHighCount = (int)(dRatHigh * nEdgeNum + 0.5); k=1;
nEdgeNum = nHist[1]; //计算高阈值
while((k<(nMaxMag-1)) && (nEdgeNum < nHighCount))
{
k++;
nEdgeNum += nHist[k];
} *pThrHigh = k; //低阈值
*pThrLow = (int)((*pThrHigh) * dRatLow + 0.5);}//利用函数寻找边界起点
void Hysteresis(int *pMag, SIZE sz, double dRatLow, double dRatHigh, LPBYTE pResult)
{
LONG y,x; int nThrHigh,nThrLow; int nPos;
//估计TraceEdge 函数需要的低阈值,以及Hysteresis函数使用的高阈值
EstimateThreshold(pMag, sz,&nThrHigh,&nThrLow,pResult,dRatHigh,dRatLow); //寻找大于dThrHigh的点,这些点用来当作边界点,
//然后用TraceEdge函数跟踪该点对应的边界
for(y=0;y<sz.cy;y++)
{
for(x=0;x<sz.cx;x++)
{
nPos = y*sz.cx + x; //如果该像素是可能的边界点,并且梯度大于高阈值,
//该像素作为一个边界的起点
if((pResult[nPos]==128) && (pMag[nPos] >= nThrHigh))
{
//设置该点为边界点
pResult[nPos] = 255;
TraceEdge(y,x,nThrLow,pResult,pMag,sz);
} }
} //其他点已经不可能为边界点
for(y=0;y<sz.cy;y++)
{
for(x=0;x<sz.cx;x++)
{
nPos = y*sz.cx + x; if(pResult[nPos] != 255)
{
pResult[nPos] = 0;
}
}
}
}//根据Hysteresis 执行的结果,从一个像素点开始搜索,搜索以该像素点为边界起点的一条边界的
//一条边界的所有边界点,函数采用了递归算法
// 从(x,y)坐标出发,进行边界点的跟踪,跟踪只考虑pResult中没有处理并且可能是边界
// 点的像素(=128),像素值为0表明该点不可能是边界点,像素值为255表明该点已经是边界点void TraceEdge(int y, int x, int nThrLow, LPBYTE pResult, int *pMag, SIZE sz)
{
//对8邻域像素进行查询
int xNum[8] = {1,1,0,-1,-1,-1,0,1};
int yNum[8] = {0,1,1,1,0,-1,-1,-1}; LONG yy,xx,k; for(k=0;k<8;k++)
{
yy = y+yNum[k];
xx = x+xNum[k]; if(pResult[yy*sz.cx+xx]==128 && pMag[yy*sz.cx+xx]>=nThrLow )
{
//该点设为边界点
pResult[yy*sz.cx+xx] = 255; //以该点为中心再进行跟踪
TraceEdge(yy,xx,nThrLow,pResult,pMag,sz);
}
}
}
// Canny算子
void Canny(LPBYTE pGray, SIZE sz, double sigma, double dRatLow,
double dRatHigh, LPBYTE pResult)
{
//经过高斯滤波后的图像
LPBYTE pGaussSmooth; pGaussSmooth = new unsigned char[sz.cx*sz.cy]; //x方向导数的指针
int *pGradX;
pGradX = new int[sz.cx*sz.cy];
//y方向
int *pGradY;
pGradY = new int[sz.cx*sz.cy];
//梯度的幅度
int *pGradMag;
pGradMag = new int[sz.cx*sz.cy]; //对原图高斯滤波
GaussianSmooth(sz,pGray,pGaussSmooth,sigma); //计算方向导数和梯度的幅度
Grad(sz,pGaussSmooth,pGradX,pGradY,pGradMag); //应用非最大抑制
NonmaxSuppress(pGradMag,pGradX,pGradY,sz,pResult); //应用Hysteresis,找到所有边界
Hysteresis(pGradMag,sz,dRatLow,dRatHigh,pResult); delete[] pGradX;
pGradX = NULL;
delete[] pGradY;
pGradY = NULL;
delete[] pGradMag;
pGradMag = NULL;
delete[] pGaussSmooth;
pGaussSmooth = NULL;
}/*
void CChildWnd::OnCanny()
{
if (! m_fOpenFile)
{
return;
}
m_fDone = TRUE;
RGBToGray(szImg, aRGB, aGray, BPP);
Canny(aGray,szImg,0.1,0.9,0.76,aBinImg);
ShowGrayImage("l",szImg,aBinImg);
}
//*/
http://search.codesoso.com/Search?q=canny+%E7%AE%97%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B+%E4%B8%AD%E6%96%87%E8%B5%84%E6%96%99&btnc=%E6%90%9C%E7%B4%A2
http://www.codesoso.com/code/Canny_Edge_Extract.aspx
http://firsttiger.bokee.com/6701029.html
http://zh.wikipedia.org/wiki/%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B
http://download.csdn.net/source/182505