1、数学运算
vtkImageMathematics提供了基本的一元和二元数学操作。根据不同的操作,需要一个或者两个输入图像。二元数字操作要求两个输入图像具有相同的像素数据类型,颜色分量。当两个图像大小不同时,输出图像的范围为两个输入图像范围的并集,并且原点和像素间隔与第一个输入图像保持一致。
#include <vtkMath.h>
#include <vtkSmartPointer.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkImageMathematics.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
int main(int, char *[])
{
vtkSmartPointer<vtkImageCanvasSource2D> imageSource = vtkSmartPointer<vtkImageCanvasSource2D>::New();//创建的画布图像
imageSource->SetNumberOfScalarComponents(3);
imageSource->SetScalarTypeToUnsignedChar();
imageSource->SetExtent(0, 4, 0, 4, 0, 0);
imageSource->SetDrawColor(100.0, 0, 0);
imageSource->FillBox(0, 4, 0, 4);
imageSource->Update();
vtkSmartPointer<vtkImageMathematics> imageMath = vtkSmartPointer<vtkImageMathematics>::New();
imageMath->SetOperationToMultiplyByK();//将图像中所有像素值乘以常数K
imageMath->SetConstantK(2.0);
imageMath->SetInputConnection(imageSource->GetOutputPort());
imageMath->Update();
vtkSmartPointer<vtkImageActor> originalActor = vtkSmartPointer<vtkImageActor>::New();
originalActor->SetInputData(imageSource->GetOutput());
vtkSmartPointer<vtkImageActor> mathActor = vtkSmartPointer<vtkImageActor>::New();
mathActor->SetInputData(imageMath->GetOutput());
double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkRenderer> originalRenderer = vtkSmartPointer<vtkRenderer>::New();
originalRenderer->SetViewport(leftViewport);
originalRenderer->AddActor(originalActor);
originalRenderer->ResetCamera();
originalRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> gradientMagnitudeRenderer = vtkSmartPointer<vtkRenderer>::New();
gradientMagnitudeRenderer->SetViewport(rightViewport);
gradientMagnitudeRenderer->AddActor(mathActor);
gradientMagnitudeRenderer->ResetCamera();
gradientMagnitudeRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(originalRenderer);
renderWindow->AddRenderer(gradientMagnitudeRenderer);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindow->SetWindowName("ImageMathematicsExample");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
renderWindowInteractor->SetInteractorStyle(style);
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
运行结果:
上例中生成了一副图像,图像中绘制了一个暗红色矩形;然后定义vtkImageMathematics对象,并调用SetOperationToMultiplyByK()函数来将图像中所有的像素值乘以一个常数K,这里常数值为2.0
vtkImageMathematics中支持的二元数学操作有:
SetOperationToAdd:两个图像对应像素加法运算
SetOperationToSubtract:两个图像对应像素减法运算
SetOperationToMultiply:两个图像对应像素相乘运算
SetOperationToDivide:两个图像对应像素相除运算
SetOperationToConjugate:将两个标量图像对应像素组合为共轭复数
SetOperationToComplexMultiply:两个图像对应像素复数乘法运算
SetOperationToMin:取两个图像中对应像素较小值
SetOperationToMax:取两个图像中对应像素较大值
一元操作有:
SetOperationToInvert:图像像素值取倒数运算
SetOperationToSin:图像像素值正弦运算
SetOperationToCos:图像像素值余弦运算
SetOperationToExp:图像像素值自然指数运算
SetOperationToLog:图像像素值自然对数运算
SetOperationToAbsoluteValue:图像像素值取绝对值
SetOperationToSquare:图像像素值平方运算
SetOperationToSquareRoot:图像像素值平凡根运算
SetOperationToATAN:图像像素值正切运算
SetOperationToATAN2:图像像素值反正切运算
SetOperationToMultiplyByK:图像像素值乘以常数K,需要先调用SetConstantK()设置K值
SetOperationToAddConstant:图像像素值加上常数K,需要先调用SetConstantK()设置K值
SetOperationToReplaceCByK:将图像中像素为C的像素值替换为K,需要先调用SetConstantK()和SetConstantC设置K和C值
2、逻辑运算
vtkImageLogic接收一个或者两个图像进行布尔逻辑运算,该类主要支持与(AND),或(OR),异或(XOR),与非(NAND),或非(NOR)和非(NOT)。当选择一元操作符时,只对第一个输入图像有效。 当选择二元操作符时,两个输入图像的类型必须一致。
/*逻辑运算*/
#include <vtkSmartPointer.h>
#include <vtkMath.h> //
#include <vtkImageData.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkImageLogic.h> //
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
int main(int, char *[])
{
vtkSmartPointer<vtkImageCanvasSource2D> imageSource1 = vtkSmartPointer<vtkImageCanvasSource2D>::New();
imageSource1->SetScalarTypeToUnsignedChar();
imageSource1->SetNumberOfScalarComponents(1);
imageSource1->SetExtent(0, 100, 0, 100, 0, 0);
imageSource1->SetDrawColor(0.0);
imageSource1->FillBox(0, 100, 0, 100);
imageSource1->SetDrawColor(255);
imageSource1->FillBox(20, 60, 20, 60);
imageSource1->Update();
vtkSmartPointer<vtkImageCanvasSource2D> imageSource2 = vtkSmartPointer<vtkImageCanvasSource2D>::New();
imageSource2->SetNumberOfScalarComponents(1);
imageSource2->SetScalarTypeToUnsignedChar();
imageSource2->SetExtent(0, 100, 0, 100, 0, 0);
imageSource2->SetDrawColor(0.0);
imageSource2->FillBox(0, 100, 0, 100);
imageSource2->SetDrawColor(255.0);
imageSource2->FillBox(40, 80, 40, 80);
imageSource2->Update();
vtkSmartPointer<vtkImageLogic> imageLogic = vtkSmartPointer<vtkImageLogic>::New();
imageLogic->SetInput1Data(imageSource1->GetOutput());
imageLogic->SetInput2Data(imageSource2->GetOutput());
imageLogic->SetOperationToXor();
imageLogic->SetOutputTrueValue(128);
imageLogic->Update();
vtkSmartPointer<vtkImageActor> originalActor1 = vtkSmartPointer<vtkImageActor>::New();
originalActor1->SetInputData(imageSource1->GetOutput());
vtkSmartPointer<vtkImageActor> originalActor2 = vtkSmartPointer<vtkImageActor>::New();
originalActor2->SetInputData(imageSource2->GetOutput());
vtkSmartPointer<vtkImageActor> logicActor = vtkSmartPointer<vtkImageActor>::New();
logicActor->SetInputData(imageLogic->GetOutput());
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 };
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(0.8, 0.8, 0.8);
vtkSmartPointer<vtkRenderer> logicRenderer = vtkSmartPointer<vtkRenderer>::New();
logicRenderer->SetViewport(rightViewport);
logicRenderer->AddActor(logicActor);
logicRenderer->ResetCamera();
logicRenderer->SetBackground(0.6, 0.6, 0.6);
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(originalRenderer1);
renderWindow->AddRenderer(originalRenderer2);
renderWindow->AddRenderer(logicRenderer);
renderWindow->SetSize(640, 320);
renderWindow->Render();
renderWindow->SetWindowName("ImageLogicExample");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
renderWindowInteractor->SetInteractorStyle(style);
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
运行结果:
上例中首先生成了两个二值图像,两个图像中前景为两个部分重叠矩形。然后定义vtkImageLogic对象,并设置两个图像为输入,SetOperationToXor()设置逻辑操作算子为异或操作,并且SetOutputTrueValue()设置当两个图像对应像素值异或结果为真时的输出像素值,其执行结果如下,可以看成两个矩形的重叠部分像素值相同,因此输出为0;矩形的不重叠部分像素值一个为0,一个为255,因此异或结果为真,那么输出值为128。
vtkImageLogic设置逻辑运算的函数有:
SetOperationToAnd():逻辑与操作
SetOperationToOr():逻辑或操作
SetOperationToXor():逻辑异或
SetOperationToNand():逻辑与非
SetOperationToNor():逻辑或非
SetOperationToNot():逻辑非
注:imageLogic->SetInput1Data(imageSource1->GetOutput());
imageLogic->SetInput2Data(imageSource2->GetOutput());
vtkImageShrink3D通过SetShrinkFactors()设置X、Y和Z方向的采样率,参数为三个int类型数据。vtkImageMagnify通过SetMagnificationFactors设置相应的放大采样率。从图中可以看成,重采样图像已经变得十分模糊了。而升采样图像则变化不大。程序中输出了原图和重采样图像的维数和像素间隔,从输出来看,原图像的维数为512x512,缩小16倍后,图像维数变为32x32。需要注意的是,原图的像素间隔为(1,1,1),而重采样后像素间隔变为(16, 16, 1),这是因为采样是在世界坐标系下进行的,当采样图像的维数减小时,采样的像素间隔也相应的变大,这样保持图像的区域不会发生改变。同样的道理,当升采样后图像的维数变为原来的10倍,而像素间隔变为原来的十分之一。
注:此文知识学习笔记,仅记录完整程序和实现结果,具体原理参见:
https://blog.csdn.net/www_doling_net/article/details/8541534
https://blog.csdn.net/shenziheng1/article/category/6114053/4
参考资料:
1.《The Visualization Toolkit – AnObject-Oriented Approach To 3D Graphics (4th Edition)》
2. 张晓东, 罗火灵. VTK图形图像开发进阶[M]. 机械工业出版社, 2015.