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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

Canny边缘检测算法原理及其VC实现详解(二)

發布時間:2023/12/10 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Canny边缘检测算法原理及其VC实现详解(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

3、? Canny算法的實現流程

?? ? ? 由于本文主要目的在于學習和實現算法,而對于圖像讀取、視頻獲取等內容不進行闡述。因此選用OpenCV算法庫作為其他功能的實現途徑(關于OpenCV的使用,作者將另文表述)。首先展現本文將要處理的彩色圖片。


圖2 待處理的圖像

3.1 圖像讀取和灰度化

?? ? ??編程時采用上文所描述的第二種方法來實現圖像的灰度化。其中ptr數組中保存的灰度化后的圖像數據。具體的灰度化后的效果如圖3所示。

  • IplImage*?ColorImage?=?cvLoadImage(?"12.jpg",?-1?);???//讀入圖像,獲取彩圖指針??
  • IplImage*?OpenCvGrayImage;????????????????????????????//定義變換后的灰度圖指針??
  • unsigned?char*?ptr;???????????????????????????????????//指向圖像的數據首地址??
  • if?(ColorImage?==?NULL)??
  • ?????return;????????
  • int?i?=?ColorImage->width?*?ColorImage->height;?????????
  • BYTE?data1;???????//中間過程變量??
  • BYTE?data2;??
  • BYTE?data3;??
  • ptr?=?new?unsigned?char[i];??
  • for(intj=0;?j<ColorImage->height;?j++)?????????????????//對RGB加權平均,權值參考OpenCV??
  • {??
  • ?????for(intx=0;?x<ColorImage->width;?x++)??
  • ?????{??
  • ?????????data1?=?(BYTE)ColorImage->imageData[j*ColorImage->widthStep?+?i*3];?????//B分量??
  • ?????data2?=?(BYTE)ColorImage->imageData[j*ColorImage->widthStep?+?i*3?+?1];?//G分量??
  • ?????data3?=?(BYTE)ColorImage->imageData[j*ColorImage->widthStep?+?i*3?+?2];?//R分量??
  • ?????????ptr[j*ColorImage->width+x]=(BYTE)(0.072169*data1?+?0.715160*data2?+?0.212671*data3);??
  • ?????}??
  • }??
  • OpenCvGrayImage=cvCreateImageHeader(cvGetSize(ColorImage),?ColorImage->depth,?1);????
  • cvSetData(GrayImage,ptr,?GrayImage->widthStep);?????????//根據數據生成灰度圖??
  • cvNamedWindow("GrayImage",CV_WINDOW_AUTOSIZE);??
  • cvShowImage("GrayImage",OpenCvGrayImage);???????????????//顯示灰度圖??
  • cvWaitKey(0);??
  • cvDestroyWindow("GrayImage");??

  • 圖3 灰度化后的圖像

    3.2 圖像的高斯濾波

    ?? ? ??根據上面所講的邊緣檢測過程,下一個步驟就是對圖像進行高斯濾波。可根據之前博文描述的方法獲取一維或者二維的高斯濾波核。因此進行圖像高斯濾波可有兩種實現方式,以下具體進行介紹。

    ?? ? ??首先定義該部分的通用變量:
  • double?nSigma?=?0.4;????????????????????????????//定義高斯函數的標準差??
  • int?nWidowSize?=?1+2*ceil(3*nSigma);????????????//定義濾波窗口的大小??
  • int?nCenter?=?(nWidowSize)/2;???????????????????//定義濾波窗口中心的索引??
  • ?? ? ? 兩種方法都需要用到的變量:
  • int?nWidth?=?OpenCvGrayImage->width;?????????????????????????????//獲取圖像的像素寬度??
  • int?nHeight?=?OpenCvGrayImage->height;???????????????????????????//獲取圖像的像素高度??
  • unsigned?char*?nImageData?=?new?unsigned?char[nWidth*nHeight];???//暫時保存圖像中的數據??
  • unsigned?char*pCanny?=?new?unsigned?char[nWidth*nHeight];????????//為平滑后的圖像數據分配內存??
  • double*?nData?=?new?double[nWidth*nHeight];??????????????????????//兩次平滑的中間數據??
  • for(int?j=0;?j<nHeight;?j++)?????????????????????????????????????//獲取數據??
  • {??
  • ????for(i=0;?i<nWidth;?i++)??
  • ?????????????nImageData[j*nWidth+i]?=?(unsigned?char)OpenCvGrayImage->imageData[j*nWidth+i];??
  • }??
  • 3.2.1 根據一維高斯核進行兩次濾波

    ?? ? ??1)生成一維高斯濾波系數

  • //生成一維高斯濾波系數/??
  • double*?pdKernal_1?=?new?double[nWidowSize];????//定義一維高斯核數組??
  • double??dSum_1?=?0.0;???????????????????????????//求和,用于進行歸一化??????????
  • 一維高斯函數公式//???????
  • ???????????????????x*x???????????????????????????/??
  • ??????????-1*----------------????????????????????/??
  • ?????????1?????2*Sigma*Sigma?????????????????????/??
  • ???------------?e????????????????????????????????/??
  • ?????????????????????????????????????????????????/??
  • ???\/2*pi*Sigma??????????????????????????????????/??
  • //??
  • for(int?i=0;?i<nWidowSize;?i++)??
  • {??
  • ????????double?nDis?=?(double)(i-nCenter);??
  • ????pdKernal_1[i]?=?exp(-(0.5)*nDis*nDis/(nSigma*nSigma))/(sqrt(2*3.14159)*nSigma);??
  • ????dSum_1?+=?pdKernal_1[i];??
  • }??
  • for(i=0;?i<nWidowSize;?i++)??
  • {??
  • ????pdKernal_1[i]?/=?dSum_1;?????????????????//進行歸一化??
  • }??

  • ?? ? ? 2)分別進行x向和y向的一維加權濾波,濾波后的數據保存在矩陣pCanny中
  • for(i=0;?i<nHeight;?i++)???????????????????????????????//進行x向的高斯濾波(加權平均)??
  • {??
  • ????for(j=0;?j<nWidth;?j++)??
  • ????{??
  • ????????double?dSum?=?0;??
  • ????????double?dFilter=0;???????????????????????????????????????//濾波中間值??
  • ????????for(int?nLimit=(-nCenter);?nLimit<=nCenter;?nLimit++)??
  • ????????{??
  • ????????????if((j+nLimit)>=0?&&?(j+nLimit)?<?nWidth?)???????//圖像不能超出邊界??
  • ????????????{??
  • ????????????????dFilter?+=?(double)nImageData[i*nWidth+j+nLimit]?*?pdKernal_1[nCenter+nLimit];??
  • ????????????????dSum?+=?pdKernal_1[nCenter+nLimit];??
  • ????????????}??
  • ????????}??
  • ????????nData[i*nWidth+j]?=?dFilter/dSum;??
  • ????}??
  • }??
  • ??
  • for(i=0;?i<nWidth;?i++)????????????????????????????????//進行y向的高斯濾波(加權平均)??
  • {??
  • ????for(j=0;?j<nHeight;?j++)??
  • ????{??
  • ????????double?dSum?=?0.0;??
  • ????????double?dFilter=0;??
  • ????????for(int?nLimit=(-nCenter);?nLimit<=nCenter;?nLimit++)??
  • ????????{??
  • ????????????if((j+nLimit)>=0?&&?(j+nLimit)?<?nHeight)???????//圖像不能超出邊界??
  • ????????????{??
  • ????????????????dFilter?+=?(double)nData[(j+nLimit)*nWidth+i]?*?pdKernal_1[nCenter+nLimit];??
  • ????????????????dSum?+=?pdKernal_1[nCenter+nLimit];??
  • ????????????}??
  • ????????}??
  • ????????pCanny[j*nWidth+i]?=?(unsigned?char)(int)dFilter/dSum;??
  • ????}??
  • }??

  • 3.2.2?根據二維高斯核進行濾波

    ?? ? ?1)生成二維高斯濾波系數

  • //生成一維高斯濾波系數//????
  • double*?pdKernal_2?=?new?double[nWidowSize*nWidowSize];?//定義一維高斯核數組??
  • double??dSum_2?=?0.0;???????????????????????????????????//求和,進行歸一化????????
  • ///二維高斯函數公式??????
  • ?????????????????????????x*x+y*y????????????????????????///??
  • ???????????????????-1*--------------????????????????///??
  • ?????????1?????????????2*Sigma*Sigma????????????????///??
  • ???----------------?e???????????????????????????????????///??
  • ???2*pi*Sigma*Sigma?????????????????????????????????????///??
  • ///??
  • for(i=0;?i<nWidowSize;?i++)??
  • {??
  • ????for(int?j=0;?j<nWidowSize;?j++)??
  • ????{??
  • ????????int?nDis_x?=?i-nCenter;??
  • ????????int?nDis_y?=?j-nCenter;??
  • ????????pdKernal_2[i+j*nWidowSize]=exp(-(1/2)*(nDis_x*nDis_x+nDis_y*nDis_y)??
  • ????????????/(nSigma*nSigma))/(2*3.1415926*nSigma*nSigma);??
  • ????????dSum_2?+=?pdKernal_2[i+j*nWidowSize];??
  • ????}??
  • }??
  • for(i=0;?i<nWidowSize;?i++)??
  • {??
  • ????for(int?j=0;?j<nWidowSize;?j++)?????????????????//進行歸一化??
  • ????????{??
  • ????????pdKernal_2[i+j*nWidowSize]?/=?dSum_2;??
  • ????}??
  • }??

  • ?? ? ?2)采用高斯核進行高斯濾波,濾波后的數據保存在矩陣pCanny中
  • int?x;??
  • int?y;??
  • for(i=0;?i<nHeight;?i++)??
  • {??
  • ????for(j=0;?j<nWidth;?j++)??
  • ????{??
  • ????????double?dFilter=0.0;??
  • ????????double?dSum?=?0.0;??
  • ????????for(x=(-nCenter);?x<=nCenter;?x++)?????????????????????//行??
  • ????????{??
  • ????????????????????????for(y=(-nCenter);?y<=nCenter;?y++)?????????????//列??
  • ????????????{??
  • ????????????????if(?(j+x)>=0?&&?(j+x)<nWidth?&&?(i+y)>=0?&&?(i+y)<nHeight)?//判斷邊緣??
  • ????????????????{??
  • ????????????????????dFilter?+=?(double)nImageData?[(i+y)*nWidth?+?(j+x)]??
  • ????????????????????????*?pdKernal_2[(y+nCenter)*nWidowSize+(x+nCenter)];??
  • ????????????????????dSum?+=?pdKernal_2[(y+nCenter)*nWidowSize+(x+nCenter)];??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????????pCanny[i*nWidth+j]?=?(unsigned?char)dFilter/dSum;??
  • ????}??
  • }??

  • 3.3 圖像增強——計算圖像梯度及其方向
    ?? ? ?根據上文分析可知,實現代碼如下
  • //同樣可以用不同的檢測器/??
  • /????P[i,j]=(S[i,j+1]-S[i,j]+S[i+1,j+1]-S[i+1,j])/2?????/??
  • /????Q[i,j]=(S[i,j]-S[i+1,j]+S[i,j+1]-S[i+1,j+1])/2?????/??
  • /??
  • double*?P?=?new?double[nWidth*nHeight];?????????????????//x向偏導數??
  • double*?Q?=?new?double[nWidth*nHeight];?????????????????//y向偏導數??
  • int*?M?=?new?int[nWidth*nHeight];???????????????????????//梯度幅值??
  • double*?Theta?=?new?double[nWidth*nHeight];?????????????//梯度方向??
  • //計算x,y方向的偏導數??
  • for(i=0;?i<(nHeight-1);?i++)??
  • {??
  • ????????for(j=0;?j<(nWidth-1);?j++)??
  • ????????{??
  • ??????????????P[i*nWidth+j]?=?(double)(pCanny[i*nWidth?+?min(j+1,?nWidth-1)]?-?pCanny[i*nWidth+j]?+?pCanny[min(i+1,?nHeight-1)*nWidth+min(j+1,?nWidth-1)]?-?pCanny[min(i+1,?nHeight-1)*nWidth+j])/2;??
  • ??????????????Q[i*nWidth+j]?=?(double)(pCanny[i*nWidth+j]?-?pCanny[min(i+1,?nHeight-1)*nWidth+j]?+?pCanny[i*nWidth+min(j+1,?nWidth-1)]?-?pCanny[min(i+1,?nHeight-1)*nWidth+min(j+1,?nWidth-1)])/2;??
  • ????}??
  • }??
  • //計算梯度幅值和梯度的方向??
  • for(i=0;?i<nHeight;?i++)??
  • {??
  • ????????for(j=0;?j<nWidth;?j++)??
  • ????????{??
  • ??????????????M[i*nWidth+j]?=?(int)(sqrt(P[i*nWidth+j]*P[i*nWidth+j]?+?Q[i*nWidth+j]*Q[i*nWidth+j])+0.5);??
  • ??????????????Theta[i*nWidth+j]?=?atan2(Q[i*nWidth+j],?P[i*nWidth+j])?*?57.3;??
  • ??????????????if(Theta[i*nWidth+j]?<?0)??
  • ????????????????????Theta[i*nWidth+j]?+=?360;??????????????//將這個角度轉換到0~360范圍??
  • ????}??
  • }??


  • 3.4 非極大值抑制

    ?? ? ?根據上文所述的工作原理,這部分首先需要求解每個像素點在其鄰域內的梯度方向的兩個灰度值,然后判斷是否為潛在的邊緣,如果不是則將該點灰度值設置為0.

    ?? ? ?首先定義相關的參數如下:

  • unsigned?char*?N?=?new?unsigned?char[nWidth*nHeight];??//非極大值抑制結果??
  • int?g1=0,?g2=0,?g3=0,?g4=0;????????????????????????????//用于進行插值,得到亞像素點坐標值??
  • double?dTmp1=0.0,?dTmp2=0.0;???????????????????????????//保存兩個亞像素點插值得到的灰度數據??
  • double?dWeight=0.0;????????????????????????????????????//插值的權重??
  • ?? ? ?其次,對邊界進行初始化:
  • for(i=0;?i<nWidth;?i++)??
  • {??
  • ????????N[i]?=?0;??
  • ????????N[(nHeight-1)*nWidth+i]?=?0;??
  • }??
  • for(j=0;?j<nHeight;?j++)??
  • {??
  • ????????N[j*nWidth]?=?0;??
  • ????????N[j*nWidth+(nWidth-1)]?=?0;??
  • }??
  • ?? ? ?進行局部最大值尋找,根據上文圖1所述的方案進行插值,然后判優,實現代碼如下:
  • for(i=1;?i<(nWidth-1);?i++)??
  • {??
  • ????for(j=1;?j<(nHeight-1);?j++)??
  • ????{??
  • ????????int?nPointIdx?=?i+j*nWidth;???????//當前點在圖像數組中的索引值??
  • ????????if(M[nPointIdx]?==?0)??
  • ????????????N[nPointIdx]?=?0;?????????//如果當前梯度幅值為0,則不是局部最大對該點賦為0??
  • ????????else??
  • ????????{??
  • ????????首先判斷屬于那種情況,然后根據情況插值///??
  • ????????第一種情況///??
  • ????????/???????g1??g2??????????????????/??
  • ????????/???????????C???????????????????/??
  • ????????/???????????g3??g4??????????????/??
  • ????????/??
  • ????????if(?((Theta[nPointIdx]>=90)&&(Theta[nPointIdx]<135))?||???
  • ????????????????((Theta[nPointIdx]>=270)&&(Theta[nPointIdx]<315)))??
  • ????????????{??
  • ????????????????//根據斜率和四個中間值進行插值求解??
  • ????????????????g1?=?M[nPointIdx-nWidth-1];??
  • ????????????????g2?=?M[nPointIdx-nWidth];??
  • ????????????????g3?=?M[nPointIdx+nWidth];??
  • ????????????????g4?=?M[nPointIdx+nWidth+1];??
  • ????????????????dWeight?=?fabs(P[nPointIdx])/fabs(Q[nPointIdx]);???//反正切??
  • ????????????????dTmp1?=?g1*dWeight+g2*(1-dWeight);??
  • ????????????????dTmp2?=?g4*dWeight+g3*(1-dWeight);??
  • ????????????}??
  • ????????第二種情況///??
  • ????????/???????g1??????????????????????/??
  • ????????/???????g2??C???g3??????????????/??
  • ????????/???????????????g4??????????????/??
  • ????????/??
  • ????????????else?if(?((Theta[nPointIdx]>=135)&&(Theta[nPointIdx]<180))?||???
  • ????????????????((Theta[nPointIdx]>=315)&&(Theta[nPointIdx]<360)))??
  • ????????????{??
  • ????????????????g1?=?M[nPointIdx-nWidth-1];??
  • ????????????????g2?=?M[nPointIdx-1];??
  • ????????????????g3?=?M[nPointIdx+1];??
  • ????????????????g4?=?M[nPointIdx+nWidth+1];??
  • ????????????????dWeight?=?fabs(Q[nPointIdx])/fabs(P[nPointIdx]);???//正切??
  • ????????????????dTmp1?=?g2*dWeight+g1*(1-dWeight);??
  • ????????????????dTmp2?=?g4*dWeight+g3*(1-dWeight);??
  • ????????????}??
  • ????????第三種情況///??
  • ????????/???????????g1??g2??????????????/??
  • ????????/???????????C???????????????????/??
  • ????????/???????g4??g3??????????????????/??
  • ????????/??
  • ????????????else?if(?((Theta[nPointIdx]>=45)&&(Theta[nPointIdx]<90))?||???
  • ????????????????((Theta[nPointIdx]>=225)&&(Theta[nPointIdx]<270)))??
  • ????????????{??
  • ????????????????g1?=?M[nPointIdx-nWidth];??
  • ????????????????g2?=?M[nPointIdx-nWidth+1];??
  • ????????????????g3?=?M[nPointIdx+nWidth];??
  • ????????????????g4?=?M[nPointIdx+nWidth-1];??
  • ????????????????dWeight?=?fabs(P[nPointIdx])/fabs(Q[nPointIdx]);???//反正切??
  • ????????????????dTmp1?=?g2*dWeight+g1*(1-dWeight);??
  • ????????????????dTmp2?=?g3*dWeight+g4*(1-dWeight);??
  • ????????????}??
  • ????????????第四種情況///??
  • ????????????/???????????????g1??????????????/??
  • ????????????/???????g4??C???g2??????????????/??
  • ????????????/???????g3??????????????????????/??
  • ????????????/??
  • ????????????else?if(?((Theta[nPointIdx]>=0)&&(Theta[nPointIdx]<45))?||???
  • ????????????????((Theta[nPointIdx]>=180)&&(Theta[nPointIdx]<225)))??
  • ????????????{??
  • ????????????????g1?=?M[nPointIdx-nWidth+1];??
  • ????????????????g2?=?M[nPointIdx+1];??
  • ????????????????g3?=?M[nPointIdx+nWidth-1];??
  • ????????????????g4?=?M[nPointIdx-1];??
  • ????????????????dWeight?=?fabs(Q[nPointIdx])/fabs(P[nPointIdx]);???//正切??
  • ????????????????dTmp1?=?g1*dWeight+g2*(1-dWeight);??
  • ????????????????dTmp2?=?g3*dWeight+g4*(1-dWeight);??
  • ????????????}??
  • ????????}?????????
  • ????????//進行局部最大值判斷,并寫入檢測結果??
  • ????????if((M[nPointIdx]>=dTmp1)?&&?(M[nPointIdx]>=dTmp2))??
  • ????????????N[nPointIdx]?=?128;??
  • ????????else??
  • ????????????N[nPointIdx]?=?0;??
  • ????????}??
  • }??
  • 3.5雙閾值檢測實現

    ?? ? ?1)定義相應參數如下

  • int?nHist[1024];???
  • int?nEdgeNum;?????????????//可能邊界數??
  • int?nMaxMag?=?0;??????????//最大梯度數??
  • int?nHighCount;??

  • ?? ? ?2)構造灰度圖的統計直方圖,根據上文梯度幅值的計算公式可知,最大的梯度幅值為:
    ?? ? ?因此設置nHist為1024足夠。以下實現統計直方圖:
  • for(i=0;i<1024;i++)??
  • ????????nHist[i]?=?0;??
  • for(i=0;?i<nHeight;?i++)??
  • {??
  • ????????for(j=0;?j<nWidth;?j++)??
  • ????????{??
  • ??????????????if(N[i*nWidth+j]==128)??
  • ???????????????????nHist[M[i*nWidth+j]]++;??
  • ????????}??
  • }??
  • ?? ? ?3)獲取最大梯度幅值及潛在邊緣點個數

  • nEdgeNum?=?nHist[0];??
  • nMaxMag?=?0;????????????????????//獲取最大的梯度值????????
  • for(i=1;?i<1024;?i++)???????????//統計經過“非最大值抑制”后有多少像素??
  • {??
  • ????if(nHist[i]?!=?0)???????//梯度為0的點是不可能為邊界點的??
  • ????{??
  • ????????nMaxMag?=?i;??
  • ????}?????
  • ????nEdgeNum?+=?nHist[i];???//經過non-maximum?suppression后有多少像素??
  • }??

  • ?? ? ?4)計算兩個閾值
  • double??dRatHigh?=?0.79;??
  • double??dThrHigh;??
  • double??dThrLow;??
  • double??dRatLow?=?0.5;??
  • nHighCount?=?(int)(dRatHigh?*?nEdgeNum?+?0.5);??
  • j=1;??
  • nEdgeNum?=?nHist[1];??
  • while((j<(nMaxMag-1))?&&?(nEdgeNum?<?nHighCount))??
  • {??
  • ???????j++;??
  • ???????nEdgeNum?+=?nHist[j];??
  • }??
  • dThrHigh?=?j;???????????????????????????????????//高閾值??
  • dThrLow?=?(int)((dThrHigh)?*?dRatLow?+?0.5);????//低閾值??

  • ?? ? ?這段代碼的意思是,按照灰度值從低到高的順序,選取前79%個灰度值中的最大的灰度值為高閾值,低閾值大約為高閾值的一半。這是根據經驗數據的來的,至于更好地參數選取方法,作者后面會另文研究。
    ?? ? ?5)進行邊緣檢測
  • SIZE?sz;??
  • sz.cx?=?nWidth;??
  • sz.cy?=?nHeight;??
  • for(i=0;?i<nHeight;?i++)??
  • {??
  • ????for(j=0;?j<nWidth;?j++)??
  • ????{??
  • ????????if((N[i*nWidth+j]==128)?&&?(M[i*nWidth+j]?>=?dThrHigh))??
  • ????????{??
  • ????????????N[i*nWidth+j]?=?255;??
  • ????????????TraceEdge(i,?j,?dThrLow,?N,?M,?sz);??
  • ????????}??
  • ????}??
  • }??

  • ?? ? ? ?以上代碼在非極大值抑制產生的二值灰度矩陣的潛在點中按照高閾值尋找邊緣,并以所找到的點為中心尋找鄰域內滿足低閾值的點,從而形成一個閉合的輪廓。然后對于不滿足條件的點,可用如下代碼直接刪除掉。
  • //將還沒有設置為邊界的點設置為非邊界點??
  • for(i=0;?i<nHeight;?i++)??
  • {??
  • ????for(j=0;?j<nWidth;?j++)??
  • ????{??
  • ????????if(N[i*nWidth+j]?!=?255)??
  • ????????{??
  • ????????????N[i*nWidth+j]??=?0?;???//?設置為非邊界點??
  • ????????}??
  • ????}??
  • }??
  • ?? ? ? 其中TraceEdge函數為一個嵌套函數,用于在每個像素點的鄰域內尋找滿足條件的點。其實現代碼如下:

  • 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算法。其檢測效果如圖4所示。注意:以上代碼僅為作者理解所為,目的是驗證本人對算法的理解,暫時沒有考慮到代碼的執行效率的問題。

    圖4 邊緣檢測結果

    4、擴展

    首先看一下OpenCV中cvCanny函數對該圖像的處理結果,如圖5所示。
    圖5 OpenCV中的Canny邊緣檢測結果

    ?? ? 對比圖4和圖5可以發現,作者自己實現的邊緣檢測效果沒有OpenCV的好,具體體現在:1)丟失了一些真的邊緣;2)增加了一些假的邊緣。

    ?? ? ?經過對整個算法的來回檢查,初步推斷主要的問題可能在于在進行灰度矩陣梯度幅值計算式所采用的模板算子性能不是太好,還有就是關于兩個閾值的選取方法。關于這兩個方面的改進研究,后文闡述。

    5、總結

    ?? ? ? ? 本文是過去一段時間,對圖像邊緣檢測方法學習的總結。主要闡述了Canny算法的工作原理,實現過程,在此基礎上基于VC6.0實現了該算法,并給出了效果圖。最后,通過對比發現本文的實現方法雖然能夠實現邊緣檢測,但效果還不是很理想,今后將在閾值選取原則和梯度幅值算子兩個方面進行改進。

    總結

    以上是生活随笔為你收集整理的Canny边缘检测算法原理及其VC实现详解(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

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