自适应阈值的canny边缘检测算法-c语言实现
canny算子请查看:请点击这里
为了解决canny算子中阈值的取值问题,引入了自适应阈值。技术文章来自:
自适应Canny算子边缘检测技术_李牧
大家可以google一下,很好找到。
在文章中使用了“基于梯度幅度直方图和类内方差最小化动态的自动确定高低阈值”方法;
主要方法如下:
1.将经过非模极大值抑制后的梯度幅值分为L级, 模极大值分成3类: C0、C1、C2,
C0 类为非边缘点的像素,
C2 类为边缘点的像素,
C1 类包含的像素可能是边缘点, 也可能不是边缘点.
设定ni 为模数为i 的像素的总数, Pi 为该模级像素数占整个图像像素的比率:
令C0 包含模级[ 0, 1, ,, k] 的像素, C1 包含模级[ k+1, k+ 2, ,, m] 的像素, C2 包含模级[ m+ 1,m+2, ,, l-1] 的像素:
这里的k m 就是我们需要找到的低 高阈值。
经过过程推导(请忽视这些细节)后,得到我们需要的公式:
附上改写的c语言实现:
void autoGetValue(SIZE sz, int *pThrHigh, int *pThrLow, int *pMag) { //自适应的阈值计算 double P[256]; //灰度概率值 for (int i = 0;i < 256;i++) { P[i] = 0; } //LPBYTE pGray 数据 for(LONG y=0;y<sz.cy;y++) { for(LONG x=0;x<sz.cx;x++) { P[pMag[y*sz.cx+x]]++;//对应的灰度值加1 //printf ("%d\n",pGray[y*sz.cx+x]); } } for (int i = 0;i < 256;i++) { //printf ("h:%d,v:%d\n",i,P[i]); P[i]/=(sz.cx * sz.cy * 1.0); //printf ("h:%d,v:%f\n",i,P[i]); } //前n项的概率和 double P_M[256]; P_M[0] = P[0]; for (int i = 1;i < 256;i++) { P_M[i] = P_M[i - 1] + P[i]; //printf ("前n灰度概率:%d,v:%f\n",i,P_M[i]); } //前N项的期望和 double P_M_I[256]; P_M_I[0] = 0; for (int i = 1;i < 256;i++) { P_M_I[i] = i * P[i] +P_M_I[i - 1]; //printf ("前n灰度期望:%d,v:%f\n",i,P_M_I[i]); } int k = 0; int m = 0; int go_on; for (k = 0;k < 256;k++) { go_on = 1; for (m = 0;m < 256;m++) { if (fabs(2.0 * k - (P_M_I[k] / (P_M[k] * 1.0)) - ( (P_M_I[m] - P_M_I[k])/ (P_M[m] - P_M[k]))) <= 1 && fabs(2.0 * m - ( (P_M_I[m] - P_M_I[k])/ (P_M[m] - P_M[k])) - ( (P_M_I[255] - P_M_I[m])/ (P_M[255] - P_M[m]))) <= 1 ){ //printf ("have?"); go_on = 0; break; } //找到最佳阈值 } if (!go_on) break; } *pThrHigh =m; *pThrLow = k; }
学习ing。