使用 C# 實現圖像的邊緣檢測


轉自:http://www.tangrui.net/2006/01/22/implementation-of-edge-detection-using-csharp

     我本人對圖像處理沒什么興趣,要不是這門課要交作業,我才懶得做這些東西。唉……不過程序寫了,自然會有一點想法,發到 Blog 上,以備后用吧。但是,即便是寫了程序,也仍然不知道作邊緣檢測的原理何在,只是模糊的知道大概是對圖像灰度求梯度,梯度大的就是邊緣了。但畢竟圖像是離散化的,可以使用另外的方法求梯度,而不用像高數中那樣拼命地算偏導數了。有很多學者提出了很多種不同性能的模板,只要按照模板作簡單的四則運算就行了,當然這也是能用程序實現的關鍵。由於作為教學課程,所有的內容都是以簡單的灰度圖像來說明舉例的,當然邊緣檢測也不例外,留作業寫程序也是一樣,所以馬上就遇到的一個問題是如何將彩色圖像轉為灰度圖像。在課程中,都是簡單的認為灰度圖像只有一個亮度,這自然是沒錯的,但是放到計算機里,灰度也是一種顏色,是顏色就要使用色彩模式(最常用的自然是 RGB 了),那么這種灰度到底應該是怎樣的顏色編碼呢?索性取向 Photoshop ,看一看各種灰度色調,終於有所發祥。其實也可以這么想,全黑是 #000000 ,全白是 #FFFFFF ,那么是不是只要 RGB 值都相等,這個顏色就是灰度色呢?試了一下,果然如此。這樣就好辦了,至少第一步知道了轉換的目標是什么了。但馬上就又有了一個問題,彩色圖片的顏色這么多,那么如何知道哪種彩色顏色對應哪種灰度顏色呢?這一點我從 .net Framework 中找到了答案。其實我從一開始就想在 .net Framework 中尋找有沒有直接將 RGB 轉成灰度或者是 HIS 模式(因為 HIS 模式中的 I 就使亮度,自然就容易轉成灰度了)的,是不是太奢望了,所以我也沒抱太大的希望,但是在這過程中卻發現 Color 中有關一個實例方法 GetBrightness() ,就是用來獲得顏色亮度的,真是踏破鐵鞋無覓處,得來全不費功夫。該方法返回一個 0~1 之間的浮點數,那么如果 RGB 每個各占一個字節的話,那么剛好可以用這個值去乘以 255 ,然后拼成一個 RGB ,這個顏色就是原始色彩所對應的灰色。程序代碼如下:
//定義兩個顏色變量,oColor為原始色彩,gColor為對應的灰度色彩
Color oColor,gColor;
//原始色彩的亮度
float brightness;
//灰度色彩用 RGB 來表示,由於 R=G=B 所以只用一個變量就可以了
int gRGB;
//遍歷圖像中的每個像素
for (int i = 0; i < oBmp.Width; i ++) {
    for (int j = 0; j < oBmp.Height; j ++) {
        //得到像素的原始色彩       
        oColor = oBmp.GetPixel(i,j);
        //得到該色彩的亮度
        brightness = oColor.GetBrightness();
        //用該亮度計算灰度
        gRGB = (int)(brightness * 255);
        //組成灰度色彩
        gColor = Color.FromArgb(gRGB,gRGB,gRGB);
        //最后將該灰度色彩賦予該像素
        gBmp.SetPixel(i,j,gColor);
    }
}

其實還是很簡單的。這之后就可以按照書中所說的模板游歷的方法來進行邊緣檢測了。程序如下:

//template為模板,nThreshold是一個閾值,
//用來將模板游歷的結果(也就是梯度)進行划分。
//大於閾值的和小於閾值的分別賦予兩種顏色,白或黑來標志邊界和背景
private void EdgeDectect(int[,] template,int nThreshold) {
    //取出和模板等大的原圖中的區域
    int[,] gRGB = new int[3,3];
    //模板值結果,梯度
    int templateValue = 0;
    //遍歷灰度圖中每個像素
    for (int i = 1; i < gBmp.Width - 1; i ++) {
        for (int j = 1; j < gBmp.Height - 1; j ++) {
            //取得模板下區域的顏色,即灰度
            gRGB[0,0] = gBmp.GetPixel(i-1,j-1).R;
            gRGB[0,1] = gBmp.GetPixel(i-1,j).R;
            gRGB[0,2] = gBmp.GetPixel(i-1,j+1).R;
            gRGB[1,0] = gBmp.GetPixel(i,j-1).R;
            gRGB[1,1] = gBmp.GetPixel(i,j).R;
            gRGB[1,2] = gBmp.GetPixel(i,j+1).R;
            gRGB[2,0] = gBmp.GetPixel(i+1,j-1).R;
            gRGB[2,1] = gBmp.GetPixel(i+1,j).R;
            gRGB[2,2] = gBmp.GetPixel(i+1,j+1).R;
            //按模板計算
            for (int m = 0; m < 3; m ++) {
                for (int n = 0; n < 3; n ++) {
                    templateValue += template[m,n] * gRGB[m,n];
                }
            }
            //將梯度之按閾值分類,並賦予不同的顏色
            if (templateValue > nThreshold) {
                eBmp.SetPixel(i,j,Color.FromArgb(255,255,255)); //白
            } else {
                eBmp.SetPixel(i,j,Color.FromArgb(0,0,0)); //黑
            }
            templateValue = 0;
        }
    }
}

 

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com