vtk瞎操作

因为项目需求,想要对一个模型文件进行渲染,从而获取更多的模型图像数据。
这个因为本来自己理解也不多,工具也不太熟悉。正好在计算机图形学课程上看到vtk的工具库,因此,想利用vtk实现对于模型文件的灰度图像(彩色图像等数据需要贴纹理操作,因此也没继续搞)和模型的深度图像(图像中各个像素点处距离相机平面的距离)

因为本来对于vtk都不太熟悉,所以胡乱摸索了好几天。推荐vtk学习基本教程还是从官网例子上来看,一番摸索下来,感觉对于未知问题描述能力以及搜索能力,都是非常重要,而且本人需要提高的。

问题还存在一些,包括

  1. 没有实现纹理的渲染
  2. 深度图像背景距离应该为0或者为无穷,但是实际上是一个farClipping Dsitance。如何在vtk中去除也是一个问题。
  3. 渲染图象只有在renderWindow中交互之后才有物体。 目前还没有找到在不显示renderWindow,并且不进行交互作业之后,生成真实的渲染图象。理想上是要找一个 renderWindow->Update之类的东西,可是因为理解不够,还没有找到。
  4. 感觉这个渲染方法有些繁琐,可能还存在更好的渲染图象的软件或者工具包。如果有同学知道的话还请推荐一个

代码如下:

