VTK编程指南<十五>:vtk图像区域提取和直方图统计

news/2024/12/18 8:03:42/

1、区域提取

  感兴趣区域(Volume of Interest,VOI)是图像内部的一块子区域。在VTK中,vtkExtractVOI类可根据用户指定的区域范围提取子图像。该Filter的输入和输出都是一个vtkImageData,因此其结果可以直接作为图像保存。

在这里插入图片描述

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);// VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkBMPReader.h>
#include <vtkExtractVOI.h>//测试图像:../data/lena.bmp
int main(int argc, char* argv[])
{vtkSmartPointer<vtkBMPReader> reader =vtkSmartPointer<vtkBMPReader>::New();reader->SetFileName ("../data/lena.bmp");reader->Update();int dims[3];reader->GetOutput()->GetDimensions(dims);vtkSmartPointer<vtkExtractVOI> extractVOI =vtkSmartPointer<vtkExtractVOI>::New();extractVOI->SetInputConnection(reader->GetOutputPort());extractVOI->SetVOI(0, 3. * dims[0]/4.,0., 3. * dims[1]/4., 0, 0);extractVOI->Update();vtkSmartPointer<vtkImageActor> originalActor =vtkSmartPointer<vtkImageActor>::New();originalActor->SetInputData(reader->GetOutput());vtkSmartPointer<vtkImageActor> voiActor =vtkSmartPointer<vtkImageActor>::New();voiActor->SetInputData(extractVOI->GetOutput());double originalViewport[4] = {0.0, 0.0, 0.5, 1.0};double voiviewport[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> shiftscaleRenderer =vtkSmartPointer<vtkRenderer>::New();shiftscaleRenderer->SetViewport(voiviewport);shiftscaleRenderer->AddActor(voiActor);shiftscaleRenderer->ResetCamera();shiftscaleRenderer->SetBackground(1.0, 1.0, 1.0);vtkSmartPointer<vtkRenderWindow> renderWindow =vtkSmartPointer<vtkRenderWindow>::New();renderWindow->AddRenderer(originalRenderer);renderWindow->AddRenderer(shiftscaleRenderer);renderWindow->SetSize(900, 300);renderWindow->Render();renderWindow->SetWindowName("ExtractVOIExample");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;
}

  上述代码用于提取图像的感兴趣区域。先读取一幅 BMP图像,并获取图像的维数;然后定义vtkExtractVOI 对象,该对象接收两个输入:第一个是图像数据,第二个是区域大小。设置区域大小的函数原型的代码如下:

void SetvOI(int _arg1, int _arg2, int _arg3, int _arg4, int _arg5, int _arg6)
void SetVOI(int _arg[])

  其参数是所提取区域各个方向的大小,共 6个参数,依次表示X方向坐标最小值、X方向最大值、Y方向最小值、Y方向最大值、Z方向最小值和Z方向最大值。本例中由于读取的是二维图像,因此 Z方向的区域为[0,0],而 X方向的范围[dims[0]/4,3dims[0]/4],Y 方向的范围为[dims[1]/4,3dims[1]/4],即提取图像原图中间 1/4 图像。

2、灰度直方图

  直方图统计是图像处理中一种非常重要的操作。VTK 中的 vtkImageAccumulate 类用于实现直方图统计功能。它将每个组分的数值范围划分为离散的间隔,然后统计每个灰度间隔上的像素数目。vtkImageAccumulate 输入和输出都是 vtkImageData 类型,因此直方图也可以看作一幅图像;输入图像的像素数据类型可以是任意的,但是最大支持3个组分像素类型,而输出图像的像素数据类型为 int 型。对于灰度图像使用该Filter 会产生一个一维图像。下述代码演示了计算灰度图像直方图的方法。

在这里插入图片描述

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);// VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);#include <vtkActor.h>
#include <vtkBarChartActor.h>
#include <vtkFieldData.h>
#include <vtkImageAccumulate.h>
#include <vtkImageData.h>
#include <vtkIntArray.h>
#include <vtkJPEGReader.h>
#include <vtkLegendBoxActor.h>
#include <vtkProperty2D.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkTextProperty.h>//测试图像:../data/lena-gray.jpg
int main(int argc, char* argv[])
{vtkSmartPointer<vtkJPEGReader> reader =vtkSmartPointer<vtkJPEGReader>::New();reader->SetFileName ( "..\\data\\lena-gray.jpg" );reader->Update();int bins   = 16;int comps  = 1;vtkSmartPointer<vtkImageAccumulate> histogram =vtkSmartPointer<vtkImageAccumulate>::New();histogram->SetInputData(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());vtkSmartPointer<vtkIntArray> frequencies = vtkSmartPointer<vtkIntArray>::New();frequencies->SetNumberOfComponents(1);for(int j = 0; j < bins; ++j){for(int i=0; i<comps; i++){frequencies->InsertNextTuple1(*output++);}}vtkSmartPointer<vtkDataObject> dataObject = vtkSmartPointer<vtkDataObject>::New();dataObject->GetFieldData()->AddArray( frequencies );vtkSmartPointer<vtkBarChartActor> barChart = vtkSmartPointer<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();double colors[3][3] = {{ 1, 0, 0 },{ 0, 1, 0 },{ 0, 0, 1 } };int count = 0;for( int i = 0; i < bins; ++i ){for( int j = 0; j < comps; ++j ){barChart->SetBarColor( count++, colors[j] );}}vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();renderer->AddActor(barChart);renderer->SetBackground(1.0, 1.0, 1.0);vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();renderWindow->AddRenderer(renderer);renderWindow->SetSize(640, 480);renderWindow->Render();renderWindow->SetWindowName("ImageAccumulateExample");vtkSmartPointer<vtkRenderWindowInteractor> interactor =vtkSmartPointer<vtkRenderWindowInteractor>::New();interactor->SetRenderWindow(renderWindow);interactor->Initialize();interactor->Start();return EXIT_SUCCESS;
}

  该示例先读入一幅灰度图像。一般灰度图像的灰度范围为0~255。定义了一个变量bins
