文档章节

VTK入门(三)--图像加工处理(一)

qt_plus
 qt_plus
发布于 2017/01/16 14:55
字数 2730
阅读 299
收藏 2
VTK

不知不觉离上篇博客已经过去了一个月了,决定把vtk图像处理的方式方法总结下来。

编写vtk程序就和平时做事情是一样的,要循序渐进,才不会出错,具体步骤如下:

1、vtk图像构建

前面的文章提到过,可以用Source(比如,vtkConeSource创建椎体源对象,vtkImageCanvasSource2D创建空白画布对象)来创建,并且都会提供相应的图像处理功能,但随着我对vtk学习的慢慢深入,发现Source类快读生成图像的方法在现实中用到的并不到,所以我们采用别的方法手动创建图像。
我们知道图像的三个重要信息是:起点位置、像素间隔、维数,有了这三个要素就可以在空间中构建一副图像出来。下面是对应的示例:

 

vtkImageData *imgCreate = vtkImageData::New();
imgCreate->SetDimensions(20,20,1);
imgCreate->SetScalarTypeToUnsignedChar();
imgCreate->SetNumberOfScalarComponents(1);
imgCreate->AllocateScalars();
unsigned char *ptr = (unsigned char*)imgCreate->GetScalarPointer();
for(int i=0; i<20*20*1; i++)
{
	*ptr ++ =i%256; 
}
vtk中的图像数据结构都是vtkImageData类来表示,所以要创建图像,要先定义vtkImageData类的对象,接下来的就是创建三要素,其中本示例中原点和像素间隔都采用了默认值。
SetScalarTypeToUnsignedChar() ,指定其数据类型为UnsignedChar.。
SetNumberOfScalarComponents(1),指定像素值为1也就是组分数为1,说道组分又可以说很多东西,vkt的内存是连续分配的,用类vtkDataArray来实现,叫做数据数组,比如一个数据有4个分量构成,那么要在连续数组中表达这一数据,就需要采用元组Tuple,存储类型相同的数据,元组的组分数为其大小。
AllocateScalars(),分配内存,生成数据。
GetScalarPointer(),返回图像数据数组。
for循环中重新设置像素值。
运行结果如图,出现这个瑕疵是SetDimensions没有设置好的缘故。

2、vtk图像显示

vtk中图像显示可以使用vtkImageViewer2(至于为什么有个2,据说是vtkImageView被版本淘汰了)和vtkImageActor来实现。

(1)vtkImageViewer2

此类封装了vtk图像的可视化渲染引擎,包括vtkActor,vtkRender,vtkRenderWindow等,并且可以提供图像的缩放窗宽窗位调节功能(窗框是图像的灰度范围,窗位是窗宽的中心位置),下面贴出示例:

 

vtkJPEGReader *reader =vtkJPEGReader::New();
reader->SetFileName("../data/lo.jpg");
reader->Update();
vtkImageViewer2 *imageViewer =vtkImageViewer2::New();
imageViewer->SetInputConnection(reader->GetOutputPort());

vtkRenderWindowInteractor *Interactor =vtkRenderWindowInteractor::New();
imageViewer->SetupInteractor(Interactor);
imageViewer->SetColorLevel(500);
imageViewer->SetColorWindow(2000);
imageViewer->SetSlice(40);
imageViewer->SetSliceOrientationToXY();
imageViewer->Render();

imageViewer->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
imageViewer->SetSize(320, 240);
imageViewer->GetRenderWindow()->SetWindowName("Display");
Interactor->Initialize();
Interactor->Start();

前三行读入衣服jpg格式的图片,然后使用vtkImageViewer2显示图像。

SetColorLevel(500),设置窗位

SetColorWindow(2000),设置窗宽

SetSlice(40),设置切片索引

SetSliceOrientationToXY(),设置切片方向

随后就是基本的可视化流程。

运行结果如下:

 

(2)vtkImageActor

vktImageActor需要建立完整的渲染管线,示例如下:

 

