前言
“VTK图形图像开发进阶_张晓东_罗火灵”的学习笔记。
东灵工作室 教程系列导航:http://blog.csdn.net/www_doling_net/article/details/8763686
学习资料
VTK官网学习地址:https://vtk.org/doc/nightly/html/
边缘检测
图像中不连续的灰度值会产生边缘,图像的边缘检测是基于边界的图像分割方法的基础, 例如,分水岭算法通常是分割原图的梯度图像,而梯度实际上也是反映图像的边缘信息。图像边缘常用图像一阶导数和二阶导数来检测。
梯度算子
梯度算子对应于图像一阶导数。图像一阶导数一般是通过差分运算来近似的。VTK中可 以用vtklmageGradient类计算图像梯度。注意:图像梯度是一个矢量,具有方向和大小,因此vtklmageGradient的计算结果是一个梯度场,即每个像素值都是一个梯度矢量。
注意:彩色图像不能直接用来计算梯度,需要先转换为灰度图像。
#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkJPEGReader.h>
#include <vtkImageGradient.h>
#include <vtkImageMagnitude.h>
#include <vtkImageCast.h>
#include <vtkImageShiftScale.h>
//测试图像:../data/lena-gray.jpg
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileName("C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/lena-gray.jpg");
reader->Update();
//图像梯度
vtkSmartPointer<vtkImageGradient> gradientFilter = vtkSmartPointer<vtkImageGradient>::New();
gradientFilter->SetInputConnection(reader->GetOutputPort());
gradientFilter->SetDimensionality(2); //用于设置要计算的图像维数,默认为二维
vtkSmartPointer<vtkImageMagnitude> magnitudeFilter =
vtkSmartPointer<vtkImageMagnitude>::New();
magnitudeFilter->SetInputConnection(gradientFilter->GetOutputPort());
magnitudeFilter->Update();
double range[2];
//获取图像值范围
magnitudeFilter->GetOutput()->GetScalarRange(range);
std::cout<<"获取图像值范围 :"<<range[0] << "~" <<range[1]<<std::endl;
//可以指定偏移和比例参数来对输入图像数据进行类型转换操作。
vtkSmartPointer<vtkImageShiftScale> ShiftScale =
vtkSmartPointer<vtkImageShiftScale>::New();
ShiftScale->SetOutputScalarTypeToUnsignedChar();
ShiftScale->SetScale( 255 / range[1] );
ShiftScale->SetInputConnection(magnitudeFilter->GetOutputPort());
ShiftScale->Update();
vtkSmartPointer<vtkImageActor> originalActor =
vtkSmartPointer<vtkImageActor>::New();
originalActor->SetInputData(reader->GetOutput());
vtkSmartPointer<vtkImageActor> gradActor =
vtkSmartPointer<vtkImageActor>::New();
gradActor->SetInputData(ShiftScale->GetOutput());
double originalViewport[4] = {0.0, 0.0, 0.5, 1.0};
double gradviewport[4] = {0.5, 0.0, 1.0, 1.0};
vtkSmartPointer<vtkRenderer> originalRenderer =
vtkSmartPointer<vtkRenderer>::New();
originalRenderer->SetViewport(originalViewport);
originalRenderer->AddActor(originalActor);
originalRenderer->ResetCamera();
originalRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> gradRenderer =
vtkSmartPointer<vtkRenderer>::New();
gradRenderer->SetViewport(gradviewport);
gradRenderer->AddActor(gradActor);
gradRenderer->ResetCamera();
gradRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(originalRenderer);
renderWindow->AddRenderer(gradRenderer);
renderWindow->SetSize( 640, 320 );
renderWindow->Render();
renderWindow->SetWindowName("ImageGradientExample");
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;
}
Sobel算子提取图像边缘
Sobel算子也是一种常用的梯度算子。Sobel算子计算稍微复杂,它采用3x3的模板。计算时模板在图像上移动,并在每个位置上计算对应中心像素的梯度值。
VTK中vtkSobel2D计算图像的sobel算子
#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)
#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageSobel2D.h>
#include <vtkImageExtractComponents.h>
#include <vtkImageMathematics.h>
#include <vtkImageData.h>
#include <vtkImageShiftScale.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
int main()
{
vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileName("C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/lena.jpg");
reader->Update();
//sobel算子计算图像的梯度图像
vtkSmartPointer<vtkImageSobel2D> sobelFilter = vtkSmartPointer<vtkImageSobel2D>::New();
sobelFilter->SetInputConnection(reader->GetOutputPort());//包含横向和竖向边缘
//提取X向边缘成分
vtkSmartPointer<vtkImageExtractComponents> xSobel =
vtkSmartPointer<vtkImageExtractComponents>::New();
xSobel->SetComponents(0);//提取第一成分即X向梯度
xSobel->SetInputConnection(sobelFilter->GetOutputPort());
xSobel->Update();
//计算Sobel算子的值可能存在负值,因此利用vtklmageMathematics对各分量图像计算绝对值
vtkSmartPointer<vtkImageMathematics> absFilter =
vtkSmartPointer<vtkImageMathematics>::New();
absFilter->SetOperationToAbsoluteValue();//将属性设置为绝对值模式
absFilter->SetInputConnection(xSobel->GetOutputPort());
absFilter->Update();
double xRange[2];
absFilter->GetOutput()->GetScalarRange(xRange);
//由vtklmageShiftScale将图像的数值范围调节到[0, 255]再显示
vtkSmartPointer<vtkImageShiftScale> xShiftScale =
vtkSmartPointer<vtkImageShiftScale>::New();
xShiftScale->SetOutputScalarTypeToUnsignedChar();//强制类型转换 方便显示
xShiftScale->SetScale(255 / xRange[1]);//设置属性
xShiftScale->SetInputConnection(absFilter->GetOutputPort());
xShiftScale->Update();
//提取Y向边缘成分
vtkSmartPointer<vtkImageExtractComponents> ySobel =
vtkSmartPointer<vtkImageExtractComponents>::New();
ySobel->SetComponents(1);
ySobel->SetInputConnection(sobelFilter->GetOutputPort());
ySobel->Update();
vtkSmartPointer<vtkImageMathematics> absYsobel =
vtkSmartPointer<vtkImageMathematics>::New();
absYsobel->SetOperationToAbsoluteValue();
absYsobel->SetInputConnection(ySobel->GetOutputPort());
absYsobel->Update();
double yRange[2];
absYsobel->GetOutput()->GetScalarRange(yRange);
vtkSmartPointer<vtkImageShiftScale> yShiftScale =
vtkSmartPointer<vtkImageShiftScale>::New();
yShiftScale->SetOutputScalarTypeToUnsignedChar();
yShiftScale->SetScale(255 / yRange[1]);
yShiftScale->SetInputConnection(absYsobel->GetOutputPort());
yShiftScale->Update();
vtkSmartPointer<vtkImageActor> origActor =
vtkSmartPointer<vtkImageActor>::New();
origActor->SetInputData(reader->GetOutput());
vtkSmartPointer<vtkImageActor> xSobelActor =
vtkSmartPointer<vtkImageActor>::New();
xSobelActor->SetInputData(xShiftScale->GetOutput());
vtkSmartPointer<vtkImageActor> ySobelActor =
vtkSmartPointer<vtkImageActor>::New();
ySobelActor->SetInputData(yShiftScale->GetOutput());
double origView[4] = { 0, 0, 0.33, 1 };
double xSobelView[4] = { 0.33, 0, 0.66, 1 };
double ySobelView[4] = { 0.66, 0, 1, 1 };
vtkSmartPointer<vtkRenderer> origRender =
vtkSmartPointer<vtkRenderer>::New();
origRender->SetViewport(origView);
origRender->AddActor(origActor);
origRender->ResetCamera();
origRender->SetBackground(1, 0, 0);
vtkSmartPointer<vtkRenderer> xSobelRender =
vtkSmartPointer<vtkRenderer>::New();
xSobelRender->SetViewport(xSobelView);
xSobelRender->AddActor(xSobelActor);
xSobelRender->ResetCamera();
xSobelRender->SetBackground(0, 1, 0);
vtkSmartPointer<vtkRenderer> ySobelRender =
vtkSmartPointer<vtkRenderer>::New();
ySobelRender->SetViewport(ySobelView);
ySobelRender->AddActor(ySobelActor);
ySobelRender->ResetCamera();
ySobelRender->SetBackground(0, 0, 1);
//
vtkSmartPointer<vtkRenderWindow> rw =
vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(origRender);
rw->AddRenderer(xSobelRender);
rw->AddRenderer(ySobelRender);
rw->SetSize(960, 320);
rw->SetWindowName("Edge by Soebl");
vtkSmartPointer<vtkRenderWindowInteractor> rwi =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style =
vtkSmartPointer<vtkInteractorStyleImage>::New();
rwi->SetInteractorStyle(style);
rwi->SetRenderWindow(rw);
rwi->Initialize();
rwi->Start();
return 0;
}
Canny算子
最优边缘的特性,即检测到的边缘要尽可能跟实际的边缘接近并尽可能的多,同时,要尽量降低噪声对边缘检测的干扰。Canny算子的计算步骤如下
1)对源图像进行高斯平滑以消除图像中噪声
2)采用差分法近似计算图像每一个像素的梯度,并计算梯度的模值和方向
3)对梯度进行"非极大抑制":图像边缘点梯度值通常在梯度方向是极大值,因此检测边缘需要将非极大值赋值0来抑制非边缘点。检测方法就是在一个局部窗口内,如果中心像素点的梯度不比梯度方向上相邻两个像素值大,那么该中心像素点梯度值赋0。
4)双阈值法检测边缘和连接边缘。取两个梯度阈值high和low,将梯度图像中小于high的像素赋0得到边缘图像L1,该图像能够接近图像边缘但是可能会存在间断点;将梯度图像中小于low的像素赋0得到边缘图像L2,该图中受噪声影响比较大,但是边缘信息更多。在连接边缘时,以L1为基础,对非零点进行边缘跟踪,如果追踪过程中出现中断,则从L2对应像素点及其邻域来寻找可以连接的边缘,直至结束。
在VTK中没有实现一个专门的类来做Canny边缘检测,但我们可以根据以上步骤来实现。
#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageShiftScale.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkJPEGReader.h>
#include <vtkImageCast.h>
#include <vtkImageGaussianSmooth.h>
#include <vtkImageGradient.h>
#include <vtkImageMagnitude.h>
#include <vtkImageNonMaximumSuppression.h>
#include <vtkImageConstantPad.h>
#include <vtkImageToStructuredPoints.h>
#include <vtkLinkEdgels.h>
#include <vtkThreshold.h>
#include <vtkGeometryFilter.h>
#include <vtkSubPixelPositionEdgels.h>
#include <vtkCamera.h>
#include <vtkProperty.h>
#include <vtkStripper.h>
#include <vtkPolyDataMapper.h>
#include <vtkBMPReader.h>
#include <vtkImageLuminance.h>
//测试图像:../data/lena-gray.jpg
/*
vtkLinkEdgels (006E0448): No data to transform (or wrong data type)!
ERROR: In VTK\VTK-8.2.0\Filters\General\vtkSubPixelPositionEdgels.cxx, line 75
vtkSubPixelPositionEdgels (039006C0): No data to fit!
解决方案加入Update()
*/
int main(int argc, char* argv[])
{
//读取图像数据
vtkSmartPointer<vtkBMPReader> reader =
vtkSmartPointer<vtkBMPReader>::New();
reader->SetFileName("C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/lena.bmp");
reader->Update();
int dims[3]; //获取图像大小
reader->GetOutput()->GetDimensions(dims);
int nbOfComp;
nbOfComp = reader->GetOutput()->GetNumberOfScalarComponents(); //获取像素的元组组分数(是灰度图、梯度图、RGB图)
vtkAlgorithmOutput *data = reader->GetOutputPort();
if(nbOfComp >= 3 )
{
vtkImageLuminance *luminanceFilter =
vtkImageLuminance::New();
luminanceFilter->SetInputData(reader->GetOutput());
luminanceFilter->Update();
data = luminanceFilter->GetOutputPort();
std::cout << "输入图像为rbg图像 需要先转化成灰度图像:" << dims[0] <<" "<< dims[1] <<" "<< dims[2] <<" "<< nbOfComp << std::endl;
}
//转成float类型
vtkSmartPointer<vtkImageCast> ic =
vtkSmartPointer<vtkImageCast>::New();
ic->SetOutputScalarTypeToFloat();
ic->SetInputConnection(data);
ic->Update();
//高斯平滑
vtkSmartPointer<vtkImageGaussianSmooth> gs =
vtkSmartPointer<vtkImageGaussianSmooth>::New();
gs->SetInputData(ic->GetOutput());
gs->SetDimensionality(2); //设置维数
gs->SetRadiusFactors(1, 1, 0);
gs->Update();
//图像梯度
vtkSmartPointer<vtkImageGradient> imgGradient =
vtkSmartPointer<vtkImageGradient>::New();
imgGradient->SetInputData(gs->GetOutput());
imgGradient->SetDimensionality(2);
imgGradient->Update();
//计算矢量模—2-范数
vtkSmartPointer<vtkImageMagnitude> imgMagnitude =
vtkSmartPointer<vtkImageMagnitude>::New();
imgMagnitude->SetInputData(imgGradient->GetOutput());
imgMagnitude->Update();
//将图像的非局部峰值设置为0
vtkSmartPointer<vtkImageNonMaximumSuppression> nonMax =
vtkSmartPointer<vtkImageNonMaximumSuppression>::New();
nonMax->SetMagnitudeInputData(imgMagnitude->GetOutput()); //需要输入模值图像和矢量图像
nonMax->SetVectorInputData(imgGradient->GetOutput());
nonMax->SetDimensionality(2);
nonMax->Update();
//增加图像的大小
vtkSmartPointer<vtkImageConstantPad> pad =
vtkSmartPointer<vtkImageConstantPad>::New();
pad->SetInputConnection(imgGradient->GetOutputPort());
pad->SetOutputNumberOfScalarComponents(3);//设置输出图像的组分数 这里的作用是将梯 度图像像素的组分修改为3,方便后续的vtklmageToStructuredPoints使用
pad->SetConstant(0); //设置输出图像中扩大的区域像素值
pad->Update();
//3)vtklmageToStructuredPoints«该类将vtklmageData格式转换为规则点集。
//该类的输入类型是vtklmageData,另外还有一个可选的RGB三组分向量图像输入
//其输出类型是 vtkStructuredPointSo当输入矢量图像时,矢量图像像素数据会转为输出图像的对应点的属性。
vtkSmartPointer<vtkImageToStructuredPoints> i2sp1 =
vtkSmartPointer<vtkImageToStructuredPoints>::New();
i2sp1->SetInputData(nonMax->GetOutput());
i2sp1->SetVectorInputData(pad->GetOutput());
i2sp1->Update();
//据点的相邻关系将点连接成连续的折线(Polyline)
vtkSmartPointer<vtkLinkEdgels> imgLink =
vtkSmartPointer<vtkLinkEdgels>::New();
imgLink->SetInputData(i2sp1->GetOutput());
imgLink->SetGradientThreshold(2);
imgLink->Update();
//获取输入任意类型数据的满足阈值条件的单元数据
/*
当属性为多组分数据时,还需要设置阈值比较时 使用哪个组分的数据。
其中提供了三种模式选择:所有组分都满足阈值条件、任意一个组分 满足阈值条件和用户指定的组分满足阈值条件。
当使用点属性数据时,如果设置了 AllScalars, 那么单元满足阈值条件的前提是其所有点的属性都满足阈值条件。
这里将阙值设置为10,即 Canny中双阈值的较大阈值。
*/
vtkSmartPointer<vtkThreshold> thresholdEdgels =
vtkSmartPointer<vtkThreshold>::New();
thresholdEdgels->SetInputData(imgLink->GetOutput());
thresholdEdgels->ThresholdByUpper(10);
thresholdEdgels->AllScalarsOff();
thresholdEdgels->Update();
//将数据转换为几何数据,其输出类型为vtkPolyData。该
//类从vtkThreshold的输出中提取图像边缘的几何数据。
vtkSmartPointer<vtkGeometryFilter> gf =
vtkSmartPointer<vtkGeometryFilter>::New();
gf->SetInputConnection(thresholdEdgels->GetOutputPort());
vtkSmartPointer<vtkImageToStructuredPoints> i2sp =
vtkSmartPointer<vtkImageToStructuredPoints>::New();
i2sp->SetInputData(imgMagnitude->GetOutput());
i2sp->SetVectorInputData(pad->GetOutput());
i2sp->Update();
//接收一系列连续曲线及其对应的梯度信息作为输入, 利用梯度信息来调整曲线位置。这里对前面提取的图像边缘再根据其梯度进行调整。
vtkSmartPointer<vtkSubPixelPositionEdgels> spe =
vtkSmartPointer<vtkSubPixelPositionEdgels>::New();
spe->SetInputConnection(gf->GetOutputPort());
spe->SetGradMapsData(i2sp->GetStructuredPointsOutput());
/*
vtkStrippero该类用来将输入的多边形、三角形或者线段生成三角形条带或者折线段。
注意:输入的多边形数据必须是三角形,否则不会进行带化处理。
因此,处理多边形数据时, 可以先用vtkTriangleFilter类进行三角化后再使用这个类。
如果输入中存在孤立点,也不会进 行任何处理。默认情况下,该Filter处理后会丢弃掉属性数据。
*/
vtkSmartPointer<vtkStripper> strip =
vtkSmartPointer<vtkStripper>::New();
strip->SetInputConnection(spe->GetOutputPort());
vtkSmartPointer<vtkPolyDataMapper> dsm =
vtkSmartPointer<vtkPolyDataMapper>::New();
dsm->SetInputConnection(strip->GetOutputPort());
dsm->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> planeActor =
vtkSmartPointer<vtkActor>::New();
planeActor->SetMapper(dsm);
planeActor->GetProperty()->SetAmbient(1.0);
planeActor->GetProperty()->SetDiffuse(0.0);
planeActor->GetProperty()->SetColor(1.0, 0.0, 0.0);
vtkSmartPointer<vtkImageActor> originalActor =
vtkSmartPointer<vtkImageActor>::New();
originalActor->SetInputData(reader->GetOutput());
double originalViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
double gradviewport[4] = { 0.5, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkRenderer> originalRenderer =
vtkSmartPointer<vtkRenderer>::New();
originalRenderer->SetViewport(originalViewport);
originalRenderer->AddActor(originalActor);
originalRenderer->ResetCamera();
originalRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> gradRenderer =
vtkSmartPointer<vtkRenderer>::New();
gradRenderer->SetViewport(gradviewport);
gradRenderer->AddActor(planeActor);
gradRenderer->ResetCamera();
gradRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(900, 300);
renderWindow->AddRenderer(originalRenderer);
renderWindow->AddRenderer(gradRenderer);
renderWindow->Render();
renderWindow->SetWindowName("CannyExample");
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;
}
拉普拉斯算子
拉普拉斯算子是一个二阶边缘算子,即梯度的散度。拉普拉斯算子也是通过模板实现。 常用的拉普拉斯算子模板定义如下图所示。
拉普拉斯算子计算图像的二阶导数,对于图像噪声比较敏感。拉普拉斯算子的结果为标 量,表示边缘的宽度。但是它常产生双像素宽边缘,而且不能提供方向信息,因此较少直接 用于边缘检测。
#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkImageShiftScale.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkJPEGReader.h>
#include <vtkImageLaplacian.h>
//测试图像:../data/lena-gray.jpg
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkJPEGReader> reader =
vtkSmartPointer<vtkJPEGReader>::New();
reader->SetFileName("C:/Users/jbyyy/Desktop/work/QTDEMO/jbyyy/VTK/学习资料/VTK图形图像开发进阶+张晓东+PDF+源码/VTK图形图像开发进阶随书代码/VTK图形图像开发进阶随书代码/Examples/Chap05/data/lena-gray.jpg");
reader->Update();
vtkSmartPointer<vtkImageLaplacian> lapFilter =
vtkSmartPointer<vtkImageLaplacian>::New();
lapFilter->SetInputConnection(reader->GetOutputPort());
lapFilter->SetDimensionality(2);
double range[2];
lapFilter->GetOutput()->GetScalarRange(range);
vtkSmartPointer<vtkImageShiftScale> ShiftScale =
vtkSmartPointer<vtkImageShiftScale>::New();
ShiftScale->SetOutputScalarTypeToUnsignedChar();
ShiftScale->SetScale( 255 / (range[1]-range[0]) );
ShiftScale->SetShift(-range[0]);
ShiftScale->SetInputConnection(lapFilter->GetOutputPort());
ShiftScale->Update();
vtkSmartPointer<vtkImageActor> originalActor =
vtkSmartPointer<vtkImageActor>::New();
originalActor->SetInputData(reader->GetOutput());
vtkSmartPointer<vtkImageActor> gradActor =
vtkSmartPointer<vtkImageActor>::New();
gradActor->SetInputData(ShiftScale->GetOutput());
double originalViewport[4] = {0.0, 0.0, 0.5, 1.0};
double gradviewport[4] = {0.5, 0.0, 1.0, 1.0};
vtkSmartPointer<vtkRenderer> originalRenderer =
vtkSmartPointer<vtkRenderer>::New();
originalRenderer->SetViewport(originalViewport);
originalRenderer->AddActor(originalActor);
originalRenderer->ResetCamera();
originalRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> gradRenderer =
vtkSmartPointer<vtkRenderer>::New();
gradRenderer->SetViewport(gradviewport);
gradRenderer->AddActor(gradActor);
gradRenderer->ResetCamera();
gradRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(originalRenderer);
renderWindow->AddRenderer(gradRenderer);
renderWindow->SetSize(640, 320);
renderWindow->Render();
renderWindow->SetWindowName("LaplacianExample");
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;
}