5.4.2 邊緣檢測-sobel運算元
阿新 • • 發佈:2018-11-24
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