vtkJPEGReader *reader = vtkJPEGReader::New();
reader->SetFileName ( "../data/lo.jpg" );
reader->Update();

vtkImageActor* imgActor =vtkImageActor::New();
imgActor->SetInput(reader->GetOutput());

vtkRenderer *renderer =vtkRenderer::New();
renderer->AddActor(imgActor);
renderer->SetBackground(1.0, 1.0, 1.0);

vtkRenderWindow *renderWindow =vtkRenderWindow::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize( 320, 240 );
renderWindow->Render();
renderWindow->SetWindowName("Display2");

vtkRenderWindowInteractor *renderWindowInteractor =vtkRenderWindowInteractor::New();
vtkInteractorStyleImage *style =vtkInteractorStyleImage::New();

renderWindowInteractor->SetInteractorStyle(style);
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize();

renderWindowInteractor->Start();

首先读入jpg图像,然后依次建立vtkImageActor,vtkRender,vtkRenderWindow等,最后创建vtkInteractorStyleImage对象,设置交互类型。

 

 

补充说明:

上述两种方法显示图像都是显示一幅图像,用vtkImageBlend将多个图像输入,输出为融合图像。vtk中规定,输出图像的三要素与第一幅图像一直。示例如下:

vtkJPEGReader *reader =vtkJPEGReader::New();
reader->SetFileName ( "../data/lo.jpg" );
reader->Update();

vtkImageCanvasSource2D *imageSource = vtkImageCanvasSource2D::New();
imageSource->SetNumberOfScalarComponents(1);
imageSource->SetScalarTypeToUnsignedChar();
imageSource->SetExtent(0, 1050, 0, 699, 0, 0);
imageSource->SetDrawColor(0.0);
imageSource->FillBox(0, 1050, 0, 699);
imageSource->SetDrawColor(255.0);
imageSource->FillBox(100,400,100,400);
imageSource->Update();

vtkImageBlend *imageBlend = vtkImageBlend::New();
imageBlend->SetInput(0, reader->GetOutput());
imageBlend->SetInput(1, imageSource->GetOutput());
imageBlend->SetOpacity(0, 0.4);
imageBlend->SetOpacity(1, 0.6);
imageBlend->Update();
首先读入图像,然后用Source类生成一幅图,最后用vtkImageBlend进行融合,在输出,其中两幅图像都需要编号

 

SetOpacity(),可以用来设置不透明度。

3、图像基本操作

图像的基本操作是指获取图像的基本信息,修改像素值,图像数据类型转换,等基本操作。

(1)、图像信息访问和修改

我们看到vtk封装了许多Set和Get的方法,没错,他们可以用来访问图像信息,比如GetDimensions(),获取图像的维数,另外还可以使用vtkChangeImageInformation来修改图像的三要素,同时可以实现缩放等操作;

(2)、像素值的访问修改

像素值的修改与访问是最常用的一种操作,vtk中可以直接访问vtkImageData的数据数组,前面提到了可以使用GetScalarPointer()来获取指针。

unsigned char * pixel = (unsigned char *) ( reader->GetOutput()->GetScalarPointer(i, j, k) );

 该函数返回的是void类型的指针,需转换成unsigned char *类型。

 

还有一种方法是使用vtkImageIterator类通过迭代器来实现。

vtkImageIterator<unsigned char> it(reader->GetOutput(), subRegion);
该类是一个模板类,使用时需要图像类型以及迭代的区域的大小。

 

(3)、类型转换

前面我们也看到经常需要进行图像类型装换,vtk中提供了vtkImageCast类和vtkIamgeShiftScale类来进行操作。

vtkImageCast 的使用只要把该类封装的SetOutputScalarTypeTo..设置成相应的类型就行了。

而vtkIamgeShiftScale则可以对偏移和比例参数来对图像数据进行操作,代码操作如下:

 

vtkImageShiftScale *shift = vtkImageShiftScale::New();  
shift->SetInputConnection(image->GetProducerPort());  
shift->SetOutputScalarTypeToUnsignedChar();  
shift->SetShift(1);  
shift->SetScale(100);  
shift->Update();  

 