-16,表示图像灰度直方图的间隔数目,也可以理解为直方图一维数组的维数。然后定义vtkImageAccumulate 对象,并设置输入数据为读入的图像数据,接着调用了如下三个函数。

  1. SetComponentExtent(0,bins-1,0,0,0,0)。该函数设置要计算每个组分的直方图的最小值和最大值。vtkImageAccumulate 最大支持像素值为三个组分(如 RGB图像)的直方图,该方法共有六个参数,分别表示每个组分的直方图最小值和最大值。该例中由于计算的是灰度图像直方图,只有一个组分,因此第二个组分和第三个组分都设置为0:而第一组分直方图维数为 bins= 16,那么其灰度范围是[0,bins-1]。
  2. SetComponentOrigin(0,0,0)。该函数设置的是统计每个组分直方图时的起始灰度值。这里设置为 0,表示灰度从0开始统计直方图。由于vtkImageAccumulate 最大支持像素值为三个组分,因此这里也要设置三个参数。如果图像的灰度范围为[1000,2000],那么计算直方图时,其起始灰度应该设置为1000。
  3. SetComponentSpacing(16,0,0)。该函数设置直方图每个间隔代表的灰度范围,例如当一个图像灰度范围为[1000, 2000],统计直方图的间隔数 bins为 100时,对应的 space 应该设置为SetComponentSpacing(100,0, 0)。参数设置完毕,执行Update()即可计算直方图。前面已经提到过,vtkImageAccumulate的输出结果也是一个vtkImageData类型数据,这样就可以方便地访问图像的每个数据。需要注意的是,输出直方图图像的数据类型为int。

  这里顺便介绍一下直方图的显示。虽然vtkImageAccumulate 的输出类型为vtkImageData,但是并不能直接以图像的方式进行显示。VTK中的vtkBarChartActor 类用来显示条形图,可以利用它来显示直方图。但是该类接收的数据类型为vtkDataObject类型,因此需要先对直方图数据进行类型转换:先将直方图数组存储到 vtkIntArray数组frequencics 中,然后通过vtkDataObjcct 函数 GetFieldData()->AddArray(frequencies)将其添加到 vtkDataObject 对象中。

vtkBarChartActor 对象接收vtkDataObject对象作为输入,另外还需要设置图表的名字、颜色等。这里需要注意两个函数:

