canny算子c语言

跪求canny边缘检测算子的c源代码

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;ysz.cy;y++)

{

for(x=0;xsz.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; xsz.cx;x++)

{

for(y=0; ysz.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;ysz.cy-1;y++)

{

for(x=1;xsz.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;xsz.cx-1;x++)

{

for(y=1;ysz.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; ysz.cy; y++)

{

for(x=0; xsz.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;xsz.cx;x++)

{

pNSRst[x] = 0;

pNSRst[(sz.cy-1)*sz.cx+x] = 0;

}

for(y=0;ysz.cy;y++)

{

pNSRst[y*sz.cx] = 0;

pNSRst[y*sz.cx + sz.cx-1] = 0;

}

for(y=1;ysz.cy-1;y++)

{

for(x=1;xsz.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*gy0)

{

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;k256;k++)

{

nHist[k] = 0;

}

//统计直方图,利用直方图计算阈值

for(y=0;ysz.cy;y++)

{

for(x=0;xsz.cx;x++)

{

if(pGray[y*sz.cx+x]==128)

{

nHist[pMag[y*sz.cx+x]]++;

}

}

}

nEdgeNum = nHist[0];

nMaxMag = 0;

//统计经过“非最大值抑制”后有多少像素

for(k=1;k256;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;ysz.cy;y++)

{

for(x=0;xsz.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;ysz.cy;y++)

{

for(x=0;xsz.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;k8;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);

}

//*/

canny算子c语言

需要一段用Canny算子实现图像边缘检测的MATLAB程序,拜托高手们帮帮忙,很急啊!

Matlab上有CANNY算子的库函数啊,直接调用就行了。

我这有VC++的边缘检测算法,很长的。稍微改一下就可以用在Matlab上。

/ 一维高斯分布函数,用于平滑函数中生成的高斯滤波系数

void CFunction::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 CFunction::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;ysz.cy;y++)

{

for(x=0;xsz.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; xsz.cx;x++)

{

for(y=0; ysz.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)(int)dDotMul/dWeightSum;

}

}

delete []pdKernel;

pdKernel = NULL;

delete []pdTemp;

pdTemp = NULL;

}

// 方向导数,求梯度

void CFunction::Grad(SIZE sz, LPBYTE pGray,int *pGradX, int *pGradY, int *pMag)

{

LONG y,x;

//x方向的方向导数

for(y=1;ysz.cy-1;y++)

{

for(x=1;xsz.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;xsz.cx-1;x++)

{

for(y=1;ysz.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; ysz.cy; y++)

{

for(x=0; xsz.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 CFunction::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;xsz.cx;x++)

{

pNSRst[x] = 0;

//pNSRst[(sz.cy-1)*sz.cx+x] = 0;

pNSRst[sz.cy-1+x] = 0;

}

for(y=0;ysz.cy;y++)

{

pNSRst[y*sz.cx] = 0;

pNSRst[y*sz.cx + sz.cx-1] = 0;

}

for(y=1;ysz.cy-1;y++)

{

for(x=1;xsz.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*gy0)

{

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 CFunction::EstimateThreshold(int *pMag, SIZE sz, int *pThrHigh, int *pThrLow, LPBYTE pGray,

double dRatHigh, double dRatLow)

{

LONG y,x,k;

//该数组的大小和梯度值的范围有关,如果采用本程序的算法

//那么梯度的范围不会超过pow(2,10)

int nHist[1024];

//可能边界数

int nEdgeNum;

//最大梯度数

int nMaxMag;

int nHighCount;

nMaxMag = 0;

//初始化

for(k=0;k1024;k++)

{

nHist[k] = 0;

}

//统计直方图,利用直方图计算阈值

for(y=0;ysz.cy;y++)

{

for(x=0;xsz.cx;x++)

{

if(pGray[y*sz.cx+x]==128)

{

nHist[pMag[y*sz.cx+x]]++;

}

}

}

nEdgeNum = nHist[0];

nMaxMag = 0;

//统计经过“非最大值抑制”后有多少像素

for(k=1;k1024;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 CFunction::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;ysz.cy;y++)

{

for(x=0;xsz.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;ysz.cy;y++)

{

for(x=0;xsz.cx;x++)

{

nPos = y*sz.cx + x;

if(pResult[nPos] != 255)

{

pResult[nPos] = 0;

}

}

}

}

//根据Hysteresis 执行的结果,从一个像素点开始搜索,搜索以该像素点为边界起点的一条边界的

//一条边界的所有边界点,函数采用了递归算法

// 从(x,y)坐标出发,进行边界点的跟踪,跟踪只考虑pResult中没有处理并且可能是边界

// 点的像素(=128),像素值为0表明该点不可能是边界点,像素值为255表明该点已经是边界点

void CFunction::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;k8;k++)

{

yy = y+yNum[k];

xx = x+xNum[k];

if(pResult[640 * (479 – yy)+xx]==128 pMag[640 * (479 – yy)+xx]=nThrLow )

{

//该点设为边界点

pResult[640 * (479 – yy)+xx] = 255;

//以该点为中心再进行跟踪

TraceEdge(yy,xx,nThrLow,pResult,pMag,sz);

}

}

}

// Canny算子

BOOL CFunction::Canny(LPBYTE m_pDibData,CPoint ptLeft, CPoint ptRight , double sigma, double dRatLow, double dRatHigh)

{

BYTE* m_Newdata;//每一步处理后的图像数据

m_Newdata = (BYTE*)malloc(maxImage);

memcpy(m_Newdata,(BYTE *)m_pDibData,maxImage);

//经过抑制局部像素非最大值的处理后的数据

BYTE* pResult;//每一步处理后的图像数据

pResult = (BYTE*)malloc(maxImage);

memcpy(pResult,(BYTE *)m_pDibData,maxImage);

int pointy,pointx,m,n,i=0;

long Position;

int GradHori;

int GradVert;

//存储结构元素的数组

BYTE array[9]={0};

//设定两个阈值

int nThrHigh,nThrLow;

//梯度分量

int gx;

int gy;

//中间变量

int g1,g2,g3,g4;

double weight;

double dTmp,dTmp1,dTmp2;

int Width,Higth;

Width=ptRight.x-ptLeft.x+1;

Higth=ptRight.y-ptLeft.y+1;

CSize sz=CSize(Width,Higth);

//x方向导数的指针

int *pGradX= new int[maxImage];

memset(pGradX,0,maxImage);

//y方向

int *pGradY;

pGradY = new int [maxImage];

memset(pGradY,0,maxImage);

//梯度的幅度

int *pGradMag;

pGradMag = new int [maxImage];

//对pGradMag进行初始化

for (pointy = 0;pointy 480;pointy++)

{

for (pointx = 0;pointx 640 ;pointx++)

{

Position=640 * (479 – pointy)+pointx;

pGradMag[Position]=m_pDibData[Position];

}

}

//第一步进行高斯平滑器滤波

//进入循环,使用3*3的结构元素,处理除去第一行和最后一行以及第一列和最后一列。

for (pointy = ptLeft.y+1;pointy = ptRight.y-1;pointy++)

{

for (pointx = ptLeft.x+1;pointx = ptRight.x-1;pointx++)

{

Position=640 * (479 – pointy)+pointx;

for (m = 0;m 3;m++)

{

for (n = 0;n 3;n++)

{

array[m*3+n]=m_pDibData[Position+640*(1-m)+n-1];

}

}

GradHori=abs(array[0]+2*array[1]+array[2]+2*array[3]+4*array[4]+2*array[5]+array[6]+2*array[7]+array[8]);

GradHori=(int)(0.0625*GradHori+0.5);

if (GradHori255)

{

m_Newdata[Position]=255;

}

else

m_Newdata[Position]=GradHori;

}

}

//第二步用一阶偏导的有限差分来计算梯度的幅值和方向

//x方向的方向导数

for (pointy = ptLeft.y+1;pointy = ptRight.y-1;pointy++)

{

for (pointx = ptLeft.x+1;pointx = ptRight.x-1;pointx++)

{

pGradX[pointy*Width +pointx]=(int)(m_Newdata[pointy*Width +pointx+1]- m_Newdata[pointy*Width +pointx-1] );

}

}

//y方向方向导数

for (pointx = ptLeft.x+1;pointx = ptRight.x-1;pointx++)

{

for (pointy = ptLeft.y+1;pointy = ptRight.y-1;pointy++)

{

pGradY[pointy*Width +pointx] = (int)(m_Newdata[(pointy+1)*Width +pointx] – m_Newdata[(pointy-1)*Width +pointx]);

}

}

//求梯度

for (pointy = ptLeft.y+1;pointy = ptRight.y-1;pointy++)

{

for (pointx = ptLeft.x+1;pointx = ptRight.x-1;pointx++)

{

Position=640 * (479 – pointy)+pointx;

for (m = 0;m 3;m++)

{

for (n = 0;n 3;n++)

{

array[m*3+n]=m_Newdata[Position+640*(1-m)+n-1];

}

}

GradHori=abs((-1)*array[0]+(-2)*array[3]+2*array[7]+array[8]);

GradVert=abs((-1)*array[0]-2*array[1]+2*array[5]+array[8]);

GradHori =(int)((float)sqrt(pow(GradHori,2)+pow(GradVert,2))+0.5);

pGradMag[Position]=GradHori;

}

}

//针对第一行的像素点及最后一行的像素点

for (pointx = ptLeft.x;pointx = ptRight.x;pointx++)

{

Position=640 * (479 – ptLeft.y)+pointx;

pGradMag[Position]=0;

Position=640 * (479 – ptRight.y)+pointx;

pGradMag[Position]=0;

}

//针对第一列以及最后一列的像素点

for (pointy = ptLeft.y+1;pointy = ptRight.y-1;pointy++)

{

Position=640 * (479 – pointy)+ptLeft.x;

pGradMag[Position]=0;

Position=640 * (479 – pointy)+ptRight.x;

pGradMag[Position]=0;

}

//第三步进行抑制梯度图中的非局部极值点的像素

for (pointy = ptLeft.y+1;pointy = ptRight.y-1;pointy++)

{

for (pointx = ptLeft.x+1;pointx = ptRight.x-1;pointx++)

{ //当前点

Position=640 * (479 – pointy)+pointx;

//如果当前像素梯度幅度为0,则不是边界点

if(pGradMag[Position] == 0)

{

pGradMag[Position] = 0;

}

else

{ //当前点的梯度幅度

dTmp = pGradMag[Position];

//x,y方向导数

gx = pGradX[Position];

gy = pGradY[Position];

//如果方向导数y分量比x分量大,说明导数方向趋向于y分量

if(abs(gy) abs(gx))

{

//计算插值比例

weight = fabs(gx)/fabs(gy);

g2 = pGradMag[Position-640];

g4 = pGradMag[Position+640];

//如果x,y两个方向导数的符号相同

//C 为当前像素,与g1-g4 的位置关系为:

//g1 g2

// C

// g4 g3

if(gx*gy0)

{

g1 = pGradMag[Position-640-1];

g3 = pGradMag[Position+640+1];

}

//如果x,y两个方向的方向导数方向相反

//C是当前像素,与g1-g4的关系为:

// g2 g1

// C

// g3 g4

else

{

g1 = pGradMag[Position-640+1];

g3 = pGradMag[Position+640-1];

}

}

//如果方向导数x分量比y分量大,说明导数的方向趋向于x分量

else

{

//插值比例

weight = fabs(gy)/fabs(gx);

g2 = pGradMag[Position+1];

g4 = pGradMag[Position-1];

//如果x,y两个方向的方向导数符号相同

//当前像素C与 g1-g4的关系为

// g3

// g4 C g2

// g1

if(gx * gy 0)

{

g1 = pGradMag[Position+640+1];

g3 = pGradMag[Position-640-1];

}

//如果x,y两个方向导数的方向相反

// C与g1-g4的关系为

// g1

// g4 C g2

// g3

else

{

g1 =pGradMag[Position-640+1];

g3 =pGradMag[Position+640-1];

}

}

//利用 g1-g4 对梯度进行插值

{

dTmp1 = weight*g1 + (1-weight)*g2;

dTmp2 = weight*g3 + (1-weight)*g4;

//当前像素的梯度是局部的最大值

//该点可能是边界点

if(dTmp=dTmp1 dTmp=dTmp2)

{

pResult[Position] = 128;

}

else

{

//不可能是边界点

pResult[Position] = 0;

}

}

}

}

}

//第四步根据梯度计算及经过非最大值得印制后的结果设定阈值

//估计TraceEdge 函数需要的低阈值,函数使用的高阈值

EstimateThreshold(pGradMag, sz,nThrHigh,nThrLow,pResult,dRatHigh,dRatLow);

//寻找大于dThrHigh的点,这些点用来当作边界点,

//然后用TraceEdge函数跟踪该点对应的边界

for (pointy = ptLeft.y+1;pointy = ptRight.y-1;pointy++)

{

for (pointx = ptLeft.x+1;pointx = ptRight.x-1;pointx++)

{

Position=640 * (479 – pointy)+pointx;

//如果该像素是可能的边界点,并且梯度大于高阈值,

//该像素作为一个边界的起点

if((pResult[Position]==128) (pGradMag[Position] = nThrHigh))

{

//设置该点为边界点

pResult[Position] = 255;

TraceEdge(pointy,pointx,nThrLow,pResult,pGradMag,sz);

}

}

}

//其他点已经不可能为边界点

for (pointy = ptLeft.y+1;pointy = ptRight.y-1;pointy++)

{

for (pointx = ptLeft.x+1;pointx = ptRight.x-1;pointx++)

{

Position=640 * (479 – pointy)+pointx;

if(pResult[Position] != 255)

{

pResult[Position] = 0;

}

}

}

//计算方向导数和梯度的幅度

// Grad(sz,pGaussSmooth,pGradX,pGradY,pGradMag);

//应用非最大抑制

// NonmaxSuppress(pGradMag,pGradX,pGradY,sz,pResult);

//应用Hysteresis,找到所有边界

// Hysteresis(pGradMag,sz,dRatLow,dRatHigh,pResult);

memcpy(m_pDibData,(BYTE *)pResult,maxImage);

delete[] pResult;

pResult = NULL;

delete[] pGradX;

pGradX = NULL;

delete[] pGradY;

pGradY = NULL;

delete[] pGradMag;

pGradMag = NULL;

delete[] m_Newdata;

m_Newdata = NULL;

return true;

}

sobel边缘检测优缺点与canny算子的优缺点?

一、sobel边缘检测:

1、sobel边缘检测优点:输出图像(数组)的元素通常具有更大的绝对数值。

2、sobel边缘检测缺点:由于边缘是位置的标志,对灰度的变化不敏感。

二、canny算子:

1、canny算子优点:法能够尽可能多地标识出图像中的实际边缘;标识出的边缘要与实际图像中的实际边缘尽可能接近。

2、canny算子缺点:图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘。

扩展资料:

Sobel边缘检测的核心在于像素矩阵的卷积,卷积对于数字图像处理非常重要,很多图像处理算法都是做卷积来实现的。

卷积运算的本质就是对制定的图像区域的像素值进行加权求和的过程,其计算过程为图像区域中的每个像素值分别与卷积模板的每个元素对应相乘,将卷积的结果作求和运算,运算到的和就是卷积运算的结果。

参考资料来源:

百度百科-sobel

百度百科-Canny算子

本文来自投稿,不代表【】观点,发布者:【

本文地址: ,如若转载,请注明出处!

举报投诉邮箱:253000106@qq.com

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2024年3月27日 13:21:05
下一篇 2024年3月27日 13:29:22

相关推荐

  • c语言改写模式,c语言实现修改功能

    c语言程序修改? 1、这个程序有4个错误,我都加粗了,第一个是m没有赋初值,第二个是while表达式中的ch=getchar()需要括号括起来,第三个是m=m*10+ch-0中的0也需要用单引号括起来,第四个是第2个while中为m!=0。 2、define容易造成误会,因为不符合一般的编程习惯,false 0, true 1;scanf放在你的那个地方是达…

    2024年5月23日
    4100
  • c语言控制代码的换码序列,c语言交换代码

    求C语言编程大神解答一下下面这个编程代码? k==5,用5去除125余0,所以r=125%5中r为0。由于!0为1,所以执行while循环体:先打印出5(k的值),再n=n/k==125/5=25;由于251则再打印出*号。这一循环结果输出是5*。 下面是我的代码,三个函数分别对应三个问题。 在实现基本要求的前提下,拓展了可以从键盘输入的功能,以下为各题代码…

    2024年5月23日
    5800
  • c语言扫描io脚状态,c语言端口扫描

    求51单片机的上升沿和下降沿C语言检测程序列子,端口就是普通IO口。 上升沿触发是当信号有上升沿时的开关动作,当电位由低变高而触发输出变化的就叫上升沿触发。也就是当测到的信号电位是从低到高也就是上升时就触发,叫做上升沿触发。 单片机怎么计算1s内下降沿的个数的C语言程序或者计算两个下降沿的时间(检测脉冲频率)计算1s内下降沿的个数方法是,一个定时器设置定时1…

    2024年5月23日
    4500
  • c语言mallloc使用的简单介绍

    C语言中使用malloc必须加#includemallo.h? 1、在C语言中使用malloc函数进行动态内存分配。malloc的全称是memory allocation,中文叫动态内存分配。原型:extern void malloc(unsigned int num_bytes);功能:分配长度为num_bytes字节的内存块。 2、你可以看一下C语言那本…

    2024年5月23日
    4500
  • c语言三位小数,C语言三位小数

    怎样用C++语言输出精确到小数点后三位的数? 1、用C++语言输出精确到小数点后三位的数,可以参考下面给出的代码:coutsetiosflags(ios:fixed)setprecision(3)。其中 setiosflags中set是设置的意思。ios是iostream的缩写,即输入输出流。flags是标志的意思。 2、要精确到小数点后若干位,则数据类型为…

    2024年5月23日
    7500
  • c语言21点游戏,二十一点游戏代码c语言

    如何使用C语言编写简单小游戏? 1、数学知识:长方形的面积S=a*b 长方形周长L=2*(a+b)其中a b分别为长方形的宽和高。算法分析:长方形面积及周长均依赖于宽和高,所以先要输入宽高值,然后根据公式计算,输出结果即可。 2、/*也不知道你是什么级别的,我是一个新手,刚接触编程语言,以下是我自己变得一个小程序,在所有c语言的编译器(vc++0、turbo…

    2024年5月23日
    6500
  • c语言当中的null,C语言当中的符号

    C/C++中,NULL和null的区别是什么? nul 和 null要看编译器,不同的编译器有所区别。 所以C或者C++中都使用一个特殊定义NULL表示无效值,其本质就是未定义具体数据类型的0值。 null是是什么都没有的意思。在java中表示空对象。 本意是“空的;元素只有零的”意思。计算机中通常表示空值,无结果,或是空集合。\x0d\x0a在ASCII码…

    2024年5月23日
    4700
  • 包含c语言对txt文件命名的词条

    如何在C语言编程里面修改源文件名字 如果你是在WINDOWS的话,简单了,随便用个编辑器,比如记事本,然后写c源程序,保存到你想要保存的位置。如果你在DOS下,可以用edit,写好以后,按alt键,选择文件菜单,然后保存。 用open打开文件,注意操作模式使用“修改”或者“添加” 用write或者fprintf向文件中写入你的内容。 用close关闭文件。 …

    2024年5月23日
    5000
  • 学c语言编程,学c语言编程用什么软件

    编程开发必须要学C语言吗? 1、要学习。编程开发的学习内容主要包括c语言、python和c+语言。C语言作为一种简单灵活的高级编程语言,它是一个面向过程的语言,一般是作为计算机专业的基础入门语言课程。 2、C语言。对于刚接触编程的人来说,先学习C语言是非常重要的。C语言可以说是是计算机编程语言的鼻祖,其他的编程语言几乎全是由C语言变化衍生出来的。 3、不需要…

    2024年5月23日
    3500
  • c语言用string定义字符串,c语言中用string类型来处理字符串类型

    C++怎样定义定义字符串 1、第一是字符数组来表示字符串。用下面的语句声明:char a[10];C语言中字符数组与字符串的唯一区别是字符串末尾有一个结束符\0,而字符数组不需要。 2、在C中定义字符串有下列几种形式:字符串常量,char数组,char指针 字符串常量 即:位于一对双括号中的任何字符。双引号里的字符加上编译器自动提供的结束标志\0字符,作为 …

    2024年5月23日
    4500

发表回复

登录后才能评论



关注微信