SetShift()设置偏移量,SetScale()用于设置放缩值。

 

(4)、颜色操作

灰度图像映射可以使用vtkImageLuminance来实现,方法比较简答,而彩色图像映射前面提到过,通过颜色查找表实现vtkLookUpTable实现。

vtk中vtkImageExtractComponents用来提取彩色图像的各个颜色组分,提供SetComponents()方法提取组分号,执行Update()即可得到数据。

vtkImageAppendComponents类可以用来合成彩色图像。代码示例如下:

 

 

vtkSmartPointer<vtkImageCanvasSource2D> red =  
    vtkSmartPointer<vtkImageCanvasSource2D>::New();  
red->SetScalarTypeToUnsignedChar();  
red->SetNumberOfScalarComponents(1);  
red->SetExtent(0, 100, 0, 100, 0, 0);  
red->SetDrawColor(0, 0, 0, 0);  
red->FillBox(0,100,0,100);  
red->SetDrawColor(255, 0, 0, 0);  
red->FillBox(20,40,20,40);  
red->Update();  
  
vtkSmartPointer<vtkImageCanvasSource2D> green =  
    vtkSmartPointer<vtkImageCanvasSource2D>::New();  
green->SetScalarTypeToUnsignedChar();  
green->SetNumberOfScalarComponents(1);  
green->SetExtent(0, 100, 0, 100, 0, 0);  
green->SetDrawColor(0, 0, 0, 0);  
green->FillBox(0,100,0,100);  
green->SetDrawColor(255, 0, 0, 0);  
green->FillBox(30,50,30,50);  
green->Update();  
  
vtkSmartPointer<vtkImageCanvasSource2D> blue =  
    vtkSmartPointer<vtkImageCanvasSource2D>::New();  
blue->SetScalarTypeToUnsignedChar();  
blue->SetNumberOfScalarComponents(1);  
blue->SetExtent(0, 100, 0, 100, 0, 0);  
blue->SetDrawColor(0, 0, 0, 0);  
blue->FillBox(0,100,0,100);  
blue->SetDrawColor(255, 0, 0, 0);  
blue->FillBox(40,60,40,60);  
blue->Update();  
  
vtkSmartPointer<vtkImageAppendComponents> appendFilter =  
    vtkSmartPointer<vtkImageAppendComponents>::New();  
appendFilter->SetInputConnection(0, red->GetOutputPort());  
appendFilter->AddInputConnection(0, green->GetOutputPort());  
appendFilter->AddInputConnection(0, blue->GetOutputPort());  
appendFilter->Update();  
首先定义了三个灰度图像,然后让三个图像部分重叠,程序运行结果如下:

 

(5)、区域提取

vtkExtractVOI类可以提取指定区域的图像,输入输出都是vtkImageData。示例程序如下:

 

 

vtkJPEGReader* reader =vtkJPEGReader::New();  
reader->SetFileName ("../data/lo.jpg");  
reader->Update();  
  
int dims[3];  
reader->GetOutput()->GetDimensions(dims);  
  
vtkExtractVOI* extractVOI =vtkExtractVOI::New();  
extractVOI->SetInputConnection(reader->GetOutputPort());  
extractVOI->SetVOI(dims[0]/4.,3.*dims[0]/4.,dims[1]/4.,3.*dims[1]/4., 0, 0);  
extractVOI->Update();  
  
vtkImageActor *originalActor =vtkImageActor::New();  
originalActor->SetInput(reader->GetOutput());  
  
vtkImageActor *voiActor =vtkImageActor::New();  
voiActor->SetInput(extractVOI->GetOutput());  
读入一副图像,然后提取出需要的区域,最后定义两个actor将他们显示出来

 


 

而在三维图像中可以使用vtkImageReslice进行三维图像切面的提取。

(6)、直方图显示

显示一副灰度图像直方图,vtk中使用vtkImageAccumulate类来进行统计功能。该类输入输出都是vtkImageData类型,代码示例如下:

