VTK笔记-图像融合-02-vtkImageBlend类

vtkImageBlend

  VTK中的图像融合是利用图像的不透明度来合成图像,使用类vtkImageBlend实现图像的融合;vtkImageBlend使用alpha或opacity将图像融合在一起;vtkImageBlend可以接收多个图像输入,其输出为融合图像。输出图像的间距、原点、范围和组件数与第一个输入的相同。如果输入有一个alpha分量,那么这个分量会原封不动地复制到输出中。此外,如果第一个输入有一个或两个分量,即如果是L(灰度)或LA(灰度+α),则所有其他输入也必须是L或LA。
  vtkImageBlend类支持L(灰度图像)、LA(灰度+透明度)、RGB或RGBA(RGB+透明度)图像作为输入。
  vtkImageBlend类支持两种图像融合模式:标准模式(Normal)和混合模式(Compound)。

枚举
VTK_IMAGE_BLEND_MODE_NORMAL0
VTK_IMAGE_BLEND_MODE_COMPOUND1

  标准模式是默认模式,这是OpenGL和其他图形包使用的标准混合模式。输出总是具有与第一个输入相同的组件数量和范围。第一个输入的alpha值不用于混合计算,而是直接复制到输出。
  混合模式,将图像合成在一起,每个组件按alpha/opacity值之和进行缩放。使用SetCompoundThreshold方法设置并指定复合模式下的阈值。不透明度*alpha小于或等于此阈值的像素将被忽略。第一个输入的alpha值(如果存在)不会复制到输出的alpha值。输出总是具有与第一个输入相同的组件数量和范围。如果设置了CompoundAlpha,则还将使用alpha加权混合计算来计算输出的alpha值。

接口说明

数据源

void SetInputData(int num, vtkDataObject* input);
void SetInputData(vtkDataObject* input) { this->SetInputData(0, input); } 
vtkDataObject* GetInput(int num);
vtkDataObject* GetInput() { return this->GetInput(0); }

  以上接口已经废弃,使用 SetInputConnection()和vtkAlgorithm::GetInputConnection(0, num);
  SetInputConnection根据ID号来设置输入图像;
  当vtkImageBlend的inputData大于2个对象时,需要通过AddInputData来设置InputData;

透明度

void SetOpacity(int idx, double opacity);
double GetOpacity(int idx);

  SetOpacity和GetOpacity根据ID号来设置对应id号的图像的不透明度的大小或者获取不透明度的大小;

融合模式:

vtkSetClampMacro(BlendMode, int, VTK_IMAGE_BLEND_MODE_NORMAL, VTK_IMAGE_BLEND_MODE_COMPOUND);
vtkGetMacro(BlendMode, int);
void SetBlendModeToNormal() { this->SetBlendMode(VTK_IMAGE_BLEND_MODE_NORMAL); }
void SetBlendModeToCompound() { this->SetBlendMode(VTK_IMAGE_BLEND_MODE_COMPOUND); }
const char* GetBlendModeAsString(void);

阈值:

vtkSetMacro(CompoundThreshold, double);
vtkGetMacro(CompoundThreshold, double);

示例

vtkJPEGReader
vtkImageActor1
vtkRenderer1
vtkImageCanvasSource2D
vtkImageActor2
vtkRenderer1
vtkImageBlend
vtkImageActor3
vtkRenderer1
vtkRenderWindow
vtkRenderWindowInteractor
vtkInteractorStyleImage

代码

#include "vtkSmartPointer.h"
#include "vtkJPEGReader.h"
#include "vtkImageBlend.h"
#include "vtkImageCanvasSource2D.h"
#include "vtkImageActor.h"
#include "vtkImageMapper3D.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkInteractorStyleImage.h"
#include "vtkAutoInit.h" 

VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

