原理:
參考鏈接:https://blog.csdn.net/poem_qianmo/article/details/25560901
Sobel算子
OpenCV調用:
C++: void Sobel (
InputArray src,//輸入圖
OutputArray dst,//輸出圖
int ddepth,//輸出圖像的深度
int dx,
int dy,
int ksize=3,
double scale=1,
double delta=0,
int borderType=BORDER_DEFAULT );
-
第一個參數,InputArray 類型的src,爲輸入圖像,填Mat類型即可。
-
第二個參數,OutputArray類型的dst,即目標圖像,函數的輸出參數,需要和源圖片有一樣的尺寸和類型。
-
第三個參數,int類型的ddepth,輸出圖像的深度,支持如下src.depth()和ddepth的組合:
- 若src.depth() = CV_8U, 取ddepth=-1/CV_16S/CV_32F/CV_64F
- 若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
- 若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F
- 若src.depth() = CV_64F, 取ddepth = -1/CV_64F
- 第四個參數,int類型dx,x 方向上的差分階數。
- 第五個參數,int類型dy,y方向上的差分階數。
- 第六個參數,int類型ksize,有默認值3,表示Sobel核的大小;必須取1,3,5或7。
- 第七個參數,double類型的scale,計算導數值時可選的縮放因子,默認值是1,表示默認情況下是沒有應用縮放的。
我們可以在文檔中查閱getDerivKernels的相關介紹,來得到這個參數的更多信息。
-
第八個參數,double類型的delta,表示在結果存入目標圖(第二個參數dst)之前可選的delta值,有默認值0。
-
第九個參數, int類型的borderType,我們的老朋友了(萬年是最後一個參數),邊界模式,默認值爲BORDER_DEFAULT。這個參數可以在官方文檔中borderInterpolate處得到更詳細的信息。
自寫Sobel算子邊緣檢測:
//把圖像的各個像素點的值存到一個二維數組,增加代碼的可讀性
int img_garry[imgHeight][imgWidth];
for(int i = 0; i<imgHeight; i++)
{
for(int j = 0; j<imgWidth;j++)
{
img_garry[i][j] = grayData[i*imgWidth+j];
}
}
//sobel算法
IplImage* sobel_img = NULL; //創建用於灰度圖像的結構體指針
sobel_img = cvCreateImage(cvSize(imgWidth,imgHeight), imgDepth, 1 ); //創建單通道的色彩空間用於灰度變換
uchar *sobel_Data = (uchar*) sobel_img->imageData;//聲明無符號char型指針指向結構體的變量imageData
double Gmax = 150; //設定閾值Gmax
double Gx=0;
double Gy=0;
double G =0;
for(int i = 1;i<imgHeight-2; i++)
for(int j = 1;j<imgWidth-2; j++)
{
Gx = -1 * img_garry[i-1][j-1] + 0 * img_garry[i-1][ j ] + 1 * img_garry[i-1][j+1]
+ -2 * img_garry[ i ][j-1] + 0 * img_garry[ i ][ j ] + 2 * img_garry[ i ][j+1]
+ -1 * img_garry[i+1][j-1] + 0 * img_garry[i+1][ j ] + 1 * img_garry[i+1][j+1];
Gy = -1 * img_garry[i-1][j-1] + -2 * img_garry[i-1][ j ] + -1 * img_garry[i-1][j+1]
+ 0 * img_garry[ i ][j-1] + 0 * img_garry[ i ][ j ] + 0 * img_garry[ i ][j+1]
+ 1 * img_garry[i+1][j-1] + 2 * img_garry[i+1][ j ] + 1 * img_garry[i+1][j+1];
G = sqrt(Gx*Gx+Gy*Gy);
if(G>Gmax)
sobel_Data[i*imgWidth+j]=255;
else
sobel_Data[i*imgWidth+j] = 0;
}
cvShowImage("sobel_img", sobel_img); //顯示彩色圖像灰度處理的圖像
Laplace算子
OpenCV調用:
C++: void Laplacian(InputArray src,OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType=BORDER_DEFAULT );
- 第一個參數,
InputArray
類型的image
,輸入圖像,即源圖像,填Mat
類的對象即可,且需爲單通道8位圖像。 - 第二個參數,
OutputArray
類型的edges
,輸出的邊緣圖,需要和源圖片有一樣的尺寸和通道數。 - 第三個參數,
int
類型的ddepth
,目標圖像的深度。 - 第四個參數,
int
類型的ksize
,用於計算二階導數的濾波器的孔徑尺寸,大小必須爲正奇數,且有默認值1。 - 第五個參數,
double
類型的scale
,計算拉普拉斯值的時候可選的比例因子,有默認值1
。 - 第六個參數,
double
類型的delta
,表示在結果存入目標圖(第二個參數dst
)之前可選的delta
值,有默認值0
。 - 第七個參數,
int
類型的borderType
,邊界模式,默認值爲BORDER_DEFAULT
。這個參數可以在官方文檔中borderInterpolate()
處得到更詳細的信息。
Laplacian()
函數其實主要是利用sobel
算子的運算。它通過加上sobel算子運算出的圖像x方向和y方向上的導數,來得到我們載入圖像的拉普拉斯變換結果。
自寫Sobel算子邊緣檢測:
//laplace算法
IplImage* laplace_img = NULL; //創建用於灰度圖像的結構體指針
laplace_img = cvCreateImage(cvSize(imgWidth,imgHeight), imgDepth, 1 ); //創建單通道的色彩空間用於灰度變換
uchar *laplace_Data = (uchar*) laplace_img->imageData;//聲明無符號char型指針指向結構體的變量imageData
double L =0;
for(int i = 1;i<imgHeight-2; i++)
{
for(int j = 1;j<imgWidth-2; j++)
{
L = 0 * img_garry[i-1][j-1] + 1 * img_garry[i-1][ j ] + 0 * img_garry[i-1][j+1]
+ 1 * img_garry[ i ][j-1] + -4 * img_garry[ i ][ j ] + 1 * img_garry[ i ][j+1]
+ 0 * img_garry[i+1][j-1] + 1 * img_garry[i+1][ j ] + 0 * img_garry[i+1][j+1];
if(L>255)
laplace_Data[i*imgWidth+j] = 255;
else if( 0<L & L<255)
laplace_Data[i*imgWidth+j] = L ;
else if(L<0)
laplace_Data[i*imgWidth+j] = 0 ;
}
}
cvShowImage("laplace_img", laplace_img);
Canny算子
OpenCV調用:
C++: void Canny(InputArray image,OutputArray edges, double threshold1, double threshold2, int apertureSize=3,bool L2gradient=false )
-
第一個參數,
InputArray
類型的image
,輸入圖像,即源圖像,填Mat
類的對象即可,且需爲單通道8位圖像。 -
第二個參數,
OutputArray
類型的edges
,輸出的邊緣圖,需要和源圖片有一樣的尺寸和類型。 -
第三個參數,
double
類型的threshold1
,第一個滯後性閾值。 -
第四個參數,
double
類型的threshold2
,第二個滯後性閾值。 -
第五個參數,
int
類型的apertureSize
,表示應用Sobel
算子的孔徑大小,其有默認值3
。 -
第六個參數,
bool
類型的L2gradient
,一個計算圖像梯度幅值的標識,有默認值false
。 -
需要注意的是,這個函數閾值1和閾值2兩者的小者用於邊緣連接,而大者用來控制強邊緣的初始段,推薦的高低閾值比在2:1到3:1之間。
openCV調用示例:
//Canny算法
Mat Canny_Image = imread("/Users/inbc/Desktop/OpenCV學習/opencv_test_3/666.jpg");//注意修改路徑
if (!Canny_Image.data){
cout << "falied to read" << endl;
system("pause");
//return;
}
Mat srcGray;
cvtColor(Canny_Image, srcGray, CV_BGR2GRAY);
//高斯濾波
GaussianBlur(srcGray, srcGray, Size(3, 3),
0, 0, BORDER_DEFAULT);
//Canny檢測
int edgeThresh =100;
Mat Canny_result;
Canny(Canny_Image, Canny_result, edgeThresh, edgeThresh * 3, 3); //調用Canny算子
imshow("Canny_Image", Canny_Image);
imshow("Canny_Image", Canny_result);
Hough變換檢測直線
OpenCV調用:
C++:void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0 )
- 第一個參數,
InputArray
類型的image
,輸入圖像,即源圖像,需爲8位的單通道二進制圖像,可以將任意的源圖載入進來後由函數修改成此格式後,再填在這裏。 - 第二個參數,
InputArray
類型的lines
,經過調用HoughLinesP
函數後後存儲了檢測到的線條的輸出矢量,每一條線由具有四個元素的矢量(x_1,y_1,x_2, y_2)
表示,其中,(x_1, y_1)
和(x_2, y_2)
是是每個檢測到的線段的結束點。 - 第三個參數,
double
類型的rho
, 以像素爲單位的距離精度。 另一種形容方式是直線搜索時的進步尺寸的單位半徑。 - 第四個參數,
double
類型的theta
,以弧度爲單位的角度精度。另一種形容方式是直線搜索時的進步尺寸的單位角度。 - 第五個參數,
int
類型的threshold
,累加平面的閾值參數,即識別某部分爲圖中的一條直線時它在累加平面中必須達到的值。 大於閾值threshold
的線段纔可以被檢測通過並返回到結果中。 - 第六個參數,
double
類型的minLineLength
,有默認值0
,表示最低線段的長度,比這個設定參數短的線段就不能被顯現出來。 - 第七個參數,
double
類型的maxLineGap
,有默認值0
,允許將同一行點與點之間連接起來的最大的距離。
OpenCV調用示例:
//Hough變換檢測直線
Mat Hough_Image = imread("/Users/inbc/Desktop/OpenCV學習/opencv_test_3/666.jpg", 0);//注意修改路徑
Mat CannyImg;
Canny(Hough_Image, CannyImg, 70, 200, 3);
imshow("CannyImg_2", CannyImg);
Mat DstImg;
cvtColor(Hough_Image, DstImg, CV_GRAY2BGR);
vector<Vec4i> Lines;
HoughLinesP(CannyImg, Lines, 1, CV_PI / 360, 170,30,15);
for (size_t i = 0; i < Lines.size(); i++)
{
line(DstImg, Point(Lines[i][0], Lines[i][1]), Point(Lines[i][2], Lines[i][3]), Scalar(0, 0, 255), 2, 8);
}
imshow("Hough_Image", DstImg);