vtkJPEGReader *reader =vtkJPEGReader::New();  
reader->SetFileName ( "..\\data\\lena-gray.jpg" );  
reader->Update();  
  
int bins   = 16;  
int comps  = 1;  
  
vtkImageAccumulate *histogram =vtkImageAccumulate::New();  
histogram->SetInput(reader->GetOutput());  
histogram->SetComponentExtent(0, bins-1, 0, 0, 0, 0);  
histogram->SetComponentOrigin(0, 0, 0);  
histogram->SetComponentSpacing(256.0/bins, 0, 0);  
histogram->Update();  
  
int* output = static_cast<int*>(histogram->GetOutput()->GetScalarPointer());  
  
vtkIntArray* frequencies = vtkIntArray::New();  
frequencies->SetNumberOfComponents(1);  
  
for(int j = 0; j < bins; ++j)  
{  
    for(int i=0; i<comps; i++)  
    {  
        frequencies->InsertNextTuple1(*output++);  
    }  
}  
  
vtkDataObject *dataObject = vtkDataObject::New();  
dataObject->GetFieldData()->AddArray( frequencies );  
  
vtkBarChartActor *barChart = vtkBarChartActor::New();  
barChart->SetInput(dataObject);  
barChart->SetTitle("Histogram");  
barChart->GetPositionCoordinate()->SetValue(0.05,0.05,0.0);  
barChart->GetPosition2Coordinate()->SetValue(0.95,0.95,0.0);  
barChart->GetProperty()->SetColor(0,0,0);  
barChart->GetTitleTextProperty()->SetColor(0,0,0);  
barChart->GetLabelTextProperty()->SetColor(0,0,0);  
barChart->GetLegendActor()->SetNumberOfEntries(dataObject->GetFieldData()->GetArray(0)->GetNumberOfTuples());  
barChart->LegendVisibilityOff();  
barChart->LabelVisibilityOff();  
代码比较长,一点点来解释,首先读入一副灰度图形,然后定义了灰度直方图的间隔数目。
SetComponentExtent(0, bins-1, 0, 0, 0, 0);设置每个组分直方图最大最小值

 

SetComponentOrigin(0, 0, 0);每个组分直方图的其实灰度值。

SetComponentSpacing(256.0/bins, 0, 0);每个间隔代表的灰度范围。

然后调用updata()就可以计算了。

另外要将图像显示出来,需要通过vtkBarChartActor来显示,但是他接受vtkDataObject类型,所以先存储到数组frequencies中,然后再添加到vtkDataObject中,最后在通过vtkBarChartActor来实现实现。

(7)、重采样

重采样是按照图像的像素位置和间距重新采样,然后重新构成新图像。重采样会改变图像的维数,分为降采样和增采样,vtkImageShrink3D用来实现降采样操作,vtkImageMagnify用来实现升采样操作。

(8)、数学运算与逻辑运算

vtkImageMathematics来提供基本的数学操作,提供的一元操作有如下:

 

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值

提供的二元操作有:

 

SetOperationToAdd:两个图像对应像素加法运算

SetOperationToSubtract:两个图像对应像素减法运算

SetOperationToMultiply:两个图像对应像素相乘运算

SetOperationToDivide:两个图像对应像素相除运算

SetOperationToConjugate:将两个标量图像对应像素组合为共轭复数

SetOperationToComplexMultiply:两个图像对应像素复数乘法运算

SetOperationToMin:取两个图像中对应像素较小值

SetOperationToMax:取两个图像中对应像素较大值

vtkImageLogic通常用来执行图像的布尔逻辑运算,支持的逻辑运算有:

 

SetOperationToAnd():逻辑与操作

SetOperationToOr():逻辑或操作

SetOperationToXor():逻辑异或

SetOperationToNand():逻辑与非

SetOperationToNor():逻辑或非

SetOperationToNot():逻辑非

 

(9)、二值化

二值化顾名思义,二值图像的取值只能是0和255.可以通过vtkImageThreshold类实现图像二值化。示例代码如下:

