【QT+VTK 学习笔记】07:图像信息的访问与修改、图像类型转换、图像颜色映射

前言

“VTK图形图像开发进阶_张晓东_罗火灵”的学习笔记。
东灵工作室 教程系列导航:http://blog.csdn.net/www_doling_net/article/details/8763686

学习资料

VTK官网学习地址:https://vtk.org/doc/nightly/html/

学习笔记

VTK图像基本操作

熟练掌握这些基本操作有助于使用VTK进行图 像处理应用程序的快速开发。

图像信息的访问与修改

利用vtklmageData的方法
获取图像维数、图像原点、像素间隔。

	vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New();
	reader->SetFileName ( argv[1] );
	reader->Update();

	int dims[3];
	reader->GetOutput()->GetDimensions(dims);
	std::cout<<"图像维数:" <<dims[0]<<" "<<dims[1]<<" "<<dims[2]<<std::endl;

	double origin[3];
	reader->GetOutput()->GetOrigin(origin);
	std::cout<<"图像原点:" <<origin[0]<<" "<<origin[1]<<" "<<origin[2]<<std::endl;

	double spaceing[3];
	reader->GetOutput()->GetSpacing(spaceing);
	std::cout<<"像素间隔:" <<spaceing[0]<<" "<<spaceing[1]<<" "<<spaceing[2]<<std::endl;

利用类 vtkChangelmagelnformation
修改图像的原点、像素间隔以及范围、实现图像平移缩放等功能

	vtkSmartPointer<vtkImageChangeInformation> changer = vtkSmartPointer<vtkImageChangeInformation>::New();
	changer->SetInputData(reader->GetOutput());
	changer->SetOutputOrigin(100, 100, 0);
	changer->SetOutputSpacing(5,5,1);
	changer->SetCenterImage(1);
	changer->Update();

	changer->GetOutput()->GetDimensions(dims);
	std::cout<<"修改后图像维数:" <<dims[0]<<" "<<dims[1]<<" "<<dims[2]<<std::endl;
	changer->GetOutput()->GetOrigin(origin);
	std::cout<<"修改后图像原点:" <<origin[0]<<" "<<origin[1]<<" "<<origin[2]<<std::endl;
	changer->GetOutput()->GetSpacing(spaceing);
	std::cout<<"修改后像素间隔:" <<spaceing[0]<<" "<<spaceing[1]<<" "<<spaceing[2]<<std::endl;

图像像素值的访问与修改

方法一 直接访问vtklmageData的数据数组 GetScalarPointer
在这里插入图片描述

	vtkSmartPointer<vtkBMPReader> reader =
		vtkSmartPointer<vtkBMPReader>::New();
	reader->SetFileName(argv[1]);
	reader->Update();

	int dims[3];
	reader->GetOutput()->GetDimensions(dims);	//得到图像大小

	int nbOfComp;
	nbOfComp = reader->GetOutput()->GetNumberOfScalarComponents();	//获取像素的元组组分数(是灰度图、梯度图、RGB图)

	for(int k=0; k<dims[2]; k++)
	{
		for(int j=0; j<dims[1]; j++)
		{
			for(int i=0; i<dims[0]; i++)
			{
				if(i<100 && j<100)
				{
					unsigned char * pixel = (unsigned char *) ( reader->GetOutput()->GetScalarPointer(i, j, k) );
					*pixel = 0;
					*(pixel+1) = 0;
					*(pixel+2) = 0;
				}
			}
		}
	}

方法二 vtklmagelterator类实现迭代器方法访问图像像素
在这里插入图片描述

	vtkSmartPointer<vtkBMPReader> reader =
		vtkSmartPointer<vtkBMPReader>::New();
	reader->SetFileName ( argv[1] );
	reader->Update();

	int subRegion[6] = {0,300, 0, 300, 0, 0};	//定义一个子区域(不能超过图像大小范围)
	//根据图像类型unsigned char 定义一个图像迭代器it,两个参数(要访问的图像、要访问的图像区域)
	vtkImageIterator<unsigned char> it(reader->GetOutput(), subRegion);	

	while(!it.IsAtEnd())
	{
		unsigned char *inSI = it.BeginSpan();	//获取第一个组分
		unsigned char *inSIEnd = it.EndSpan();	//表示组分迭代完毕

		while(inSI != inSIEnd)					//判断是否结束
		{
			*inSI = 255-*inSI;
			++inSI;								//迭代组分
		}
		it.NextSpan();							//组分迭代完毕后继续迭代像素it至下一个元祖
	}