using namespace std;
int main()
{
	vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
	reader->SetFileName("D:\\test.jpg");
	reader->Update();

	vtkSmartPointer<vtkImageCanvasSource2D> imageSource = vtkSmartPointer<vtkImageCanvasSource2D>::New();
	imageSource->SetNumberOfScalarComponents(1);
	imageSource->SetScalarTypeToUnsignedChar();
	imageSource->SetExtent(0, 512, 0, 512, 0, 0);
	imageSource->SetDrawColor(0.0);
	imageSource->FillBox(0, 512, 0, 512);
	imageSource->SetDrawColor(255.0);
	imageSource->FillBox(100, 400, 100, 400);
	imageSource->Update();

	vtkSmartPointer<vtkImageBlend> imageBlend = vtkSmartPointer<vtkImageBlend>::New();
	imageBlend->SetInputConnection(0, reader->GetOutputPort());
	imageBlend->SetInputConnection(1, imageSource->GetOutputPort());
	imageBlend->SetOpacity(0, 0.4);
	imageBlend->SetOpacity(1, 0.6);
	imageBlend->Update();

	// Create actors
	vtkSmartPointer<vtkImageActor> originalActor1 = vtkSmartPointer<vtkImageActor>::New();
	originalActor1->GetMapper()->SetInputConnection(reader->GetOutputPort());

	vtkSmartPointer<vtkImageActor> originalActor2 = vtkSmartPointer<vtkImageActor>::New();
	originalActor2->GetMapper()->SetInputConnection(imageSource->GetOutputPort());

	vtkSmartPointer<vtkImageActor> blendActor = vtkSmartPointer<vtkImageActor>::New();
	blendActor->GetMapper()->SetInputConnection(imageBlend->GetOutputPort());

	// Define viewport ranges
	// (xmin, ymin, xmax, ymax)
	double leftViewport[4] = { 0.0, 0.0, 0.33, 1.0 };
	double midViewport[4] = { 0.33, 0.0, 0.66, 1.0 };
	double rightViewport[4] = { 0.66, 0.0, 1.0, 1.0 };

	// Setup renderers
	vtkSmartPointer<vtkRenderer> originalRenderer1 = vtkSmartPointer<vtkRenderer>::New();
	originalRenderer1->SetViewport(leftViewport);
	originalRenderer1->AddActor(originalActor1);
	originalRenderer1->ResetCamera();
	originalRenderer1->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderer> originalRenderer2 = vtkSmartPointer<vtkRenderer>::New();
	originalRenderer2->SetViewport(midViewport);
	originalRenderer2->AddActor(originalActor2);
	originalRenderer2->ResetCamera();
	originalRenderer2->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderer> blendRenderer = vtkSmartPointer<vtkRenderer>::New();
	blendRenderer->SetViewport(rightViewport);
	blendRenderer->AddActor(blendActor);
	blendRenderer->ResetCamera();
	blendRenderer->SetBackground(1.0, 1.0, 1.0);

	vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(originalRenderer1);
	renderWindow->AddRenderer(originalRenderer2);
	renderWindow->AddRenderer(blendRenderer);
	renderWindow->SetSize(640, 320);
	renderWindow->Render();
	renderWindow->SetWindowName("ImageBlendExample");

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
	renderWindowInteractor->SetInteractorStyle(style);
	renderWindowInteractor->SetRenderWindow(renderWindow);
	renderWindowInteractor->Initialize();
	renderWindowInteractor->Start();
	return 0;
}

  下图为不同渲染器所在的窗口范围;一个窗口分为了三部分,前两窗口为输入图像,最后一个窗口为输出的融合图像;
在这里插入图片描述
  运行的效果图为:
在这里插入图片描述

遇到的问题

  代码中使用书上的内容:

imageBlend->SetInputConnection(0, reader->GetOutputPort());
imageBlend->SetInputConnection(1, imageSource->GetOutputPort());

  编译无错,运行时,没有展示出融合图像,VTK有错误消息窗口弹出;
在这里插入图片描述
  VTK错误:
  ERROR: In I:\v-vtk\VTK-8.2.0\Common\ExecutionModel\vtkDemandDrivenPipeline.cxx, line 809
vtkCompositeDataPipeline (005D17D0): Input for connection index 0 on input port index 1 for algorithm vtkImageBlend(00646E30) is of type vtkImageData, but a vtkImageStencilData is required.

  从网上找到资料:

// 图像融合
vtkSmartPointer<vtkImageBlend> pImageBlend = vtkSmartPointer<vtkImageBlend>::New();
// 原始写法:不报错,融合不正确
//    pImageBlend->SetInputData(pJpegReader->GetOutput());
//    pImageBlend->SetInputData(pImageCanvas->GetOutput());
// 不报错,融合不正确
//    pImageBlend->SetInputData( pJpegReader->GetOutput());
//    pImageBlend->SetInputData( pImageStencil->GetOutput());
// 不报错,融合不正确
//    pImageBlend->SetInputData(0, pJpegReader->GetOutput());
//    pImageBlend->SetInputData(1, pImageStencil->GetStencil());
// 正确
pImageBlend->AddInputData( pJpegReader->GetOutput());

  修改后使用

imageBlend->AddInputData(reader->GetOutput());
imageBlend->AddInputData(imageSource->GetOutput());

  编译报错:
  error C2664: “void vtkImageAlgorithm::AddInputData(int,vtkDataObject *)”: 无法将参数 1 从“vtkImageData *”转换为“vtkDataObject *”
  强转为(vtkDataObject*)类型后:

imageBlend->AddInputData((vtkDataObject*)reader->GetOutput());
imageBlend->AddInputData((vtkDataObject*)imageSource->GetOutput());

  编译正常,融合图像正常:
在这里插入图片描述

新的问题

  群里有朋友提问,使用一个vtkDICOMImageReader解析的dicom文件和上文的白色方块进行融合,效果还是dicom的灰度图像;
在这里插入图片描述
  原因是什么呢,我开始认为vtkImageBlend的输入都是vtkImageData应该不会区分什么文件,后来在看了vtkImageBlend的说明后,知道“vtkImageBlend类支持L(灰度图像)、LA(灰度+透明度)、RGB或RGBA(RGB+透明度)图像作为输入”,dicom文件的图像为既不是灰度图像也不是RGB彩色图像,自然就不是vtkImageBlend的输入;
  要想实现两者的融合图像,就需要把dicom转换为灰度图像在使用vtkImageBlend;亦或者是根据融合的原理更改dicom图像里的CT值;

引用

1.Hit_HSW-融合VTKImageBlend

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑山老妖的笔记本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值