注:此文知识学习笔记,仅记录完整程序和实现结果,具体原理参见:
https://blog.csdn.net/www_doling_net/article/details/8541534
1、直接访问图像像素(索引法)
#include"vtkSmartPointer.h" #include"vtkImageData.h" #include"vtkBMPReader.h" #include"vtkImageViewer2.h" #include"vtkRenderer.h" #include"vtkRenderWindow.h" #include"vtkRenderWindowInteractor.h" int main(){ vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New(); //读取图像 reader->SetFileName("test.bmp"); reader->Update(); int dims[3]; reader->GetOutput()->GetDimensions(dims); int nbofcomp; nbofcomp = reader->GetOutput()->GetNumberOfScalarComponents(); 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 < 79 && i>31 && j>14 && j < 50){ unsigned char *pixel = (unsigned char*)(reader->GetOutput()->GetScalarPointer(i, j, k)); *pixel = 255 - *pixel; //将选择的区域设置成反色 *(pixel + 1) = 255 - *(pixel + 1); *(pixel + 2) = 255 - *(pixel + 2); } } } } vtkSmartPointer<vtkImageViewer2> imgViewer = vtkSmartPointer<vtkImageViewer2>::New(); //图像显示,vtkImageViewer2中封装了vtk图像显示的管线 imgViewer->SetInputData(reader->GetOutput());//区别于imgViewer->SetInputConnection(reader->GetOutputPort()); vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New(); imgViewer->SetupInteractor(rwi); imgViewer->Render(); imgViewer->GetRenderer()->ResetCamera();//设置相机 imgViewer->Render(); imgViewer->GetRenderer()->SetBackground(1,1,1);//设置背景 imgViewer->SetSize(640, 480); imgViewer->GetRenderWindow()->SetWindowName("VisitImagePixelDirectly");//窗口名称 rwi->Start(); return EXIT_SUCCESS; }
运行结果:
第二幅图像是将代码改为:
unsigned char *pixel = (unsigned char*)(reader->GetOutput()->GetScalarPointer(i, j, k));//GetScalarPointer获取访问图像像素值 //GetScalarPointer()函数返回的是void*类型,因此需要根据图像的实际类型进行强制转换 *pixel = 255 - *pixel; //将选择的区域设置成反色 /* *(pixel + 1) = 255 - *(pixel + 1); *(pixel + 2) = 255 - *(pixel + 2);*/
在这里,我们需要注意的一点是VTK中彩色图以及矢量图的存储方式,具体如下:
因此在修改RGB图像以及向量图像像素时,需要根据像素的元组的组分数目来访问。上例中,需要修改每个像素的RGB值时,首先获得第(i, j, k)个像素的地址也就是R值的地址,然后将地址加1来访问后续G值以及B值。如果对于像素的元组组分不确定时,可以通过函数GetNumberOfScalarComponents()来获取。
2、迭代器方法访问图像像素
/***********************************************************/ //迭代器方法访问图像像素 vtkImageIterator类(此类是一个模板类,使用时,需要提供迭代的图像像素类型以及迭代的区域大小) #include <vtkSmartPointer.h> #include <vtkBMPReader.h> #include <vtkImageData.h> #include <vtkImageIterator.h> #include <vtkImageViewer2.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> int main() { vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New();//读取bmp图像 reader->SetFileName("test.bmp"); reader->Update(); int subRegion[6] = { 31, 79, 14, 50, 0, 0 }; vtkImageIterator<unsigned char> iter(reader->GetOutput(), subRegion);//定义一个子区域,iter的两个参数(一个是要访问的图像,另外一个是访问的图像区域) while (!iter.IsAtEnd()) { unsigned char *inSI = iter.BeginSpan(); //组分迭代时,inSI = it.BeginSpan()获取第一个组分 unsigned char *inSIEnd = iter.EndSpan(); // 表示组分迭代完毕 while (inSI != inSIEnd) //这个循环判断的是当前像素的组分是否迭代完毕,组分就是RGB三组,不同图像组分不一样 { *inSI = 255 - *inSI; //像素值取反 ++inSI; //不断迭代组分 } iter.NextSpan(); } vtkSmartPointer<vtkImageViewer2> imgViewer = vtkSmartPointer<vtkImageViewer2>::New(); imgViewer->SetInputConnection(reader->GetOutputPort()); vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New(); imgViewer->SetupInteractor(rwi); imgViewer->Render(); imgViewer->GetRenderer()->ResetCamera(); imgViewer->Render(); imgViewer->GetRenderer()->SetBackground(1.0, 1.0, 1.0); imgViewer->SetSize(640, 480); imgViewer->GetRenderWindow()->SetWindowName("VisitImagePixelIteratively"); rwi->Start(); return 0; }运行结果:
参考资料:
1.《The Visualization Toolkit – AnObject-Oriented Approach To 3D Graphics (4th Edition)》
2. 张晓东, 罗火灵. VTK图形图像开发进阶[M]. 机械工业出版社, 2015.