1. 程式人生 > >5.4.2 邊緣檢測-sobel運算元

5.4.2 邊緣檢測-sobel運算元

Sobel運算元也是一種常用的梯度運算元。Sobel運算元計算稍微複雜,它採用3x3的模板。計算時模板在影象上移動,並在每個位置上計算對應中心畫素的梯度值。

VTK中vtkSobel2D計算影象的sobel運算元,使用程式碼如下:

/*-------------------------------------sobel----------------------------------------------------------------------------*/
#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageSobel2D.h> //
#include <vtkImageExtractComponents.h> //vtkImageExtractComponents提取各方向的梯度分量
#include <vtkImageMathematics.h> //對各個分量影象計算絕對值
#include <vtkImageData.h>
#include <vtkImageShiftScale.h> //資料範圍調整數值範圍到0-255
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>

int main()
{
	vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
	reader->SetFileName("data\\lena-gray.jpg");
	reader->Update();

	vtkSmartPointer<vtkImageSobel2D> sobelFilter =	vtkSmartPointer<vtkImageSobel2D>::New();
	sobelFilter->SetInputConnection(reader->GetOutputPort());//包含橫向和豎向邊緣

	//提取X向邊緣成分
	vtkSmartPointer<vtkImageExtractComponents> xSobel =	vtkSmartPointer<vtkImageExtractComponents>::New();
	xSobel->SetComponents(0);//提取第一成分即X向梯度
	xSobel->SetInputConnection(sobelFilter->GetOutputPort());
	xSobel->Update();

	vtkSmartPointer<vtkImageMathematics> absFilter = vtkSmartPointer<vtkImageMathematics>::New();
	//由於計算Sobel運算元的值可能存在負值,因此利用vtkImageMathematics對各個分量影象計算絕對值,再由vtkImageShiftScale將影象的數值範圍調節到0-255之間再顯示
	absFilter->SetOperationToAbsoluteValue();//將屬性設定為絕對值模式
	absFilter->SetInputConnection(xSobel->GetOutputPort());
	absFilter->Update();

	double xRange[2];
	absFilter->GetOutput()->GetScalarRange(xRange);

	vtkSmartPointer<vtkImageShiftScale> xShiftScale = vtkSmartPointer<vtkImageShiftScale>::New();
	xShiftScale->SetOutputScalarTypeToUnsignedChar();//強制型別轉換 方便顯示
	xShiftScale->SetScale(255 / xRange[1]);//設定屬性
	xShiftScale->SetInputConnection(absFilter->GetOutputPort());
	xShiftScale->Update();

	//提取Y向邊緣成分
	vtkSmartPointer<vtkImageExtractComponents> ySobel = vtkSmartPointer<vtkImageExtractComponents>::New();
	ySobel->SetComponents(1);//提取第二成分即y向梯度
	ySobel->SetInputConnection(sobelFilter->GetOutputPort());
	ySobel->Update();

	vtkSmartPointer<vtkImageMathematics> absYsobel = vtkSmartPointer<vtkImageMathematics>::New();
	absYsobel->SetOperationToAbsoluteValue();
	absYsobel->SetInputConnection(ySobel->GetOutputPort());
	absYsobel->Update();

	double yRange[2];
	absYsobel->GetOutput()->GetScalarRange(yRange);

	vtkSmartPointer<vtkImageShiftScale> yShiftScale =	vtkSmartPointer<vtkImageShiftScale>::New();
	yShiftScale->SetOutputScalarTypeToUnsignedChar();
	yShiftScale->SetScale(255 / yRange[1]);
	yShiftScale->SetInputConnection(absYsobel->GetOutputPort());
	yShiftScale->Update();
	////////////////////////////////////////////////////////////
	vtkSmartPointer<vtkImageActor> origActor =	vtkSmartPointer<vtkImageActor>::New();
	origActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> xSobelActor =	vtkSmartPointer<vtkImageActor>::New();
	xSobelActor->SetInputData(xShiftScale->GetOutput());

	vtkSmartPointer<vtkImageActor> ySobelActor =	vtkSmartPointer<vtkImageActor>::New();
	ySobelActor->SetInputData(yShiftScale->GetOutput());
	/////////////////////////////////////////////////////////////
	double origView[4] = { 0, 0, 0.33, 1 };
	double xSobelView[4] = { 0.33, 0, 0.66, 1 };
	double ySobelView[4] = { 0.66, 0, 1, 1 };
	vtkSmartPointer<vtkRenderer> origRender =	vtkSmartPointer<vtkRenderer>::New();
	origRender->SetViewport(origView);
	origRender->AddActor(origActor);
	origRender->ResetCamera();
	origRender->SetBackground(1, 1, 1);

	vtkSmartPointer<vtkRenderer> xSobelRender =	vtkSmartPointer<vtkRenderer>::New();
	xSobelRender->SetViewport(xSobelView);
	xSobelRender->AddActor(xSobelActor);
	xSobelRender->ResetCamera();
	xSobelRender->SetBackground(1, 1, 1);

	vtkSmartPointer<vtkRenderer> ySobelRender =	vtkSmartPointer<vtkRenderer>::New();
	ySobelRender->SetViewport(ySobelView);
	ySobelRender->AddActor(ySobelActor);
	ySobelRender->ResetCamera();
	ySobelRender->SetBackground(1, 1, 1);
	//////////////////////////////////////////////
	vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(origRender);
	rw->AddRenderer(xSobelRender);
	rw->AddRenderer(ySobelRender);
	rw->SetSize(960, 320);
	rw->SetWindowName("Edge by Soebl");

	vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
	rwi->SetInteractorStyle(style);
	rwi->SetRenderWindow(rw);
	rwi->Initialize();
	rwi->Start();

	return 0;
}

執行結果:

該例中計算利用Sobel運算元計算影象的梯度影象,然後提取X方向的梯度分量和Y方向的梯度分量。
由於計算Sobel運算元的值可能存在負值,因此利用vtkImageMathematics對各個分量影象計算絕對值,再由vtkImageShiftScale將影象的數值範圍調節到0-255之間再顯示。

參考資料:

1.《The Visualization Toolkit – AnObject-Oriented Approach To 3D Graphics (4th Edition)》
2. 張曉東, 羅火靈. VTK圖形影象開發進階[M]. 機械工業出版社, 2015.

所用軟體:vtk7.0+visual studio 2013


注:此文知識學習筆記,僅記錄完整程式和實現結果,具體原理參見:

https://blog.csdn.net/www_doling_net/article/details/8541534

https://blog.csdn.net/shenziheng1/article/category/6114053/4