图像类型转换

常用的图像算子(例如梯度算子) 在计算时出于精度的考虑,会将结果存储为float或double类型,但在图像显示时,一般要求 图像为unsigned char类型,这时就需要对数据类型曲行转换。
vtklmageCast
VTK中最简单的类型转换Filter 就是vtklmageCast。

	vtkSmartPointer<vtkMetaImageReader> reader = vtkSmartPointer<vtkMetaImageReader>::New();
	reader->SetFileName(argv[1]);
	reader->Update();

	vtkSmartPointer<vtkImageCast> imageCast = vtkSmartPointer<vtkImageCast>::New();
	imageCast->SetInput((vtkDataObject *)reader->GetOutput());
	imageCast->SetOutputScalarTypeToFloat();

只再要把SetOutputScalarTypeToxxx()设置成相应的输出类型即可。
该类有一个变量ClampOverflow用来表示是否需要截断数据,默认情况下,该变量值为0。当设置 其值为1时,输出的像素值不能超过输出类型的最大值,超过时自动截断至最大值。
VTK中也不推荐使用该类.例如一幅double类型的图像,其数值范围为「-1,1],如果需要 图像转换为unsigned char类,无法使用该Filter进行转换。这时就需要用到 vtklmageShiRScale。
vtklmageShiRScale
vtklmageShiRScale可以指定偏移和比例参数来对输入图像数据进行操作例如一幅 double类型的图像,其数值范围为[-1,1],如果将其转换为unsigned char类型,需要设置shift值为+1,比例系数设置为127.5,那么输入数据-1映射为(-1+1)X 127.5 = 0;而+1则为 ( + 1 + 1)X 127.5=255。对应代码如下

    vtkSmartPointer<vtkImageShiftScale> shitScaleFilter = vtkSmartPointer<vtkImageShiftScale>::New();
    shitScaleFilter->SetInputConnection(reader->GetOutputPort());
    shitScaleFilter->SetOutputScalarTypeToUnsignedChar();
    shitScaleFilter->SetShift(1);       //设置偏移量
    shitScaleFilter->SetScale(255/2.0); //设置缩放量
    shitScaleFilter->Update();

该类中也有一个変量ClampOverflow其值为1时,如果输出值超过输出类型的最大值时,则自动截断。例如,输出类型为unsigned char, 数值范围为0〜255,当输出像素值为257时,该类会动截断取值为255,默认情况变量ClampOverflow的值为0,此时,当输出值为257,输出类型为unsigned char时,该类不会将其截断,而是会产生溢出,最好取值为2。

图像颜色映射

图像灰度映射
vtklmageLuminance负责将一个RGB彩色图像转换为一个单组分的灰度图像。
映射公式为
在这里插入图片描述

	vtkSmartPointer<vtkImageLuminance> luminanceFilter =  vtkSmartPointer<vtkImageLuminance>::New();
	luminanceFilter->SetInput(reader->GetOutput());
	luminanceFilter->Update();

提取颜色组分
VTK中利用vtklmageExtractComponents可以方便地提取彩色图像的各个颜色组分。使 用该类时只需要设置要提取的组分序号即可。

    vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New();
	reader->SetFileName (argv[1]);
 
	vtkSmartPointer<vtkImageExtractComponents> extractRedFilter = vtkSmartPointer<vtkImageExtractComponents>::New();
	extractRedFilter->SetInputConnection(reader->GetOutputPort());
	extractRedFilter->SetComponents(0);
	extractRedFilter->Update();
 
	vtkSmartPointer<vtkImageExtractComponents> extractGreenFilter = vtkSmartPointer<vtkImageExtractComponents>::New();
	extractGreenFilter->SetInputConnection(reader->GetOutputPort());
	extractGreenFilter->SetComponents(1);
	extractGreenFilter->Update();
 
	vtkSmartPointer<vtkImageExtractComponents> extractBlueFilter = vtkSmartPointer<vtkImageExtractComponents>::New();
	extractBlueFilter->SetInputConnection(reader->GetOutputPort());
	extractBlueFilter->SetComponents(2);
	extractBlueFilter->Update();

