邊緣檢測 是圖像處理 過程中經常會涉及到的一個環節。而在計算機視覺 和 機器學習領域,邊緣檢測 用於 特徵提取 和 特徵檢測 效果也是特別明顯。而 openCV 中進行邊緣檢測的 算法 真是五花八門,下面我就選幾個最常用算法的函數api進行介紹。
本文涉及到的效果請看:邊緣檢測
內容大綱
-
轉換灰度圖
-
自適應閾值處理
-
Sobel算子
-
Scharr算子
-
Laplacian算子
-
Canny邊緣檢測
-
Sobel算子 結合 Laplacian算子
轉換灰度圖
openCV 中有個色彩類型轉換函數,其中轉換爲灰度圖( cv.COLOR_RGB2GRAY)出現頻率非常高,是其他操作的基礎,色彩類型轉換函數:
cv.cvtColor (src, dst, code, dstCn = 0)
- src: 原始圖像
- dst: 輸出圖像
- code: 色彩空間轉換碼,灰度圖爲cv.COLOR_RGB2GRAY,其他類型可查api文檔
- dstcn: 圖像通道數
const src = cv.imread(img);//讀取圖像數據
const dst = new cv.Mat();//輸出的圖像
cv.cvtColor(src, dst, cv.COLOR_RGB2GRAY, 0);//轉換爲灰度圖
cv.imshow(canvas, dst);
src.delete();
dst.delete();
自適應閾值處理
自適應閾值處理的方式通過計算每個像素點周圍鄰近區域的加權平均值獲得閾值,並使用該閾值對當前像素點進行處理。自適應閾值處理函數:
cv.adaptiveThreshold(src, dst, maxValue, adaptiveMethod, thresholdType)
- maxValue:需要處理的最大值
- adaptiveMethod:自適應閾值算法,可選 cv.ADAPTIVE_THRESH_GAUSSIAN_C (高斯方程) 或 cv.ADAPTIVE_THRESH_MEAN_C(加權平均)
- thresholdType: 閾值處理方法,可選 cv.THRESH_BINARY(二值化) 或 cv.THRESH_BINARY_INV(二值化取反)
const src = cv.imread(img);
const dst = new cv.Mat();
cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);//轉換爲灰度圖
cv.adaptiveThreshold(src, dst, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 5, 7);//自適應閾值處理
cv.imshow(canvas, dst);//顯示輸出圖像
效果如下:
Sobel算子
Sobel算子結合了高斯平滑 和微分求導運算,利用局部差分尋找邊緣,計算所得到的是一個梯度近似值。Sobel算子比較特殊的地方是要分別橫向計算和縱向計算,然後再把兩者結合,這就需要用到 cv.addWeighted 這個函數按比例顯示輸出圖像xy方向的佔比。Sobel算子函數:
cv.Sobel (src, dst, ddepth, dx, dy, ksize = 3, scale = 1, delta = 0, borderType = cv.BORDER_DEFAULT)
- ddepth:輸出圖像的深度,可選 cv.CV_8U,cv.CV_16U,cv.CV_32F,cv.CV_64F
- dx:x方向求導
- dy:y方向求導
- ksize:核大小,可選1,3,5,7
- scale:縮放因子,默認1
- delta:圖像dst的值,默認0
- borderType:邊界樣式,具體可查看api文檔
const src = cv.imread(img);
const dstx = new cv.Mat();
const dsty = new cv.Mat();
const dst = new cv.Mat();
cv.cvtColor(src, src, cv.COLOR_RGB2GRAY, 0);
cv.Sobel(src, dstx, cv.CV_8U, 1, 0, 1, 3, 0, cv.BORDER_DEFAULT); //Sobel算子 x方向
cv.Sobel(src, dsty, cv.CV_8U, 0, 1, 1, 3, 0, cv.BORDER_DEFAULT); //Sobel算子 y方向
cv.addWeighted(dstx, 0.5, dsty, 0.5, 0, dst); //分別給xy方向分配權重比例
cv.imshow(canvas, dst);
效果如下:
Scharr算子
Scharr算子可以看做是對Sobel算子的改進,它的精度更高,調用方式和Sobel算子基本一致,只是少了ksize 這個參數,下面直接看調用代碼不同的部分:
cv.Scharr(src, dstx, cv.CV_8U, 1, 0, 1, 0, cv.BORDER_DEFAULT); //Scharr算子 x方向
cv.Scharr(src, dsty, cv.CV_8U, 0, 1, 1, 0, cv.BORDER_DEFAULT); //Scharr算子 y方向
cv.addWeighted(dstx, 0.5, dsty, 0.5, 0, dst); //分別給xy方向分配權重比例
效果如下:
Laplacian算子
Laplacian(拉普拉斯)算子是一種二階導數算子,可以滿足不同方向的圖像邊緣銳化,Laplacian(拉普拉斯)算子分別進行了兩次橫向和縱向的計算。因此就不用跟 Sobel算子 和 Scharr算子 一樣要分別單獨計算xy了。Laplacian算子函數:
cv.Laplacian (src, dst, ddepth, ksize = 1, scale = 1, delta = 0, borderType = cv.BORDER_DEFAULT)
- ddepth:輸出圖像的深度,可選 cv.CV_8U,cv.CV_16U,cv.CV_32F,cv.CV_64F
- ksize:核大小,可選1,3,5,7
- scale:縮放因子,默認1
- delta:圖像dst的值,默認0
- borderType:邊界樣式,具體可查看api文檔
const src = cv.imread(img);
const dst = new cv.Mat();
cv.cvtColor(src, src, cv.COLOR_RGB2GRAY, 0);
cv.Laplacian(src, dst, cv.CV_8U, 1, 1, 0, cv.BORDER_DEFAULT); //拉普拉斯算子
cv.imshow(canvas, dst);
效果如下:
Canny邊緣檢測
Canny邊緣檢測是一種使用多級邊緣檢測算法的方法。它會經過去噪,計算梯度,非極大值抑制,確定邊緣這幾個步驟,好像很強大的感覺。Canny函數:
cv.Canny(src, dot, threshold1, threshold2, apertureSize = 3, L2gradient = false)
- threshold1: 第一個閾值,值較小時能獲取更多邊緣信息
- threshold2: 第二個閾值,值較小時能獲取更多邊緣信息
- apertureSize: 孔徑大小
- L2gradient: 圖像梯度幅度,默認False
const src = cv.imread(img);
const dst = new cv.Mat();
cv.cvtColor(src, src, cv.COLOR_RGB2GRAY, 0);
cv.Canny(src, dst, 50, 100, 3, false);
cv.imshow(canvas, dst);
效果如下:
Sobel算子 結合 Laplacian算子
openCV 還可以將不同算法結合起來,達到更好的效果,我們就以 Sobel算子 結合 Laplacian算子 爲例
const src = cv.imread(img);
const dstx = new cv.Mat();
const dsty = new cv.Mat();
const dst = new cv.Mat();
const dst2 = new cv.Mat();
cv.Sobel(src, dstx, cv.CV_8U, 1, 0, 1, 3, 0, cv.BORDER_DEFAULT); //sobel算子 x方向
cv.Sobel(src, dsty, cv.CV_8U, 0, 1, 1, 3, 0, cv.BORDER_DEFAULT); //sobel算子 y方向
cv.addWeighted(dstx, 0.5, dsty, 0.5, 0, dst); //分別給xy方向分配權重比例
cv.Laplacian(src, dst2, cv.CV_8U, 1, 1, 0, cv.BORDER_DEFAULT); //拉普拉斯算子
const mask = new cv.Mat();
cv.add(dst, dst2, dst2, mask, -1); //圖像相加
cv.imshow(canvas, dst2);
效果如下:
總結
openCV中實現邊緣檢測遠不止上面介紹的幾種,還有一種更強大的方式實現邊緣檢測,那就是傅立葉變換,它完全可以實現上面說的算法,但是比較複雜而已。我們需要做的就是了解清楚每種算法 效果有什麼差異,以及最適合使用的場景。