barChart->GetPositionCoordinate0->SetValue(0.05,0.05,0.0);
barChart>GetPosition2Coordinate0->SetValue(0.95,0.95,0.0);

  这里设置的是窗口中显示图表的所在矩形的左下角点和右上角点坐标。VTK的坐标系原点位于左下角点,设置时需要格外注意。设置完毕,即可定义相应的vtkRenderer、vtkRenderWindow和 vtkRenderWindowInteractor 对象以显示图像直方图。本示例的运行结果如图所示。

3、彩色直方图

  彩色图像有三个颜色通道,因此需要提取RGB三个通道数据分别计算直方图。每个通道计算直方图的方法与灰度图像直方图的计算方法一致。

在这里插入图片描述

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);// VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkImageAccumulate.h>
#include <vtkImageData.h>
#include <vtkImageExtractComponents.h>
#include <vtkBMPReader.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkXYPlotActor.h>
#include <vtkAxisActor2D.h>
#include <vtkProperty2D.h>
#include <vtkTextProperty.h>//测试图像:../data/lena.bmp
int main(int argc, char* argv[])
{vtkSmartPointer<vtkBMPReader> reader =vtkSmartPointer<vtkBMPReader>::New();reader->SetFileName ("../data/lena.bmp");reader->Update();int numComponents = reader->GetOutput()->GetNumberOfScalarComponents();vtkSmartPointer<vtkXYPlotActor> plot = vtkSmartPointer<vtkXYPlotActor>::New();plot->ExchangeAxesOff();plot->SetLabelFormat( "%g" );plot->SetXTitle( "Intensity" );plot->SetYTitle( "Frequency" );plot->SetXValuesToValue();plot->GetProperty()->SetColor(0.0, 0.0, 0.0);plot->GetAxisLabelTextProperty()->SetColor(0.0, 0.0, 0.0);plot->GetAxisTitleTextProperty()->SetColor(0.0, 0.0, 0.0);double colors[3][3] = {{ 1, 0, 0 },{ 0, 1, 0 },{ 0, 0, 1 } };const char* labels[3] = { "Red", "Green", "Blue" };int xmax = 0;int ymax = 0;for( int i = 0; i < numComponents; ++i ){vtkSmartPointer<vtkImageExtractComponents> extract = vtkSmartPointer<vtkImageExtractComponents>::New();extract->SetInputConnection( reader->GetOutputPort() );extract->SetComponents( i );extract->Update();double range[2];extract->GetOutput()->GetScalarRange( range );int extent = static_cast<int>(range[1])-static_cast<int>(range[0])-1;vtkSmartPointer<vtkImageAccumulate> histogram = vtkSmartPointer<vtkImageAccumulate>::New();histogram->SetInputConnection( extract->GetOutputPort() );histogram->SetComponentExtent( 0,extent, 0,0, 0,0);histogram->SetComponentOrigin( range[0],0,0 );histogram->SetComponentSpacing( 1,0,0 );histogram->SetIgnoreZero( 1 );histogram->Update();if( range[1] > xmax ) { xmax = range[1];}if( histogram->GetOutput()->GetScalarRange()[1] > ymax ) {ymax = histogram->GetOutput()->GetScalarRange()[1];}plot->AddDataSetInput( histogram->GetOutput() );plot->SetPlotColor(i,colors[i]);plot->SetPlotLabel(i,labels[i]);plot->LegendOn();}plot->SetXRange( 0, xmax);plot->SetYRange( 0, ymax);vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();renderer->AddActor(plot);renderer->SetBackground(1.0, 1.0, 1.0);vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();renderWindow->AddRenderer( renderer );renderWindow->SetSize(640, 480);renderWindow->Render();renderWindow->SetWindowName("ImageAccumulateExample2");vtkSmartPointer<vtkRenderWindowInteractor> interactor =vtkSmartPointer<vtkRenderWindowInteractor>::New();interactor->SetRenderWindow( renderWindow );interactor->Initialize();interactor->Start(); return EXIT_SUCCESS;
}

  该例先通过 vtkImageExtractComponents 来提取每个组分图像,再利用 vtkImageAccumulate统计每个组分的直方图。在本例中计算直方图的间隔取(1,0,0),即每个灰度计算统计一个频率,而且灰度起点为图像的最小灰度值。同时,SetIgnoreZero(1)设置在统计直方图时,像素值为 0的像素不进行统计。

  在灰度图像直方图示例中使用vtkBarChartActor柱状图来显示直方图,本例中则使用vtkXYPlotActor 曲线来表示直方图,这里做一简单介绍。vtkXYPlotActor类可以用来显示二维曲线,它可以接收多个输入数据,如本例中输入了三条曲线,分别是图像红色分量的直方图曲线、绿色分量的直方图曲线和蓝色分量的直方图曲线。SetXRange()和 SetYRange()用来设置X轴和Y轴的数据范围,另外还可以设置X轴和Y轴的名字、曲线的标题等属性(详细信息可以查阅 vtkXYPlotActor 类的文档)。

  vtkXYPlotActor 类是一个 vtkActor2D 的子类,因此定义相应的 vtkRenderer、vtkRenderWindow 和vtkRenderWindowInteractor 对象建立可视化管道即可显示图像直方图曲线。本示例的运行结果如图5-23 所示,其中,红色曲线代码红色分量的直方图,绿色代表绿色分量的直方图曲线,蓝色代表蓝色分量的直方图曲线。