int main(int argc, char** argv){
//  设定相机的参数
	float fx = 1423.81;
	float fy = 1423.0;
	int imgU = 1280;
	int imgV = 960;
	int magnification = 1;

// 读取模型文件
	vtkSmartPointer<vtkPolyData> polyData =
		ReadPolyData(argc > 1 ? argv[1] : "model.ply");
	vtkSmartPointer<vtkPolyDataMapper> mapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	mapper->SetInputData(polyData);

	vtkSmartPointer<vtkActor> actor =
		vtkSmartPointer<vtkActor>::New();
	actor->SetMapper(mapper);
	actor->SetPosition(-actor->GetCenter()[0], -actor->GetCenter()[1], -actor->GetCenter()[2]);

	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();

	renderWindow->AddRenderer(renderer);
	renderer->AddActor(actor);

	/***************** Pc = Tm2cPm    ************************/
	/***************** Pc' = Tm2c(transT.inverse Pm)   ************************/

	//Eigen::AngleAxisf z = Eigen::AngleAxisf(40, (0, 0, 1));
	Eigen::Matrix4f transT = Eigen::Matrix4f::Identity();
	Eigen::AngleAxisf V1(0 / 2, Eigen::Vector3f(0, 0, 1));//以(0,0,1)为旋转轴,旋转45度
	transT.block(0, 0, 3, 3) = V1.toRotationMatrix();
	std::cout << "transT is \n" << transT.block(0, 0, 3, 3) << std::endl;
	Eigen::Vector3f moveT = Eigen::Vector3f::Zero();
	//moveT(1) = 100.0;
	//moveT(0) = 0.0;
	transT.block(0, 3, 3, 1) = moveT;

	Eigen::Matrix4f Tm2c = Eigen::Matrix4f::Identity();
	{
		//Tm2c(1, 1) = -1;
		Tm2c(2, 2) = -1;
		Tm2c(2, 3) = 800.0;
		//zDir(2) = 1.0f;
	}

	transT = Tm2c*transT;
	Eigen::Matrix4f transTInverse = Eigen::Matrix4f::Identity();
	transTInverse.block(0, 0, 3, 3) = transT.block(0, 0, 3, 3).transpose();
	transTInverse.block(0, 3, 3, 1) = transTInverse.block(0, 0, 3, 3)*transT.block(0, 3, 3, 1);

	Eigen::Vector3f cameraPosition = transT.block(0, 3, 3, 1);
	Eigen::Vector3f focalDir = cameraPosition + transT.block(0, 2, 3, 1);

//设置相机参数。模型文件处于原点,旋转相机完成渲染操作
	renderer->GetActiveCamera()->SetParallelProjection(0);
	renderer->GetActiveCamera()->SetFocalPoint(focalDir(0), focalDir(1), focalDir(2));
	renderer->GetActiveCamera()->SetViewUp(-transT(0, 1), -transT(1, 1), -transT(2, 1));
	renderer->GetActiveCamera()->SetPosition(cameraPosition(0), cameraPosition(1), cameraPosition(2));
	renderer->GetActiveCamera()->SetViewAngle(2 * atan(float(imgV) / fy / 2) / 3.14*180.0);

	renderWindow->SetSize(imgU, imgV);
	renderWindow->Render();

//存在一个问题,必须实现交互器,否则最终深度图像为空。就很奇怪
	////std::cout << "Interact with image to get desired view and then press 'e'"
	////	<< std::endl;
	//vtkSmartPointer<vtkRenderWindowInteractor> interactor =
	//	vtkSmartPointer<vtkRenderWindowInteractor>::New();
	//renderWindow->SetInteractor(interactor);
	//interactor->Start();

	vtkSmartPointer<vtkRenderLargeImage> renderLarge =
		vtkSmartPointer<vtkRenderLargeImage>::New();
	renderLarge->SetInput(renderer);
	renderLarge->SetMagnification(magnification);

	std::cout << "Saving image in " << (argc > 2 ? argv[2] : "color.png") << std::endl;
	vtkSmartPointer<vtkPNGWriter> writer =
		vtkSmartPointer<vtkPNGWriter>::New();
	writer->SetFileName((argc > 2 ? argv[2] : "color.png"));
	writer->SetInputConnection(renderLarge->GetOutputPort());
	writer->Write();

	vtkSmartPointer<vtkWindowToImageFilter> filter =
		vtkSmartPointer<vtkWindowToImageFilter>::New();
	filter->SetInput(renderWindow);
	filter->SetInputBufferTypeToZBuffer(); // Extract z buffer value
	filter->Update();

	vtkSmartPointer<vtkImageShiftScale> scaleDetph =
		vtkSmartPointer<vtkImageShiftScale>::New();
	scaleDetph->SetOutputScalarTypeToUnsignedShort();
	scaleDetph->SetInputConnection(filter->GetOutputPort());

	double nearClipDis = 10.0;
	double farClipDis = 100.0;
	// zBuffer数据重新计算为真实的distance
	// scaleDepth的操作就很奇怪。 SetScale是设置值扩大系数 a
	// SetShift是设置偏移量 dis。 最终的结果为 a*(Value + dis)
	// 多次设置只以最后的为准
	renderer->GetActiveCamera()->GetClippingRange(nearClipDis, farClipDis);
	double scaleValue = 1.0  / (farClipDis - nearClipDis);
	scaleDetph->SetScale(1.0 / scaleValue);
	scaleDetph->SetShift(nearClipDis*scaleValue);

	// Write depth map as a .png image
	vtkSmartPointer<vtkPNGWriter> imageWriter = vtkSmartPointer<vtkPNGWriter>::New();
	imageWriter->SetFileName((argc > 3 ? argv[3] : "depth.png"));
	imageWriter->SetInputConnection(scaleDetph->GetOutputPort());
	imageWriter->Write();

	getchar();
	return EXIT_SUCCESS;
}

头文件很多,如下,其中模型文件的读取,还是从官网上翻下来的

#include <Eigen\dense>
#define _USE_MATH_DEFINES
#include <math.h>

#include <vtkSmartPointer.h>

#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkImageViewer.h>
#include <vtkPNGWriter.h>
#include <vtkPolyDataMapper.h>
#include <vtkSmartVolumeMapper.h>
#include <vtkVolumeProperty.h>
#include <vtkRenderLargeImage.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkWindowToImageFilter.h>
#include <vtkImageShiftScale.h>

#include <vtkBYUReader.h>
#include <vtkOBJReader.h>
#include <vtkPLYReader.h>
#include <vtkPolyDataReader.h>
#include <vtkSTLReader.h>
#include <vtkSphereSource.h>
#include <vtksys/SystemTools.hxx>
;