vtkSeedWidget¶
1 vtkSeedWidget介绍¶
vtkSeedWidget 用于在场景中放置多个种子点。种子点可用于诸如连通性,分段和区域生长之类的操作。
vtkSeedWidget默认交互操作:
1. 鼠标点击widget上空白位置放置种子点
2. 鼠标移入种子点(箭头变为小手),按下delete删除种子点
3. 鼠标移入种子点(箭头变为小手),按住鼠标左键拖动可以移动种子点
有放置对应就有拾取,如何自定义拾取每个点放在以后拾取的交互单独讲,这里只介绍vtk默认的拾取功能。
2 vtkSeedWidget 官方案例¶
vtk官方提供了三个例子,用来演示如何使用vtkSeedWidget在三维/平面场景下放置种子点。且回调种子点增加、移动、删除信息。
空间场景中放置种子点。
图片场景中放置种子点,而且增加回调信息(种子点数量、当前选择、移动坐标)。
空间场景中放置种子点,而且增加回调信息(种子点数量、当前选择、移动坐标)。
3 vtkSeedWidget常用函数¶
void SetInteractor( vtkRenderWindowInteractor * ) override;
// 设置交互器,如果不自定义使用默认的那么操作就是第一节介绍的vtkSeedWidget默认交互操作
void SetRepresentation( vtkSeedRepresentation *rep )
// 设置种子点,这个vtkSeedRepresentation放置和操作定义种子集合的点。
// 这样有个好处就是,添加的种子点数据和界面是分开的(交互/实体 分开),可以多个界面展示同一组点
void On() {this->SetEnabled(1);}
void Off() {this->SetEnabled(0);}
// 这一组设置vtkSeedWidget是否开启交互功能 (观察/命令 模式切换)
//这两组对应使用实现vtkSeedWidget的开启关闭
virtual void CompleteInteraction();
// 设置只能移动删除种子点
virtual void RestartInteraction();
// 复位交互,可以增加、删除、移动种子点
// 这两组对应使用实现vtkSeedWidget可以添加几个点
void DeleteSeed(int n);
// vtkSeedWidget交互/实体 分开,所以你想全部清空时候,只清空种子点模型是不行的
int InvokeEvent(unsigned long event, void *callData);
int InvokeEvent(const char *event, void *callData);
// 这个就理解成Qt的信号吧,emit信号用的
4 vtkSeedWidget使用技巧¶
4.1 开启/关闭 放置种子点交互¶
Off之后进入观察模式,只能看无法修改种子点。On之后开启种子点的交互。
void ImageSeeder::WidgetsOn() {
if (this->seed_widget_ != nullptr) {
this->seed_widget_->On();
}
}
void ImageSeeder::WidgetsOff() {
if (this->seed_widget_ != nullptr) {
this->seed_widget_->Off();
}
}
4.2 绑定种子点增加/删除信号到Qt¶
交互/实体 分开的,其实只要清楚数量的改变就可以了,如果需要点坐标信息,去vtkSeedRepresentation里找。
if (this->connections_ == nullptr) {
this->connections_ = vtkSmartPointer<vtkEventQtSlotConnect>::New();
this->connections_->Connect(
this->seed_widget_, vtkCommand::PlacePointEvent,
this, SLOT(SlotAddSeed(vtkObject *, unsigned long,
void *, void *)));
this->connections_->Connect(
this->seed_widget_, vtkCommand::DeletePointEvent,
this, SLOT(SlotAddSeed(vtkObject *, unsigned long,
void *, void *)));
}
void ImageSeeder::SlotAddSeed(vtkObject *caller, unsigned long vtk_event,
void *client_data, void *call_data) {
Q_UNUSED(client_data)
Q_UNUSED(vtk_event)
qint32 n = *static_cast<int *>(call_data);
vtkSmartPointer<vtkSeedWidget> widget = dynamic_cast<vtkSeedWidget *>(caller);
if (n >= 0 && widget) {
qint32 num_seeds = widget->GetSeedRepresentation()->GetNumberOfSeeds();
qDebug() << num_seeds;
}
}
void ImageSeeder::SlotDeleteSeed(vtkObject *caller, unsigned long vtk_event,
void *client_data, void *call_data) {
Q_UNUSED(client_data)
Q_UNUSED(vtk_event)
qint32 n = *static_cast<int *>(call_data);
vtkSmartPointer<vtkSeedWidget> widget = dynamic_cast<vtkSeedWidget *>(caller);
if (n >= 0 && widget) {
qint32 num_seeds = widget->GetSeedRepresentation()->GetNumberOfSeeds() - 1;
qDebug() << num_seeds;
}
}
4.3 创建种子点增加/删除/移动 回调事件¶
如果用Qt的话,这个回调就不需要使用了。
vtkSmartPointer<vtkSeedCallback> seedCallback =
vtkSmartPointer<vtkSeedCallback>::New();
seedCallback->SetRepresentation(rep);
seedWidget->AddObserver(vtkCommand::PlacePointEvent,seedCallback);
seedWidget->AddObserver(vtkCommand::InteractionEvent,seedCallback);
class vtkSeedCallback : public vtkCommand {
public:
static vtkSeedCallback *New() {
return new vtkSeedCallback;
}
vtkSeedCallback() {}
virtual void Execute(vtkObject *, unsigned long event, void *calldata) {
if(event == vtkCommand::PlacePointEvent) {
std::cout << "Point placed, total of: "
<< this->SeedRepresentation->GetNumberOfSeeds() << std::endl;
}
if(event == vtkCommand::InteractionEvent) {
if(calldata) {
std::cout << "Interacting with seed : "
<< *(static_cast< int * >(calldata)) << std::endl;
}
}
std::cout << "List of seeds (Display coordinates):" << std::endl;
for(vtkIdType i = 0; i < this->SeedRepresentation->GetNumberOfSeeds(); i++) {
double pos[3];
this->SeedRepresentation->GetSeedDisplayPosition(i, pos);
std::cout << "(" << pos[0] << " "
<< pos[1] << " " << pos[2] << ")" << std::endl;
}
}
void SetRepresentation(vtkSmartPointer<vtkSeedRepresentation> rep) {
this->SeedRepresentation = rep;
}
private:
vtkSmartPointer<vtkSeedRepresentation> SeedRepresentation;
};
4.4 设置种子点数量,达到后只能移动无法新建¶
4.2的槽函数修改下,达到一定数量后禁止添加。
void ImageSeeder::SlotAddSeed(vtkObject *caller, unsigned long vtk_event,
void *client_data, void *call_data) {
Q_UNUSED(client_data)
Q_UNUSED(vtk_event)
qint32 n = *static_cast<int *>(call_data);
if(n == max_points_sum) {
this->WidgetDisable();
}
vtkSmartPointer<vtkSeedWidget> widget = dynamic_cast<vtkSeedWidget *>(caller);
if (n >= 0 && widget) {
qint32 num_seeds = widget->GetSeedRepresentation()->GetNumberOfSeeds();
emit SignalSeedChanged(num_seeds);
}
}
void ImageSeeder::SlotDeleteSeed(vtkObject *caller, unsigned long vtk_event,
void *client_data, void *call_data) {
Q_UNUSED(client_data)
Q_UNUSED(vtk_event)
qint32 n = *static_cast<int *>(call_data);
if(n < max_points_sum) {
this->seed_widget_->RestartInteraction();
}
vtkSmartPointer<vtkSeedWidget> widget = dynamic_cast<vtkSeedWidget *>(caller);
if (n >= 0 && widget) {
qint32 num_seeds = widget->GetSeedRepresentation()->GetNumberOfSeeds() - 1;
emit SignalSeedChanged(num_seeds);
}
}
4.5 初始化种子点数量和位置 QList>¶
交互/实体 分开的,只要在vtkSeedRepresentation添加点和坐标,vtkSeedWidget会自动更新的。这里的InvokeEvent()作用是发送点增加的信号,处理别的事情。
void ImageSeeder::SetSeedList(const QList<QList<double>> seed_list) {
this->InitialSeeds();
if (this->representation_ != nullptr) {
for (qint32 i = 0; i < seed_list.size(); ++i) {
double p[3] = {seed_list[i][0], seed_list[i][1], seed_list[i][2]};
qint32 num = this->representation_->CreateHandle(p);
vtkSmartPointer<vtkHandleWidget> handle =
this->seed_widget_->CreateNewHandle();
handle->SetEnabled(true);
this->representation_->SetSeedWorldPosition(static_cast<quint32>(num), p);
this->seed_widget_->InvokeEvent(vtkCommand::PlacePointEvent, &(num));
}
}
}
4.6 导入导出种子点 QList>¶
交互/实体 分开的,只要导入导出vtkSeedRepresentation就可以了,导入就是4.5的初始化。
QList<QList<double>> ImageSeeder::GetSeedList() const {
QList<QList<double>> list;
if (this->representation_ != nullptr) {
qint32 num_seeds =
this->representation_->GetNumberOfSeeds();
for (qint32 i = 0; i < num_seeds; ++i) {
double pos[3];
this->representation_->GetSeedWorldPosition(static_cast<quint32>(i), pos);
list.append({pos[0], pos[1], pos[2]});
}
}
return list;
}