http://www.ppmy.cn/news/1556074.html

相关文章

Windows系统VSCode 搭建ESP-IDF环境

VS Code&#xff0c;安装ESP-IDF插件 快捷键CTRLSHIFTP&#xff0c;弹出显示所有命令的窗口&#xff0c;选择ESP-IDF的欢迎 使用第一个选项&#xff0c;要选择一个ESP-IDF版本&#xff0c;选最新的就行 点击Install,等待下载 提示安装成功&#xff0c;如果过程中出现python已存…

【设计模式】享元模式(Flyweight Pattern)

享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过共享尽可能多的对象来有效支持大量细粒度的对象。这个模式主要用于减少内存使用和提高性能&#xff0c;特别是在需要创建大量相似对象的场景中。享元模式的核心思想是将对象的状态分为…

Perl 引用

Perl 引用 Perl&#xff0c;作为一种灵活而强大的编程语言&#xff0c;广泛用于系统管理、网络编程、GUI开发等领域。在Perl编程中&#xff0c;引用&#xff08;References&#xff09;是一个核心概念&#xff0c;它允许变量引用其他数据&#xff0c;从而创建复杂的数据结构&a…

RPC 服务与 gRPC 的入门案例

RPC 协议 RPC&#xff08;Remote Procedure Call Protocol&#xff09;即远程过程调用协议&#xff0c;它是一种通过网络从远程计算机程序上请求服务的协议&#xff0c;允许一个计算机程序可以像调用本地服务一样调用远程服务 。 RPC的主要作用是不同的服务间方法调用就像本地…

Chrome webdriver下载-避坑

WebDriver以原生的方式驱动浏览器&#xff0c;不需要调整环境变量。 一、window版 1.chrome和chromedriver下载地址&#xff1a; Chrome for Testing availability 我下载的是如下两个安装包&#xff0c;解压即可。 2.导包 pip install selenium然后用python代码引用即可…

离散数学---随机漫步

本文根据 MIT 计算机科学离散数学课程整理&#xff08;Lecture 25&#xff09;。 赌徒破产问题&#xff08;Gamblers Ruin&#xff09; 问题描述 初始为 n 元&#xff0c;对于每一次独立的赌注&#xff0c;都有 p 的概率赢得 1 元&#xff0c;(1-p) 的概率输掉 1 元。当输完…

D7000 低电压立体声手机功放电路芯片,电源纹波抑制比高静态电流低,内置节电模式开关和静噪开关 外接元件少所需外围元件少

概述&#xff1a; D7000低电压立体声手机功放电路。 主要特点&#xff1a; ● 静态电流低 ● 电源纹波抑制比高 ● 工作电压低 ● 内置节电模式开关和静噪开关 ● 外接元件少所需外围元件少 ● 封装形式: SSOP10 应用&#xff1a; ● 便携式视盘播放器(DISCMAN) ● 便携式迷…

华为云联合中国信通院发布首个云计算智能化可观测性能力成熟度模型标准

2024年12月3日&#xff0c;由全球数字经济大会组委会主办&#xff0c;中国信息通信研究院&#xff08;以下简称“中国信通院”&#xff09;、中国通信企业协会承办的2024全球数字经济大会云AI计算国际合作论坛在北京成功召开。本次会议中&#xff0c;华为云联合中国信通院等单位…