16 OpenCV之Soble算子

一、卷積應用-圖像邊緣提取

  • 圖像的高頻分量一般出現在像素值顯著改變的地方,而高頻分量的出現就容易勾畫出圖像的輪廓。在高等數學中我們知道函數變化劇烈其所對應的導數值越大(極大值),所以表示圖像像素值改變最大的一個方法就是求出圖像的導數。其梯度值劇烈的改變預示着圖像中內容發生顯著變化。
  • 假設我們有一張一維圖像,圖中灰度值的“躍升”表示邊緣的存在,通過對函數進行一階微分我們可以更加清晰的看到邊緣“躍升”的存在,即在其一階微分中最大值代表其所對應的像素值變化劇烈。我們可以推測對於圖像邊緣的檢測可以通過定位梯度值大於鄰域的像素的方法找到(或者推廣到大於一個閾值即可認爲是圖像邊緣)
    在這裏插入圖片描述

二、Soble算子

Sobel算子是一個離散微分算子(discrete differentiation operator),它用來計算圖像灰度函數的近似梯度並結合了高斯平滑和微分求導,又被稱爲一階微分算子、求導算子。

  • 1、在兩個方向求導
    • 水平變化:將I與一個奇數大小的內核Gx進行卷積,比如當內核大小爲3時,Gx計算結果爲
      在這裏插入圖片描述
    • 垂直變化:將I與一個奇數大小的內核Gy進行卷積,比如當內核大小爲3時,Gy的計算結果爲:
      在這裏插入圖片描述
  • 2、在圖像的每一點結合以上兩個結果求出近似梯度:
    在這裏插入圖片描述
    有時也用如下更簡單的代替:
    在這裏插入圖片描述
  • 注:當內核大小爲3時,Sobel內核可能產生比較明顯的誤差,畢竟Sobel算子只是求取了導數的近似值,爲了解決這一問題,opencv提供了Scharr函數,但該函數僅作用於大小爲3的內核,該函數的運算與Sobel函數一樣快,但結果更加精確,其內核如下:
    在這裏插入圖片描述

三、相關API

  • Soble
void cv::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: 輸入圖像
OutputArray dst: 輸出圖像
int ddepth: 輸出圖像深度,與輸入圖像深度對應關係如下表所示:
在這裏插入圖片描述
int dx: x方向上的差分階數
int dy: y方向上的差分階數
int ksize = 3: Sobel函數核尺寸,只能是1、3、5、7中的一個,默認值是3
double scale = 1: 計算導數值可選的縮放銀子,默認值是1表示沒有縮放
int borderType = BORDER_DEFAULT:邊界模式

  • scharr
cv::Scharr (
InputArray Src // 輸入圖像
OutputArray dst// 輸出圖像,大小與輸入圖像一致
int depth // 輸出圖像深度.
Int dx. // X方向,幾階導數
int dy // Y方向,幾階導數.
double scale = 1
double delta = 0
int borderType = BORDER_DEFAULT
)

四、處理流程

  • 高斯模糊 – 去噪聲GaussianBlur()
  • 轉換爲灰度圖像cvtColor()
  • Sobel /Scharr – 一階導數計算Sobel ()、Scharr ()
  • 取絕對值convertScaleAbs()
  • 圖像按權值合成addWeighted()
  • 顯示結果

五、示例

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat src, dst;
	src = imread("images/02.png");
	if (!src.data) {
		cout << "could not load image1..." << endl;
		return -1;
	}
	namedWindow("input_image", CV_WINDOW_AUTOSIZE);
	imshow("input_image", src);


	Mat gray_src;
	GaussianBlur(src, dst, Size(3, 3), 0, 0);
	cvtColor(dst, gray_src, CV_BGR2GRAY);
	imshow("gray image", gray_src);

	Mat xgrad, ygrad;
	Sobel(gray_src, xgrad, CV_16S, 1, 0, 3);
	Sobel(gray_src, ygrad, CV_16S, 0, 1, 3);
	convertScaleAbs(xgrad, xgrad);
	convertScaleAbs(ygrad, ygrad);
	imshow("xgrad", xgrad);
	imshow("ygrad", ygrad);

	Mat xygrad = Mat(xgrad.size(),xgrad.type());
	//printf("type:%d\n", xgrad.type());
	int width = xgrad.cols;
	int height = ygrad.rows;
	for (int  row = 0; row < height; row++)  // 比使用addWeighted的效果要好
	{
		for (int col = 0; col < width; col++)
		{
			int xg = xgrad.at<uchar>(row, col);
			int yg = ygrad.at<uchar>(row, col);
			int xy = xg + yg;
			xygrad.at<uchar>(row, col) = saturate_cast<uchar>(xy);
		}
	}
	imshow("xygrad", xygrad); 

	Mat xygrad2;
	addWeighted(xgrad, 0.5, ygrad, 0.5,0, xygrad2);
	imshow("xygrad2", xygrad2);

	waitKey();
	return 0;
}

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章