VTK可以结合QT直接渲染,但这样会需要使用QOpenglWidget,这样会和VTK深度绑定,以后更换渲染引擎的工作量比较大,如果想在普通的QWidget启用VTK渲染,VTK作为后台渲染引擎,与界面分离,后续更换其他引擎或者自己实现引擎工作量比较小,这种技术也可以实现前后端,服务端渲染
vtk 离屏渲染的代码片段
初始化 initPipleline()
renderWindow =vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetUseOffScreenBuffers(true);
//renderWindow->SetDoubleBuffer(false);
vtkNew<vtkRenderWindowInteractor> interactor;
renderWindow->SetInteractor(interactor);
windowToImageFilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
windowToImageFilter->SetInput(renderWindow);
windowToImageFilter->SetInputBufferTypeToRGBA();
vtkNew<vtkRenderer> renderer;
renderWindow->AddRenderer(renderer);
vtkNew<vtkInteractorStyleSwitch> style;
style->SetCurrentStyleToTrackballCamera();
renderWindow->GetInteractor()->SetInteractorStyle(style);
renderWindow->SetSize(512, 512);
renderWindow->BordersOff();
renderWindow->ShowWindowOff();
volume=vtkSmartPointer<vtkVolume>::New();
vtkNew<vtkVolumeProperty> volumeProperty;
volume->SetProperty(volumeProperty);
vtkNew<vtkGPUVolumeRayCastMapper> volumeMapper;
volume->SetMapper(volumeMapper);
绘制
drawImage(QPainter &painter)
{
// if(!bInit)
// return ;
if(
)
{
windowToImageFilter->Update();
outImage=windowToImageFilter->GetOutput();
outImage->GetOrigin(outputImageOrigin);
outImage->GetDimensions(outputDimensions);
if(outputDimensions[0]>0)
{
image=QImage(outputDimensions[0], outputDimensions[1],QImage::Format_RGB32);
uchar* pdata=(uchar*)outImage->GetScalarPointer();
for(auto i=0;i<image.height();i++)
{
uchar* pSrcLine=pdata+i*image.width()*4;
uchar* pline=image.scanLine(i);
for(auto j=0;j<image.width();j++)
{
pline[j*4]=pSrcLine[j*4+2];
pline[j*4+1]=pSrcLine[j*4+1];
pline[j*4+2]=pSrcLine[j*4];
}
}
//image=QImage((uchar*)outImage->GetScalarPointer(), outputDimensions[0], outputDimensions[1],QImage::Format_RGB32);
}
painter.drawImage(image.rect(),image,image.rect());
}
}
在场景上添加需要绘制的多边形
addPolyData(std::string name, vtkPolyData *polydata)
{
if(!actorMap.count(name))
{
vtkSmartPointer<vtkActor> pactor=vtkSmartPointer<vtkActor>::New();
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputData(polydata);
pactor->SetMapper(mapper);
vtkNew<vtkProperty> property;
property->SetColor(1.0,0,0);
property->SetAmbientColor(1.0,0,0);
property->SetDiffuseColor(1.0,0,0);
property->SetOpacity(0.7);
pactor->SetProperty(property);
getRenderer()->AddActor(pactor);
int num=256;
vtkNew<vtkLookupTable> lut;
lut->SetNumberOfColors(num);
lut->SetTableRange(0, num-1);
lut->SetScaleToLinear();
lut->Build();
lut->SetTableValue(0, 0, 0, 0, 1);
vtkNew<vtkNamedColors> nameColors;
std::map<std::string,vtkColor4ub> colors;
colors["pelvis"]=nameColors->GetColor4ub("forest_green");
colors["leftfemur"]=nameColors->GetColor4ub("violet_dark");
colors["rightfemur"]=nameColors->GetColor4ub("violet_red");
vtkColor4ub color=colors[name];
for (int i = 1; i < num; ++i)
{
lut->SetTableValue(i, color.GetRed(),color.GetGreen(), color.GetBlue(), 1.0);
// int k=nameColors->GetNumberOfColors();
// double* color=nameColors->GetColor3d("")
// lut->SetTableValue(i,nam)
// auto r = randomSequence->GetRangeValue(0.4, 1);
// randomSequence->Next();
// auto g = randomSequence->GetRangeValue(0.4, 1);
// randomSequence->Next();
// auto b = randomSequence->GetRangeValue(0.4, 1);
// randomSequence->Next();
// lut->SetTableValue(i, r, g, b, 1.0);
}
mapper->SetLookupTable(lut);
actorMap[name]=pactor;
}else
{
auto pactor=actorMap[name];
pactor->GetMapper()->SetInputDataObject(polydata);
}
renderWindow->Render();
}
在屏幕上添加一个点
addPointWidget(std::string name, std::vector<double> pos)
{
if(!widgetMap.count(name))
{
vtkSmartPointer<vtkSphereWidget> pw=vtkSmartPointer<vtkSphereWidget>::New();
pw->SetCenter(pos.data());
pw->SetRadius(5);
pw->SetScale(false);
pw->SetTranslation(false);
pw->SetRepresentationToSurface();
pw->GetSphereProperty()->SetColor(
colors->GetColor3d("BurlyWood").GetData());
pw->SetInteractor(renderWindow->GetInteractor());
vtkNew<SphereCallback> sphereCallback;
sphereCallback->view=this;
pw->AddObserver(vtkCommand::StartInteractionEvent, sphereCallback);
pw->AddObserver(vtkCommand::InteractionEvent, sphereCallback);
pw->On();
widgetMap[name]=pw;
}else
{
vtkSphereWidget* pw=dynamic_cast<vtkSphereWidget*>(widgetMap[name].GetPointer());
if(pw)
{
pw->SetCenter(pos.data());
}else
{
}
}
renderWindow->Render();
}
移动点坐标
class SphereCallback : public vtkCallbackCommand
{
public:
static SphereCallback* New()
{
return new SphereCallback;
}
SphereCallback()
{
}
virtual void Execute(vtkObject* caller, unsigned long, void*)
{
vtkSphereWidget* sphereWidget = reinterpret_cast<vtkSphereWidget*>(caller);
double center[3];
sphereWidget->GetCenter(center);
std::cout << "Center: " << center[0] << " " << center[1] << " " << center[2]
<< std::endl;
view->setCrossPosition(center);
}
YVolumeView* view=nullptr;
};
绘制QWidget
void YVolumeWidget::mousePressEvent(QMouseEvent *event)
{
auto interactor=view->renderWindow->GetInteractor();
interactor->SetEventInformation(event->pos().x(),event->pos().y());
mouseButton=event->button();
switch (event->button()) {
case Qt::LeftButton:
interactor->LeftButtonPressEvent();
break;
case Qt::MiddleButton:
interactor->MiddleButtonPressEvent();
break;
case Qt::RightButton:
interactor->RightButtonPressEvent();
break;
default:
break;
}
}
void YVolumeWidget::mouseReleaseEvent(QMouseEvent *event)
{
auto interactor=view->renderWindow->GetInteractor();
interactor->SetEventInformation(event->pos().x(),event->pos().y());
switch (mouseButton) {
case Qt::LeftButton:
interactor->LeftButtonReleaseEvent();
break;
case Qt::MiddleButton:
interactor->MiddleButtonReleaseEvent();
break;
case Qt::RightButton:
interactor->RightButtonReleaseEvent();
break;
default:
break;
}
mouseButton=Qt::NoButton;
update();
}
void YVolumeWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
}
void YVolumeWidget::mouseMoveEvent(QMouseEvent *event)
{
if(mouseButton!=Qt::NoButton)
{
auto interactor=view->renderWindow->GetInteractor();
interactor->SetEventInformation(event->pos().x(),event->pos().y());
interactor->MouseMoveEvent();
update();
}
}
void YVolumeWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.fillRect(rect(),QBrush(Qt::black));
if(view->windowToImageFilter)
{
view->windowToImageFilter->Modified();
view->drawImage(painter);
QTransform vt;
vt.translate(width()-50,height()-50);
orientationMarker.setViewTransform(vt);
auto camera=view->getRenderer()->GetActiveCamera();
double vx[3];
double* vz =camera->GetDirectionOfProjection();
double* vy =camera->GetViewUp();
vtkMath::Cross(vy,vz,vx);
orientationMarker.project(vx,vy,vz);
orientationMarker.draw(painter);
}
}
void YVolumeWidget::resizeEvent(QResizeEvent *event)
{
double r=1;//this->screen()->devicePixelRatio();
view->setdevicePixelRatio(r);
view->resize(event->size());
if(view->renderWindow)
{
view->windowToImageFilter->Modified();
}
}