執行邊緣檢測的三個基本步驟:
1、為降噪對圖像進行平滑處理。(導數對噪聲具有敏感性。圖像的正負分量檢測困難)
2、邊緣點的檢測。(提取邊緣點的潛在候選者)
3、邊緣定位。(從候選者中選出真是邊緣點成員)
基本算子:梯度算子(表征某點邊緣強度和方向,又稱邊緣檢測子)
較為簡單的邊緣檢測算子模板:
sobel模板能較好地抑制噪聲。
常用絕對值來近似梯度幅值,保持灰度級的相對變化,代價是導致濾波器不再是各向同性的。
sobel計算過程
Opencv庫函數調用方法:
void Sobel (
InputArray src,
OutputArray dst,
int ddepth,
int dx, x方向上的差分階數
int dy, y方向上的差分階數
int ksize=3, 核的大小,為奇數
double scale=1, 計算導數時的縮放因子
double delta=0, 將結果存入目標圖像前可選的值
int borderType=BORDER_DEFAULT ) ;
int main()
{// Read image 讀取圖像SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN); //字體為綠色//載入原圖Mat srcImage = imread("D:\\opencv_picture_test\\形態學操作\\coin_inv.png",0); //讀取灰度圖//判斷圖像是否加載成功if (srcImage.empty()){cout << "圖像加載失敗!" << endl;return -1;}elsecout << "圖像加載成功!" << endl << endl;Mat gradx, grady;Mat abs_gradx, abs_grady;Mat dstImage;//求x方向的梯度Sobel(srcImage,gradx,CV_16S,1,0,3,1,1,BORDER_DEFAULT);// x方向1階差分 y方向0 核大小3convertScaleAbs(gradx, abs_gradx); //絕對值//求y方向的梯度Sobel(srcImage, grady, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);// x方向1階差分 y方向0 核大小3convertScaleAbs(grady, abs_grady); //絕對值addWeighted(abs_gradx,0.5, abs_grady,0.5,0,dstImage);imshow("srcImage", srcImage);imshow("x方向", abs_gradx);imshow("y方向", abs_grady);imshow("整體", dstImage);waitKey(0);return 0;
}
經過ImageWatch放大發現,提取出的邊緣比較粗。
減少精密細節的兩種方法:
1、對圖像進行平滑處理(例如用均值濾波,得到主要邊緣)
2、對梯度圖像進行閾值處理(梯度幅值大于等于閾值為黑白,小于閾值為黑),不過這一方法容易斷線。
當為了突出主要邊緣并盡可能維護連續性時,平滑處理和閾值處理兩者都要使用。
roberts、prewitt,sobel算子都是以一個或多個模板進行濾波,而未對圖像特性和噪聲內容采取防護措施。
接下來介紹一種最優的邊緣檢測方法:canny算子
●低錯誤率:標識出盡可能多的實際邊緣,同時盡可能地減少噪聲產生的誤報。
●高定位性:標識出的邊緣要與圖像中的實際邊緣盡可能接近。
●最小響應:圖像中的邊緣只能標識-一次,并且可能存在的圖像噪聲不應標
識為邊緣。
canny算子計算過程
Opencv庫函數調用方法:
void Canny (InputArray image , OutputArray edges, double threshold1,
double threshold2 , 兩個閾值較小的用于邊緣連接,較大的用于控制強邊緣的初始端,一般比例控制在3:1或者2:1
int apertureSize=3, sobel核大小
bool L2gradient=false )
int main()
{// Read image 讀取圖像SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN); //字體為綠色//載入原圖Mat srcImage = imread("D:\\opencv_picture_test\\形態學操作\\coin_inv.png",0); //讀取灰度圖//判斷圖像是否加載成功if (srcImage.empty()){cout << "圖像加載失敗!" << endl;return -1;}elsecout << "圖像加載成功!" << endl << endl;Mat dstImage;Canny(srcImage,dstImage,100,33,3,false);imshow("srcImage", srcImage);imshow("整體", dstImage);waitKey(0);return 0;
}
效果:
經過ImageWatch放大,可以發現,邊緣只有一格
總的看來,canny算子確實具有優越性。
laplace計算過程
3*3孔徑的模板:
opencv庫函數調用:
int main()
{// Read image 讀取圖像SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN); //字體為綠色//載入原圖Mat srcImage = imread("D:\\opencv_picture_test\\形態學操作\\coin_inv.png", 0); //讀取灰度圖//判斷圖像是否加載成功if (srcImage.empty()){cout << "圖像加載失敗!" << endl;return -1;}elsecout << "圖像加載成功!" << endl << endl;Mat dstImage,abs_dst;GaussianBlur(srcImage,srcImage,Size(3,3),0); //高斯模糊Laplacian(srcImage,dstImage,CV_16S,3,1,0);convertScaleAbs(dstImage, abs_dst);imshow("srcImage", srcImage);imshow("整體", dstImage);waitKey(0);return 0;
}