在这里插入图片描述
图像彩色映射
图像彩色映射的原理是:先生成一个颜色查找表,然后根据图像像素的一个标量值在颜色查找表中查找对应的颜色,并用新颜色值替代原来的像素值,用vtkLookUpTable 生成颜色查找表,以下代码展示如何进行彩色映射。
参考文献:https://blog.csdn.net/qq_40734628/article/details/88091327
实例一

#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
#include <vtkVersion.h>
#include <vtkSmartPointer.h>

#include <vtkActor.h>
#include <vtkDelaunay2D.h>
#include <vtkLookupTable.h>
#include <vtkMath.h>
#include <vtkPointData.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkXMLPolyDataWriter.h>

// For compatibility with new VTK generic data arrays
#ifdef vtkGenericDataArray_h
#define InsertNextTupleValue InsertNextTypedTuple
#endif

int main(int, char *[])
{
    // Create a grid of points (height/terrian map)
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();

    unsigned int GridSize = 20;
    double xx, yy, zz;
    //随机生成一个三维坐标,并插入vtkPoints中
    for(unsigned int x = 0; x < GridSize; x++)
    {
        for(unsigned int y = 0; y < GridSize; y++)
        {
            xx = x + vtkMath::Random(-.2, .2);
            yy = y + vtkMath::Random(-.2, .2);
            zz = vtkMath::Random(-.5, .5);
            points->InsertNextPoint(xx, yy, zz);
        }
    }

    //多边形数据集 Add the grid points to a polydata object
    vtkSmartPointer<vtkPolyData> inputPolyData = vtkSmartPointer<vtkPolyData>::New();
    inputPolyData->SetPoints(points);

    //三角化之后,每个面片都是一个三角形,由三个点确定一个三角形  Triangulate the grid points
    vtkSmartPointer<vtkDelaunay2D> delaunay = vtkSmartPointer<vtkDelaunay2D>::New();
    //根据vtk的版本来选择数据输入方式
#if VTK_MAJOR_VERSION <= 5
    delaunay->SetInput(inputPolyData);
#else
    delaunay->SetInputData(inputPolyData);
#endif
    delaunay->Update();
    vtkPolyData* outputPolyData = delaunay->GetOutput();

    //这个数组里面存放了六个坐标范围极值
    //分别是x轴方向最小最大坐标值
    //y轴方向最小最大坐标值
    //Z轴方向最小最大坐标值
    double bounds[6];
    outputPolyData->GetBounds(bounds);

    // Find min and max z
    //数组最后两个值存放的是Z轴方向最小最大坐标值
    double minz = bounds[4];
    double maxz = bounds[5];

    std::cout << "minz: " << minz << std::endl;
    std::cout << "maxz: " << maxz << std::endl;

    //颜色操作表 Create the color map
    vtkSmartPointer<vtkLookupTable> colorLookupTable = vtkSmartPointer<vtkLookupTable>::New();
    //这里如果不设置大小范围的话,默认的范围是0-1
    //这里根据自己的代码需要灵活设置颜色映射的范围值
    colorLookupTable->SetTableRange(minz, maxz);
    colorLookupTable->Build();

    // Generate the colors for each point based on the color map
    vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
    colors->SetNumberOfComponents(3);
    colors->SetName("Colors");

    //20*20
    std::cout << "There are " << outputPolyData->GetNumberOfPoints() << " points." << std::endl;

    for(int i = 0; i < outputPolyData->GetNumberOfPoints(); i++)
    {
        double p[3];
        outputPolyData->GetPoint(i,p);

        double dcolor[3];
        //根据z轴的坐标值的数据来获得一个颜色标量值
        //(使用lookupTable颜色查找表来查找)
        //查找到的标量值放入dcolor中
        colorLookupTable->GetColor(p[2], dcolor);
        std::cout << "dcolor: "
                  << dcolor[0] << " "
                  << dcolor[1] << " "
                  << dcolor[2] << std::endl;
        unsigned char color[3];
        //把获取到的颜色标量转换为颜色值,并存入颜色标量colors中
        for(unsigned int j = 0; j < 3; j++)
        {
            color[j] = static_cast<unsigned char>(255.0 * dcolor[j]);
        }
        std::cout << "color: "
                  << (int)color[0] << " "
                  << (int)color[1] << " "
                  << (int)color[2] << std::endl;

        colors->InsertNextTupleValue(color);
    }

    //给每一个点设置一个颜色,这个颜色是根据z轴的大小来设置的
    outputPolyData->GetPointData()->SetScalars(colors);

    // Create a mapper and actor
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
#if VTK_MAJOR_VERSION <= 5
    mapper->SetInputConnection(outputPolyData->GetProducerPort());
#else
    mapper->SetInputData(outputPolyData);
#endif

    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);

    // Create a renderer, render window, and interactor
    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
    vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(renderer);
    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetRenderWindow(renderWindow);

    // Add the actor to the scene
    renderer->AddActor(actor);
    renderer->SetBackground(0.1, 0.2, 0.3);

    // Render and interact
    renderWindow->Render();
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

