在Opencv中有個Viz模塊,可以顯示三維物體,還可以實現三維動畫,本來是很好的東東,但是里面的函數、類的說明太過簡單,始終不得要領。不過其中一個擴展功能非常好,就是你可以在vtk中設計自己的模型類,在Opencv中的Viz3d窗口中顯示。
在這里我用vtk中的vtkSurfaceReconstructionFilter類,這是一個對空間點擬合曲面的函數,重新封裝了該函數,創建了自己的類:MySurfaceReconstruction,該類可以直接在Viz中的Viz3d窗口中顯示。
本程序中所需要的頭文件如下:
#ifndef INITIAL_OPENGL #define INITIAL_OPENGL #include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL) VTK_MODULE_INIT(vtkInteractionStyle) #endif #include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/viz/vizcore.hpp> #include <opencv2/viz/viz3d.hpp> #include <opencv2/viz/widget_accessor.hpp> using namespace cv; using namespace std; #include "vtkPolyDataMapper.h" #include "vtkActor.h" #include "vtkSmartPointer.h" #include "vtkProperty.h" #include "vtkPoints.h" #include "vtkCellArray.h" #include "vtkSurfaceReconstructionFilter.h" #include "vtkContourFilter.h"
下面是該類的代碼:
class MySurfaceReconstruction:public viz::Widget3D { public: MySurfaceReconstruction(const Mat&src, const viz::Color color = viz::Color::white()); }; MySurfaceReconstruction::MySurfaceReconstruction(const Mat &src, const viz::Color color) { vtkSmartPointer<vtkPoints>m_Points=vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray>vertices=vtkSmartPointer<vtkCellArray>::New(); int numOfpixs=0; for(int i=0;i<src.rows;i++) { for(int j=0;j<src.cols;j++) { double x=j,y=i; double z=src.at<double>(i,j); m_Points->InsertPoint(numOfpixs,x,y,z); //_加入點信息 vertices->InsertNextCell(numOfpixs); //_加入細胞頂點信息----用於渲染點集 vertices->InsertCellPoint(numOfpixs); numOfpixs ++; } } vtkSmartPointer<vtkPolyData>points=vtkSmartPointer<vtkPolyData>::New(); points->SetPoints(m_Points); vtkSmartPointer<vtkSurfaceReconstructionFilter>surf=vtkSmartPointer<vtkSurfaceReconstructionFilter>::New(); surf->SetInputData(points); vtkSmartPointer<vtkContourFilter>contour=vtkSmartPointer<vtkContourFilter>::New(); contour->SetInputConnection(surf->GetOutputPort()); contour->SetValue(0,0.0); vtkSmartPointer<vtkPolyDataMapper>pointMapper=vtkSmartPointer<vtkPolyDataMapper>::New(); pointMapper->SetInputConnection(contour->GetOutputPort()); vtkSmartPointer<vtkActor>actor=vtkSmartPointer<vtkActor>::New(); actor->SetMapper(pointMapper); // Store this actor in the widget in order that visualizer can access it viz::WidgetAccessor::setProp(*this, actor); // Set the color of the widget. This has to be called after WidgetAccessor. setColor(color); }
為了方便測試,自定義了一個高斯分布函數:
//*9. 獲取二維高斯卷積核 Mat Gaussian_kernel(int kernel_size, double sigma) { int c = (kernel_size) / 2; Mat kernel(kernel_size, kernel_size, CV_64FC1); double s = 2 * sigma*sigma; for (int i = 0; i < kernel_size; i++) { for (int j = 0; j < kernel_size; j++) { double x = j - c; double y=i - c; kernel.ptr<double>(i)[j] = exp(-(x*x+y*y)/s) ; } } Scalar sumOfKernel= cv::sum(kernel);//求kernel的所有像素值之和 kernel /=sumOfKernel[0];//歸一化,避免卷積過程中增大總能量 return kernel; }
下面是測試程序,通過上面的高斯函數創建一個高斯分布二維矩陣mat,作為MySurfaceReconstruction類的初始輸入,MySurfaceReconstruction可以將mat轉化成Widget3d類物體,並通過Viz3d顯示。
int main() { /// Create a window viz::Viz3d myWindow("Creating Widgets"); /// Create a triangle widget cv::Mat mat=Gaussian_kernel(15,1); mat *=10; MySurfaceReconstruction tw(mat, viz::Color::red()); /// Show widget in the visualizer window myWindow.showWidget("my surface", tw); /// Start event loop myWindow.spin(); return 0; }
下面是運行結果: