日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

Canny边缘检测原理及C#程序实现

發(fā)布時間:2025/7/14 C# 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Canny边缘检测原理及C#程序实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文:Canny邊緣檢測原理及C#程序實現

??? Canny邊緣檢測是被公認的檢測效果最好的邊緣檢測方法,是由John F. Canny于1986年提出,算法目標是找出一個最優(yōu)的邊緣檢測的方法,所謂最優(yōu)即:1.好的檢測:算法能夠盡可能的標識出圖像的邊緣;2.好的定位:標識出的邊緣要盡可能的與實際邊緣相接近;3.最小響應:圖像中的邊緣只能標識一次,并且不能把噪聲標識成邊緣。同時我們也要滿足3個準則:信噪比準則、定位精度準則、單邊緣響應準則。

??? Canny邊緣檢測算法可分為4步:

??? 高斯濾波器平滑、計算梯度、非極大值抑制、雙閾值邊緣檢測和邊緣連接。

??? (經典不會隨著時間褪色,算法也是一樣)

??? 下面將逐步講解并給出程序:

??? 第一步:高斯平滑

????為什么要對圖像(灰度圖像)進行高斯平滑預處理呢?高斯濾波器對去除服從正態(tài)分布的的噪聲很有效,我做過實驗,隨著高斯模板的增大,被識別的邊緣會逐漸減少,所以通過選著適合大小的高斯模板平滑,可以比較有效的去除一些偽邊緣點。

??? 第二步:計算梯度

??? 首先,由一階導數算子(一般用sobel模板)計算灰度圖像每個像素點在水平和豎直方向上的導數Gx、Gy,得出梯度向量(Gx,Gy),計算梯度的值G和方向theta:

??????? G=sqrt(Gx*Gx+Gy*Gy)? theta=arctan(Gy/Gx)

然后,將每個像素點的梯度的值和方向分別放入兩個數組中,程序如下:

byte[] orients = new byte[width * height];// 梯度方向數組 float[,] gradients = new float[width, height];// 梯度值數組 double gx, gy; for (int i = 1; i < (height - 1);i++ ){for (int j = 1; j < (width - 1); j++){//求水平和豎直導數gx = bufdata[(i - 1) * width + j] + bufdata[(i + 1) * width + j] - bufdata[(i -1) * width + j - 1] - bufdata[(i + 1) * width + j - 1]+ 2*(bufdata[i * width + j + 1] - bufdata[i * width + j - 1]);gy = bufdata[(i - 1) * width + j - 1] + bufdata[(i + 1) * width + j + 1] - bufdata[(i + 1) * width + j - 1] - bufdata[(i + 1) * width + j + 1]+ 2*(bufdata[(i - 1) * width + j] - bufdata[(i + 1) * width + j - 1]);gradients[j, i] = (float)Math.Sqrt(gx * gx + gy * gy);if (gx == 0){orientation = (gy == 0) ? 0 : 90;}else{double div = (double)gy / gx;if (div < 0){orientation = 180 - Math.Atan(-div) * toAngle;}else{orientation = Math.Atan(div) * toAngle;}//只保留成4個方向if (orientation < 22.5)orientation = 0;else if (orientation < 67.5)orientation = 45;else if (orientation < 112.5)orientation = 90;else if (orientation < 157.5)orientation = 135;else orientation = 0;}orients[i*width+j] = (byte)orientation;}}

?

???? 第三步:非極大值抑制

???? 如果直接把梯度作為邊緣的話,將得到一個粗邊緣的圖像,這不滿足上面提到的準則,我們希望得到定位準確的單像素的邊緣,所以將每個像素點的梯度與其梯度方向上的相鄰像素比較,如果不是極大值,將其置0,否則置為某一不大于255的數,程序如下:

float leftPixel = 0, rightPixel = 0;for (int y = 1; y <height-1; y++){for (int x = 1; x < width-1; x++){//獲得相鄰兩像素梯度值switch (orients[y * width + x]){case 0:leftPixel = gradients[x - 1, y];rightPixel = gradients[x + 1, y];break;case 45:leftPixel = gradients[x - 1, y + 1];rightPixel = gradients[x + 1, y - 1];break;case 90:leftPixel = gradients[x, y + 1];rightPixel = gradients[x, y - 1];break;case 135:leftPixel = gradients[x + 1, y + 1];rightPixel = gradients[x - 1, y - 1];break;}if ((gradients[x, y] < leftPixel) || (gradients[x, y] < rightPixel)){dis[y * disdata.Stride + x] = 0;}else{dis[y * disdata.Stride + x] = (byte)(gradients[x, y] /maxGradient* 255);//maxGradient是最大梯度}} }

?

?????? 第四步:雙閾值邊緣檢測

????由上一步得到的邊緣還有很多偽邊緣,我們通過設置高低雙閾值的方法去除它們,具體思想是:梯度值大于高閾值的像素點認為其一定是邊緣,置為255,梯度值小于低閾值的像素點認為其一定不是邊緣置為0,介于兩閾值之間的點像素點為待定邊緣。然后,考察這些待定邊緣點,如果其像素點周圍8鄰域的梯度值都小于高閾值,認為其不是邊緣點,置為0;至于,如何設定雙閾值大小,我們可以根據實際情況設定,如設成100和20,也可以根據圖像梯度值的統(tǒng)計信息設定,一般小閾值是大閾值的0.4倍即可。程序如下:

fmean = fmean / maxGradient * 255;//某統(tǒng)計信息 highThreshold = (byte)(fmean);//高閾值 lowThreshold = (byte)(0.4 * highThreshold); //低閾值 for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){if (dis[y * disdata.Stride + x] < highThreshold){if (dis[y * disdata.Stride + x] < lowThreshold){dis[y * disdata.Stride + x] = 0;}else{if ((dis[y * disdata.Stride + x - 1] < highThreshold) &&(dis[y * disdata.Stride + x + 1] < highThreshold) &&(dis[(y - 1) * disdata.Stride + x - 1] < highThreshold) &&(dis[(y - 1) * disdata.Stride + x] < highThreshold) &&(dis[(y - 1) * disdata.Stride + x + 1] < highThreshold) &&(dis[(y + 1) * disdata.Stride + x - 1] < highThreshold) &&(dis[(y + 1) * disdata.Stride + x] < highThreshold) &&(dis[(y + 1) * disdata.Stride + x + 1] < highThreshold)){dis[y * disdata.Stride + x] = 0;}}}}}

????? 最后,效果圖如下

原圖:

灰度圖:

邊緣圖:


?

?

總結

以上是生活随笔為你收集整理的Canny边缘检测原理及C#程序实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。