vtkJPEGReader *reader =vtkJPEGReader::New();  
reader->SetFileName("../data/lo.jpg");  
reader->Update();  
  
vtkImageThreshold *thresholdFilter =vtkImageThreshold::New();  
thresholdFilter->SetInputConnection(reader->GetOutputPort());  
thresholdFilter->ThresholdByUpper(100);  
thresholdFilter->SetInValue(255);  
thresholdFilter->SetOutValue(0);  
ThresholdByUpper()设置大于100的灰度范围为有效范围。通过SetInValue()设置范围内的输出值,SetOutValue()设置范围外的输出值。

 

© 著作权归作者所有

qt_plus
粉丝 5
博文 97
码字总数 28684
作品 0
石家庄
程序员
私信 提问
Activiz 使用笔记 (6) 图像数据及其处理

http://image.szpt.edu.cn/UploadFiles/%E5%9B%BE%E5%83%8F%E6%95%B0%E6%8D%AE%E5%8F%8A%E5%85%B6%E5%A4%84%E7%90%86.swf 图像数据集用类vtkImageData表示。其结构与结构化点数据集是一样的,......

小王爷和老王爷
2015/11/26
99
0
Activiz 使用笔记-4 数据源(2)

上一篇写了一些数据源的生成或者读取方法。下面开始严肃的讲一下VTK中的数据集,虽然感觉有时候不会直接去用,但是感觉这个是基础,所以要先看。 直接看《VTK用户手册》的第44页 3.1 可视化v...

小王爷和老王爷
2015/11/24
124
0
医学影像分割与配准算法平台--ITK

ITK 是美国国家卫生院下属的国立医学图书馆投入巨资支持三家科研机构开发医学影像分割与配准算法的研发平台,现已开发了初步版本。是医学影像算法平台的重要组成部分。对于ITK 国内的应用并不...

匿名
2010/09/20
4K
0
医学图像处理工具集--MITK

MITK (Medical Imaging Interaction Toolkit) 是一款开源的交互式医学图像处理软件开发平台。MITK将ITK和VTK整合为一个应用框架。同时作为一个工具箱,MITK提供了ITK和VTK所不包含的其他医学...

匿名
2012/04/07
5.4K
0
VTK相机类vtkCamera原理及用法

vtk是著名的开源三维渲染库,在三维渲染过程中的一个非常重要的内容就是相机即vtkCamera类的设置。在VTK中,相机的实质是一个观测点。VTK的官方Doc对vtkCamera写的十分简略,暗坑很多。在学习...

wzheng92
2018/04/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

fabric-sdk-java 1.4安装说明

Hyperledger Fabric Java SDK是开发基于Hyperledger Fabric区块链的Java应用之必备开发包。本文将介绍如何在Maven、Gradle和Eclipse中安装使用最新1.4版本的Hyperledger Fabric Java SDK。 ...

汇智网教程
24分钟前
0
0
Linux基础优化与安全归纳总结

一名运维工程师在运维岗位上时间久了,就会发现Linux优化的重要性,同时会给运维工作带来很多的便利性。本人逐渐认识到了这一点,所以特意在工作闲暇之余,通过阅读Linux相关书籍及向同事、同...

xiangyunyan
25分钟前
2
0
要996还是要生活?

今天早上,嗅嗅还在被窝的时候,睁开朦胧的双眼,习惯性的打开手机,一行小字映入眼帘:要996还是要生活 当真是垂死病中惊坐起,嗅嗅瞬间就清醒过来了。 其实嗅嗅当时的内心活动是:别闹了,...

forespider
25分钟前
4
0
SpringCloud微服务构建

遇到问题 修改server.port后,端口变更不起作用,总是8080 src/java/resources应该和rc/java/java在同一个层级,否则boot读取不到配置信息

铲平王
26分钟前
2
0
[IntelliJ IDEA][maven]properties in parent definition are prohibited报错

<parent> ... <version>${platform.version}</version><parent> IntelliJ报错: properties in parent definition are prohibited 解决: idea的错误提示,不用管 或者升级到maven3.5.......

Danni3
27分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部