在这里插入图片描述
实例二
在这里插入图片描述
在这里插入图片描述颜色合成
VTK也支持将多个灰度图像合并成一个彩色图像。vtklmageAppendComponents类实现

#include <QApplication>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)

#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkImageAppendComponents.h>
#include <vtkImageCanvasSource2D.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkJPEGReader.h>
#include <vtkImageActor.h>

int main(int, char *[])
{
    vtkSmartPointer<vtkImageCanvasSource2D> red =
        vtkSmartPointer<vtkImageCanvasSource2D>::New();
    red->SetScalarTypeToUnsignedChar();
    red->SetNumberOfScalarComponents(1);    //组分数为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();
    //分别传入r,g,b data  共三个组分
    appendFilter->SetInputConnection(0, red->GetOutputPort());
    appendFilter->AddInputConnection(0, green->GetOutputPort());
    appendFilter->AddInputConnection(0, blue->GetOutputPort());
    appendFilter->Update();

    vtkSmartPointer<vtkImageActor> redActor =
        vtkSmartPointer<vtkImageActor>::New();
    redActor->SetInputData(red->GetOutput());

    vtkSmartPointer<vtkImageActor> greenActor = vtkSmartPointer<vtkImageActor>::New();
    greenActor->SetInputData(green->GetOutput());

    vtkSmartPointer<vtkImageActor> blueActor = vtkSmartPointer<vtkImageActor>::New();
    blueActor->SetInputData(blue->GetOutput());

    vtkSmartPointer<vtkImageActor> combinedActor = vtkSmartPointer<vtkImageActor>::New();
    combinedActor->SetInputData(appendFilter->GetOutput());

    // Define viewport ranges
    // (xmin, ymin, xmax, ymax)
    double redViewport[4] = {0.0, 0.0, 0.25, 1.0};
    double greenViewport[4] = {0.25, 0.0, 0.5, 1.0};
    double blueViewport[4] = {0.5, 0.0, 0.75, 1.0};
    double combinedViewport[4] = {0.75, 0.0, 1.0, 1.0};

    // Setup renderers
    vtkSmartPointer<vtkRenderer> redRenderer =
        vtkSmartPointer<vtkRenderer>::New();
    redRenderer->SetViewport(redViewport);
    redRenderer->AddActor(redActor);
    redRenderer->ResetCamera();
    redRenderer->SetBackground(1.0, 1.0, 1.0);

    vtkSmartPointer<vtkRenderer> greenRenderer =
        vtkSmartPointer<vtkRenderer>::New();
    greenRenderer->SetViewport(greenViewport);
    greenRenderer->AddActor(greenActor);
    greenRenderer->ResetCamera();
    greenRenderer->SetBackground(1.0, 1.0, 1.0);

    vtkSmartPointer<vtkRenderer> blueRenderer =
        vtkSmartPointer<vtkRenderer>::New();
    blueRenderer->SetViewport(blueViewport);
    blueRenderer->AddActor(blueActor);
    blueRenderer->ResetCamera();
    blueRenderer->SetBackground(1.0, 1.0, 1.0);

    vtkSmartPointer<vtkRenderer> combinedRenderer =
        vtkSmartPointer<vtkRenderer>::New();
    combinedRenderer->SetViewport(combinedViewport);
    combinedRenderer->AddActor(combinedActor);
    combinedRenderer->ResetCamera();
    combinedRenderer->SetBackground(1.0, 1.0, 1.0);

    vtkSmartPointer<vtkRenderWindow> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(redRenderer);
    renderWindow->AddRenderer(greenRenderer);
    renderWindow->AddRenderer(blueRenderer);
    renderWindow->AddRenderer(combinedRenderer);
    renderWindow->SetSize(1200, 300);
    renderWindow->Render();
    renderWindow->SetWindowName("ImageAppendComponentsExample");

    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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值