7、灰色图转彩色图像(查表映射):

灰色图转化成彩色图,实际上是将灰色图的不同黑白程度对应到不同的其他颜色,是一种颜色一一对应的方法,在实际中,有的图片保存也有这种方式,里面保存了一张表,像素点保存的是索引值。

#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageLuminance.h>
#include <vtkLookupTable.h>
#include <vtkImageMapToColors.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("flower.jpg");
	reader->Update();
	// 灰度图
	vtkSmartPointer<vtkImageLuminance> grayImg = vtkSmartPointer<vtkImageLuminance>::New();
	grayImg->SetInputConnection(reader->GetOutputPort());
	grayImg->Update();

	// 颜色表
	vtkSmartPointer<vtkLookupTable> colorTable = vtkSmartPointer<vtkLookupTable>::New();
	colorTable->SetRange(0.0, 255.0);	// 对应灰色图的范围,标量范围(0~255)
	// 实际上,下面三行将0~255对应到了整个HSI色域空间
	colorTable->SetHueRange(0, 1);			// 对应色相,色调范围
	colorTable->SetSaturationRange(0, 1);	// 饱和度范围
	colorTable->SetValueRange(0, 1);		// 对应的值范围(如果都是0,则全部映射为黑色)
	colorTable->Build();
	// 创建映射
	vtkSmartPointer<vtkImageMapToColors> colorMap = vtkSmartPointer<vtkImageMapToColors>::New();
	colorMap->SetInputConnection(reader->GetOutputPort());
	colorMap->SetLookupTable(colorTable);
	colorMap->Update();
	// 
	vtkSmartPointer<vtkImageActor> origActor = vtkSmartPointer<vtkImageActor>::New();
	origActor->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkImageActor> colorActor = vtkSmartPointer<vtkImageActor>::New();
	colorActor->SetInputData(colorMap->GetOutput());
	// 
	double origView[4] = { 0.0, 0.0, 0.5, 1.0 };
	double colorView[4] = { 0.5, 0.0, 1.0, 1.0 };
	vtkSmartPointer<vtkRenderer> origRender = vtkSmartPointer<vtkRenderer>::New();
	origRender->SetViewport(origView);
	origRender->AddActor(origActor);
	origRender->ResetCamera();
	origRender->SetBackground(1.0, 0.0, 0.0);

	vtkSmartPointer<vtkRenderer> colorRender = vtkSmartPointer<vtkRenderer>::New();
	colorRender->SetViewport(colorView);
	colorRender->AddActor(colorActor);
	colorRender->ResetCamera();
	colorRender->SetBackground(0.0, 0.0, 0.0);
	// 
	vtkSmartPointer<vtkRenderWindow> renderwindow = vtkSmartPointer<vtkRenderWindow>::New();
	renderwindow->AddRenderer(origRender);
	renderwindow->AddRenderer(colorRender);
	renderwindow->SetSize(640, 320);
	renderwindow->SetWindowName("GrayToColor");
	// 
	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style =
		vtkSmartPointer<vtkInteractorStyleImage>::New();
	rwi->SetInteractorStyle(style);
	rwi->SetRenderWindow(renderwindow);
	rwi->Initialize();

	rwi->Start();
	return 0;
}

灰度图像变为彩色opencv 灰度图转换为彩色_标量

 

vtkLookupTable并不是专门将灰度图映射到彩色,实际上,他的作用是将一定的标量范围映射到HSI色与空间的某个范围,如果输入的为彩色图像,实际上也是可以映射的,效果如下,和上面差别并不大。

灰度图像变为彩色opencv 灰度图转换为彩色_标量_02

vtkLookupTable是映射器对象用于将标量值映射到RGBA(红 - 绿 - 蓝 - 阿尔法)颜色规范或RGBA到标量值的对象。可以通过直接插入颜色值,或通过指定色调,饱和度,值和alpha范围以及生成表来创建颜色表。

在医学中,就可以使用这个将CT扫描的或则MRI扫描的人体图像,将骨骼,血管,神经,肌肉等不同组织映射成不同的颜色,提供给医生分析,甚至可以通过vtk建立三维模型,不同组织使用不同颜色,非常方便,是一项很实用的技术。

8、通过设置每个通道合成图像:

实际上,使用vtkImageAppendComponents可以合成图像,里面可以对一个通道添加多个输入,然后按照默认的方式,对不同输入做处理,例如,当总共有两个输入的时候,第一个输入就代表显示的图像,第二个代表现实的范围,有三个输入的时候,三个输入就分别代表红绿蓝三同时到,实际上还可以有四个输入,此时前三个输入代表红绿蓝,第四个就代表显示范围。例子如下:

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

int main()
{
	// 红色分量的位图
	vtkSmartPointer<vtkImageCanvasSource2D> red = vtkSmartPointer<vtkImageCanvasSource2D>::New();
	red->SetScalarTypeToUnsignedChar();
	red->SetNumberOfScalarComponents(1);
	red->SetExtent(0, 1000, 0, 1000, 0, 0);
	red->SetDrawColor(0, 0, 0, 0);
	red->FillBox(0, 1000, 0, 1000);
	red->SetDrawColor(255, 0, 0, 0);
	red->FillBox(250, 550, 250, 550);
	red->Update();
	// 绿色
	vtkSmartPointer<vtkImageCanvasSource2D> green = vtkSmartPointer<vtkImageCanvasSource2D>::New();
	green->SetScalarTypeToUnsignedChar();
	green->SetNumberOfScalarComponents(1);
	green->SetExtent(0, 1000, 0, 1000, 0, 0);
	green->SetDrawColor(0, 0, 0, 0);
	green->FillBox(0, 1000, 0, 1000);
	green->SetDrawColor(255, 0, 0, 0);
	green->FillBox(350, 650, 350, 650);
	green->Update();
	// 蓝色
	vtkSmartPointer<vtkImageCanvasSource2D> blue =
		vtkSmartPointer<vtkImageCanvasSource2D>::New();
	blue->SetScalarTypeToUnsignedChar();
	blue->SetNumberOfScalarComponents(1);
	blue->SetExtent(0, 1000, 0, 1000, 0, 0);
	blue->SetDrawColor(0, 0, 0, 0);
	blue->FillBox(0, 1000, 0, 1000);
	blue->SetDrawColor(255, 0, 0, 0);
	blue->FillBox(450, 750, 450, 750);
	blue->Update();
	// other
	vtkSmartPointer<vtkImageCanvasSource2D> ShowRect =
		vtkSmartPointer<vtkImageCanvasSource2D>::New();
	ShowRect->SetScalarTypeToUnsignedChar();
	ShowRect->SetNumberOfScalarComponents(1);
	ShowRect->SetExtent(0, 1000, 0, 1000, 0, 0);
	ShowRect->SetDrawColor(0, 0, 0, 0);
	ShowRect->FillBox(0, 1000, 0, 1000);
	ShowRect->SetDrawColor(255, 0, 0, 0);
	ShowRect->FillBox(200, 800, 200, 800);
	ShowRect->Update();
	// other
	vtkSmartPointer<vtkImageCanvasSource2D> other =
		vtkSmartPointer<vtkImageCanvasSource2D>::New();
	other->SetScalarTypeToUnsignedChar();
	other->SetNumberOfScalarComponents(1);
	other->SetExtent(0, 1000, 0, 1000, 0, 0);
	other->SetDrawColor(0, 0, 0, 0);
	other->FillBox(0, 1000, 0, 1000);
	other->SetDrawColor(255, 0, 0, 0);
	other->FillBox(499, 499, 501, 501);
	other->Update();
	// 从两个输入中获取组件并将它们合并为一个输出。如果Input1具有M个组件,并且Input2具有N个组件,则输出将具有M + N个组件,其中input1组件首先出现
	vtkSmartPointer<vtkImageAppendComponents> appendFilter = vtkSmartPointer<vtkImageAppendComponents>::New();
	// 端口0添加一个输入,调用此函数会清除端口0原有所有的输入
	appendFilter->SetInputConnection(0, red->GetOutputPort());		// 如果没有这些Add输入,则默认白色,第一个Set输入的算是范围
 	appendFilter->AddInputConnection(0, green->GetOutputPort());	// 如果只有两个元素,则第一个为显示,第二个为范围
 	appendFilter->AddInputConnection(0, blue->GetOutputPort());		// 如果有三个输入,则代表红绿蓝输入
	appendFilter->AddInputConnection(0, ShowRect->GetOutputPort());	// 如果有四个输入,则前三个代表红绿蓝,第四个代表显示的范围
//	appendFilter->AddInputConnection(0, other->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());

	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 };

	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("Image");

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style =
		vtkSmartPointer<vtkInteractorStyleImage>::New();

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

	return 0;
}

灰度图像变为彩色opencv 灰度图转换为彩色_灰度图像变为彩色opencv_03

还可以尝试不同的输入带来的不同效果。

9、提取图像感兴趣区域:

vtkExtractVOI可以对图像的某一部分区域做提取:

#include <vtkSmartPointer.h>
#include <vtkJPEGReader.h>
#include <vtkImageData.h>
#include <vtkExtractVOI.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("flower.jpg");
	reader->Update();

	int dim[3];
	reader->GetOutput()->GetDimensions(dim);	// 像素信息,尺寸
	// 感兴趣区域提取(vtkExtractVOI只可以用于提取图像数据)
	vtkSmartPointer<vtkExtractVOI> extractVOI = vtkSmartPointer<vtkExtractVOI>::New();
	extractVOI->SetInputConnection(reader->GetOutputPort());
	extractVOI->SetVOI(dim[0] / 4.0, 3.0*dim[0] / 4.0, dim[1] / 4.0, 3.0*dim[1] / 4.0, 0, 0);
	extractVOI->Update();
	// 
	vtkSmartPointer<vtkImageActor> origActor = vtkSmartPointer<vtkImageActor>::New();
	origActor->SetInputData(reader->GetOutput());	// GetOutput是vtkImageData
	vtkSmartPointer<vtkImageActor>  voiActor = vtkSmartPointer<vtkImageActor>::New();
	voiActor->SetInputData(extractVOI->GetOutput());
	// 
	double origView[4] = { 0, 0, 0.5, 1.0 };
	double voiView[4] = { 0.5, 0, 1.0, 1.0 };
	vtkSmartPointer<vtkRenderer> origRender = vtkSmartPointer<vtkRenderer>::New();
	origRender->SetViewport(origView);
	origRender->AddActor(origActor);
	origRender->ResetCamera();
	origRender->SetBackground(1.0, 0.0, 1.0);
	vtkSmartPointer<vtkRenderer> voiRender = vtkSmartPointer<vtkRenderer>::New();
	voiRender->SetViewport(voiView);
	voiRender->AddActor(voiActor);
	voiRender->ResetCamera();
	voiRender->SetBackground(0.0, 1.0, 1.0);
	// 
	vtkSmartPointer<vtkRenderWindow> renderwindow = vtkSmartPointer<vtkRenderWindow>::New();
	renderwindow->AddRenderer(origRender);
	renderwindow->AddRenderer(voiRender);
	renderwindow->SetSize(640, 320);
	renderwindow->SetWindowName("ExtractVolumeOfInterestFromImage");
	//设置交互
	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style =
		vtkSmartPointer<vtkInteractorStyleImage>::New();
	rwi->SetInteractorStyle(style);
	rwi->SetRenderWindow(renderwindow);
	rwi->Initialize();

	rwi->Start();
	return 0;
}

灰度图像变为彩色opencv 灰度图转换为彩色_彩色图像_04

如上图,将JPG图像的中间部分提取出来了。

10、vtk三维图像切片机:

三维切片机可以切割三维模型,切出来三维模型的某一个平面,切出来的这个平面实际上就是一副图像:

#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkDICOMImageReader.h>
#include <vtkMatrix4x4.h>
#include <vtkImageReslice.h>
#include <vtkLookupTable.h>
#include <vtkImageMapper3D.h>
#include <vtkImageMapToColors.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>

int main(int argc, char* argv[])
{
	vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New();
	reader->SetDirectoryName("F:\\Data\\36040001\\");	// 本身就是float的数据
	reader->SetDataByteOrderToLittleEndian();
	reader->Update();

	int extent[6];
	double spacing[3];
	double origin[3];

	reader->GetOutput()->GetExtent(extent);
	reader->GetOutput()->GetSpacing(spacing);
	reader->GetOutput()->GetOrigin(origin);

	double center[3];
	center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
	center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
	center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);

	static double axialElements[16] = {
		1, 0, 0, 0,
		0, 1, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1
	};

	vtkSmartPointer<vtkMatrix4x4> resliceAxes =
		vtkSmartPointer<vtkMatrix4x4>::New();
	resliceAxes->DeepCopy(axialElements);
	resliceAxes->SetElement(0, 3, center[0]);
	resliceAxes->SetElement(1, 3, center[1]);
	resliceAxes->SetElement(2, 3, center[2]);

	vtkSmartPointer<vtkImageReslice> reslice =
		vtkSmartPointer<vtkImageReslice>::New();
	reslice->SetInputConnection(reader->GetOutputPort());
	reslice->SetOutputDimensionality(2);
	reslice->SetResliceAxes(resliceAxes);
	reslice->SetInterpolationModeToLinear();

	vtkSmartPointer<vtkLookupTable> colorTable =
		vtkSmartPointer<vtkLookupTable>::New();
	colorTable->SetRange(0, 1000);
	colorTable->SetValueRange(0.0, 1.0);
	colorTable->SetSaturationRange(0.0, 0.0);
	colorTable->SetRampToLinear();
	colorTable->Build();
	vtkSmartPointer<vtkImageMapToColors> colorMap =
		vtkSmartPointer<vtkImageMapToColors>::New();
	colorMap->SetLookupTable(colorTable);
	colorMap->SetInputConnection(reslice->GetOutputPort());

	vtkSmartPointer<vtkImageActor> imgActor =
		vtkSmartPointer<vtkImageActor>::New();
	imgActor->GetMapper()->SetInputConnection(reslice->GetOutputPort());

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

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(renderer);
	renderWindow->Render();
	renderWindow->SetSize(640, 480);
	renderWindow->SetWindowName("Extract3Dslice");

	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleImage> imagestyle =
		vtkSmartPointer<vtkInteractorStyleImage>::New();
	rwi->SetInteractorStyle(imagestyle);
	rwi->SetRenderWindow(renderWindow);
	rwi->Initialize();
	rwi->Start();

	return 0;
}

灰度图像变为彩色opencv 灰度图转换为彩色_彩色图像_05

切出来的平面图如上,实际上原始数据是一幅三维图像,下面一节(11节)会看到。

11、vtk三维图像等值面合成图像及三维图像切片机:

切片机可以切割三维模型,切出来三维模型的某一个平面,切出来的这个平面实际上就是一副图像,下面代码只有少部分演示了切片机的使用,现实的切片实际上并非使用的切片机,而是显示的三维照片的某个部分而已。

#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkDICOMImageReader.h>
#include <vtkMatrix4x4.h> //
#include <vtkImageReslice.h>
#include <vtkLookupTable.h>
#include <vtkImageMapToColors.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkImageMapper3D.h>
#include <vtkMarchingCubes.h>
#include <vtkGeometryFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>

int main(int argc, char* argv[])
{
	vtkSmartPointer<vtkDICOMImageReader> pSrcImage = vtkSmartPointer<vtkDICOMImageReader>::New();
	pSrcImage->SetDirectoryName("F:\\Data\\36040001\\");	// 本身就是float的数据
//	pSrcImage->SetDataScalarTypeToUnsignedChar();
	pSrcImage->SetDataByteOrderToLittleEndian();
	pSrcImage->Update();

	int extent[6];			// 像素范围
	double spacing[3];		// 间距
	double origin[3];		// 起始点
	pSrcImage->GetOutput()->GetExtent(extent);
	pSrcImage->GetOutput()->GetSpacing(spacing);
	pSrcImage->GetOutput()->GetOrigin(origin);
	double center[3];	// 中心点 = 每个方向的起点 + 间距 * 层数 * 0.5
	center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
	center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
	center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);

	static double sagittalElements[16] = {		// 矢状面,移动矩阵位置全是0,默认不移动,只有旋转矩阵
		0, 0, -1, 0,
		1, 0, 0, 0,
		0, -1, 0, 0,
		0, 0, 0, 1 };
	static double axialElements[16] = {		// 轴向面,旋转矩阵(没有移动部分)
		1, 0, 0, 0,
		0, 1, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1
	};
	static double coronalElements[16] = {		// 冠状面
		1, 0, 0, 0,
		0, 0, 1, 0,
		0, -1, 0, 0,
		0, 0, 0, 1 };

	// 轴向面
	vtkSmartPointer<vtkMatrix4x4> resliceAxesSagittal = vtkSmartPointer<vtkMatrix4x4>::New();
	resliceAxesSagittal->DeepCopy(sagittalElements);
	resliceAxesSagittal->SetElement(0, 3, center[0]);	// 设置矩阵移动到3D图像中心
	resliceAxesSagittal->SetElement(1, 3, center[1]);
	resliceAxesSagittal->SetElement(2, 3, center[2]);
	vtkSmartPointer<vtkImageReslice> resliceSagittal = vtkSmartPointer<vtkImageReslice>::New();
	resliceSagittal->SetInputConnection(pSrcImage->GetOutputPort());
	resliceSagittal->SetOutputDimensionality(2);	// 2维切片机
	resliceSagittal->SetResliceAxes(resliceAxesSagittal);	// 切片矩阵
	resliceSagittal->SetInterpolationModeToLinear();	// 线性插值模式
	vtkSmartPointer<vtkMatrix4x4> resliceAxesAxial = vtkSmartPointer<vtkMatrix4x4>::New();
	resliceAxesAxial->DeepCopy(axialElements);
	resliceAxesAxial->SetElement(0, 3, center[0]);	// 设置矩阵移动到3D图像中心
	resliceAxesAxial->SetElement(1, 3, center[1]);
	resliceAxesAxial->SetElement(2, 3, center[2]);
	vtkSmartPointer<vtkImageReslice> resliceAxial = vtkSmartPointer<vtkImageReslice>::New();
	resliceAxial->SetInputConnection(pSrcImage->GetOutputPort());
	resliceAxial->SetOutputDimensionality(2);	// 2维切片机
	resliceAxial->SetResliceAxes(resliceAxesAxial);	// 切片矩阵
	resliceAxial->SetInterpolationModeToLinear();	// 线性插值模式
	vtkSmartPointer<vtkMatrix4x4> resliceAxesCoronal = vtkSmartPointer<vtkMatrix4x4>::New();
	resliceAxesCoronal->DeepCopy(coronalElements);
	resliceAxesCoronal->SetElement(0, 3, center[0]);	// 设置矩阵移动到3D图像中心
	resliceAxesCoronal->SetElement(1, 3, center[1]);
	resliceAxesCoronal->SetElement(2, 3, center[2]);
	vtkSmartPointer<vtkImageReslice> resliceCoronal = vtkSmartPointer<vtkImageReslice>::New();
	resliceCoronal->SetInputConnection(pSrcImage->GetOutputPort());
	resliceCoronal->SetOutputDimensionality(2);	// 2维切片机
	resliceCoronal->SetResliceAxes(resliceAxesCoronal);	// 切片矩阵
	resliceCoronal->SetInterpolationModeToLinear();	// 线性插值模式
	// 以上三个切片机切出来的,可以直接当Image使用,设置到vtkImageActor即可显示

	vtkSmartPointer<vtkLookupTable> colorTable = vtkSmartPointer<vtkLookupTable>::New();
	colorTable->SetTableRange(0, 1000);
	colorTable->SetValueRange(0.1, 1.0);
	colorTable->SetSaturationRange(0.0, 1.0);
	colorTable->SetHueRange(0.0, 1.0);
	colorTable->SetRampToLinear();
	colorTable->Build();

	vtkSmartPointer<vtkImageMapToColors> colorMapSagittal = vtkSmartPointer<vtkImageMapToColors>::New();
	colorMapSagittal->SetLookupTable(colorTable);
	colorMapSagittal->SetInputConnection(pSrcImage->GetOutputPort());
	vtkSmartPointer<vtkImageActor> imgActorSagittal = vtkSmartPointer<vtkImageActor>::New();
	imgActorSagittal->GetMapper()->SetInputConnection(colorMapSagittal->GetOutputPort());
	imgActorSagittal->SetDisplayExtent((extent[0] + extent[1]) / 2, (extent[0] + extent[1]) / 2, extent[2], extent[3], extent[4], extent[5]);
	imgActorSagittal->ForceOpaqueOn();

	vtkSmartPointer<vtkImageMapToColors> colorMapAxial = vtkSmartPointer<vtkImageMapToColors>::New();
	colorMapAxial->SetLookupTable(colorTable);
	colorMapAxial->SetInputConnection(pSrcImage->GetOutputPort());
	vtkSmartPointer<vtkImageActor> imgActorAxial = vtkSmartPointer<vtkImageActor>::New();
	imgActorAxial->GetMapper()->SetInputConnection(colorMapAxial->GetOutputPort());
	imgActorAxial->SetDisplayExtent(extent[0], extent[1], extent[2], extent[3], (extent[4] + extent[5]) / 2, (extent[4] + extent[5]) / 2);
	imgActorAxial->ForceOpaqueOn();

	vtkSmartPointer<vtkImageMapToColors> colorMapCoronal = vtkSmartPointer<vtkImageMapToColors>::New();
	colorMapCoronal->SetLookupTable(colorTable);
	colorMapCoronal->SetInputConnection(pSrcImage->GetOutputPort());
	vtkSmartPointer<vtkImageActor> imgActorCoronal = vtkSmartPointer<vtkImageActor>::New();
	imgActorCoronal->GetMapper()->SetInputConnection(colorMapCoronal->GetOutputPort());
	imgActorCoronal->SetDisplayExtent(extent[0], extent[1], (extent[2] + extent[3]) / 2, (extent[2] + extent[3]) / 2, extent[4], extent[5]);
	imgActorCoronal->ForceOpaqueOn();

	// 3D部分
	vtkSmartPointer<vtkActor> m_3DActorBone = vtkActor::New();
	vtkSmartPointer<vtkMarchingCubes> m_3DImageData = vtkMarchingCubes::New();
	m_3DImageData->SetInputConnection(pSrcImage->GetOutputPort());
	m_3DImageData->ComputeNormalsOn();
	m_3DImageData->SetValue(0, 275);	// CT数据下,骨骼对应的值大约275

	vtkSmartPointer<vtkGeometryFilter>geoVolumeBone = vtkGeometryFilter::New();
	geoVolumeBone->SetInputConnection(m_3DImageData->GetOutputPort());

	vtkSmartPointer<vtkPolyDataMapper> m_3DMapper = vtkPolyDataMapper::New();
	m_3DMapper->SetInputConnection(geoVolumeBone->GetOutputPort());
	m_3DMapper->ScalarVisibilityOff();
	m_3DMapper->Update();
	m_3DActorBone->SetMapper(m_3DMapper);
	m_3DActorBone->GetProperty()->SetColor(0.725, 0.478, 0.341);


	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	renderer->AddActor(imgActorSagittal);
	renderer->AddActor(imgActorAxial);
	renderer->AddActor(imgActorCoronal);
//	renderer->AddActor(m_3DActorBone);
	renderer->SetBackground(0.8, 0.8, 0.8);

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(renderer);
	renderWindow->Render();
	renderWindow->SetSize(640, 480);
	renderWindow->SetWindowName("Extract3DTest");

	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleTrackballCamera> imagestyle =
		vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	rwi->SetInteractorStyle(imagestyle);
	rwi->SetRenderWindow(renderWindow);
	renderWindow->Render();
	rwi->Initialize();
	rwi->Start();

	return 0;
}

灰度图像变为彩色opencv 灰度图转换为彩色_灰度图像变为彩色opencv_06

如上图,红色部分代表估值紧密部分,蓝色,绿色部分骨质比较疏松,其他灰色等,代表其他组织,由于CT扫描只能很好的分辨骨骼等高密度的物质,其他组织无法很好的表现,如果要看其他组织,可以使用MRI扫描的DICOM标准的数据。

灰度图像变为彩色opencv 灰度图转换为彩色_灰度图像变为彩色opencv_07

如上图,同时还可以建立三维模型,背后比较平的部分是床板(人体睡在床上扫描的CT),将代码略作改变,可以得到如下效果:

灰度图像变为彩色opencv 灰度图转换为彩色_灰度图像变为彩色opencv_08

12、三维图像相关的交互:

加上三维现实的交互,就可以自由切换切片机切得位置了,可以动态调整:

#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkDICOMImageReader.h>
#include <vtkMatrix4x4.h>
#include <vtkLookupTable.h>
#include <vtkImageMapToColors.h>
#include <vtkImageActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkImageMapper3D.h>
#include <vtkAxesActor.h>

class vtkVolumeImageInteractionCallback : public vtkCommand
{
public:
	static vtkVolumeImageInteractionCallback *New() //回调函数初始化函数
	{
		return new vtkVolumeImageInteractionCallback;
	}
	vtkVolumeImageInteractionCallback()
	{
		this->m_bSlicing = false;
		this->m_imgActorSagittal = nullptr;
		this->m_imgActorCoronal = nullptr;
		this->m_imgActorAxial = nullptr;
		this->Interactor = nullptr;
	}
	void SetImageActor(vtkImageActor* s, vtkImageActor* c, vtkImageActor*a)
	{
		this->m_imgActorSagittal = s;
		this->m_imgActorCoronal = c;
		this->m_imgActorAxial = a;
	}
	void SetInteractor(vtkRenderWindowInteractor *interactor)
	{
		this->Interactor = interactor;
	}
	vtkRenderWindowInteractor *GetInteractor()
	{
		return  this->Interactor;
	}
	virtual void Execute(vtkObject *, unsigned long event, void *)
	{
		vtkRenderWindowInteractor *interactor = GetInteractor();
		int lastPos[2];
		interactor->GetLastEventPosition(lastPos);
		int currPos[2];
		interactor->GetEventPosition(currPos);

		if (event == vtkCommand::RightButtonPressEvent)
		{
			this->m_bSlicing = 1; // 开始设置切片位置
		}
		else if (event == vtkCommand::RightButtonReleaseEvent)
		{
			this->m_bSlicing = 0; // 停止设置切片位置
		}
		else if (event == vtkCommand::MouseMoveEvent)
		{
			if (this->m_bSlicing)//检验鼠标左键已经按下 正在执行操作
			{
				//记下鼠标Y向变化的幅值大小
				int deltaX = lastPos[0] - currPos[0];
				int deltaY = lastPos[1] - currPos[1];

				int Pos[6] = { 0 };
				// 矢状面
				m_imgActorSagittal->GetDisplayExtent(Pos);
				Pos[0] -= deltaX; Pos[1] = Pos[0];
				m_imgActorSagittal->SetDisplayExtent(Pos);
				// 冠状面
				m_imgActorCoronal->GetDisplayExtent(Pos);
				Pos[2] -= deltaY; Pos[3] = Pos[2];
				m_imgActorCoronal->SetDisplayExtent(Pos);
				// 上面部分最好加上范围判断,超出范围显示不出的,vtk会报错

				interactor->Render();
			}
			else
			{
				vtkInteractorStyle *style = vtkInteractorStyle::SafeDownCast(
					interactor->GetInteractorStyle());
				if (style)
				{
					style->OnMouseMove();
				}
			}
		}
	}
private:
	bool m_bSlicing;
	vtkImageActor* m_imgActorSagittal;
	vtkImageActor* m_imgActorCoronal;
	vtkImageActor* m_imgActorAxial;
	vtkRenderWindowInteractor *Interactor;
};


int main(int argc, char* argv[])
{
	vtkSmartPointer<vtkDICOMImageReader> pSrcImage = vtkSmartPointer<vtkDICOMImageReader>::New();
	pSrcImage->SetDirectoryName("F:\\Data\\36040001\\");	// 本身就是float的数据
	pSrcImage->SetDataByteOrderToLittleEndian();
	pSrcImage->Update();

	int extent[6];			// 像素范围
	double spacing[3];		// 间距
	double origin[3];		// 起始点
	pSrcImage->GetOutput()->GetExtent(extent);
	pSrcImage->GetOutput()->GetSpacing(spacing);
	pSrcImage->GetOutput()->GetOrigin(origin);
	double center[3];	// 中心点 = 每个方向的起点 + 间距 * 层数 * 0.5
	center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
	center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
	center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);
	
	vtkSmartPointer<vtkLookupTable> colorTable = vtkSmartPointer<vtkLookupTable>::New();
	colorTable->SetTableRange(0, 1000);
	colorTable->SetValueRange(0.1, 1.0);
	colorTable->SetSaturationRange(0.0, 1.0);
	colorTable->SetHueRange(0.0, 1.0);
	colorTable->SetRampToLinear();
	colorTable->Build();

	vtkSmartPointer<vtkImageMapToColors> colorMapSagittal = vtkSmartPointer<vtkImageMapToColors>::New();
	colorMapSagittal->SetLookupTable(colorTable);
	colorMapSagittal->SetInputConnection(pSrcImage->GetOutputPort());
	vtkSmartPointer<vtkImageActor> imgActorSagittal = vtkSmartPointer<vtkImageActor>::New();
	imgActorSagittal->GetMapper()->SetInputConnection(colorMapSagittal->GetOutputPort());
	imgActorSagittal->SetDisplayExtent((extent[0] + extent[1]) / 2, (extent[0] + extent[1]) / 2, extent[2], extent[3], extent[4], extent[5]);
	imgActorSagittal->ForceOpaqueOn();

	vtkSmartPointer<vtkImageMapToColors> colorMapCoronal = vtkSmartPointer<vtkImageMapToColors>::New();
	colorMapCoronal->SetLookupTable(colorTable);
	colorMapCoronal->SetInputConnection(pSrcImage->GetOutputPort());
	vtkSmartPointer<vtkImageActor> imgActorCoronal = vtkSmartPointer<vtkImageActor>::New();
	imgActorCoronal->GetMapper()->SetInputConnection(colorMapCoronal->GetOutputPort());
	imgActorCoronal->SetDisplayExtent(extent[0], extent[1], (extent[2] + extent[3]) / 2, (extent[2] + extent[3]) / 2, extent[4], extent[5]);
	imgActorCoronal->ForceOpaqueOn();

	vtkSmartPointer<vtkImageMapToColors> colorMapAxial = vtkSmartPointer<vtkImageMapToColors>::New();
	colorMapAxial->SetLookupTable(colorTable);
	colorMapAxial->SetInputConnection(pSrcImage->GetOutputPort());
	vtkSmartPointer<vtkImageActor> imgActorAxial = vtkSmartPointer<vtkImageActor>::New();
	imgActorAxial->GetMapper()->SetInputConnection(colorMapAxial->GetOutputPort());
	imgActorAxial->SetDisplayExtent(extent[0], extent[1], extent[2], extent[3], (extent[4] + extent[5]) / 2, (extent[4] + extent[5]) / 2);
	imgActorAxial->ForceOpaqueOn();
	
	vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
	axes->SetTotalLength(100, 100, 100);
	axes->SetCylinderResolution(10);

	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	renderer->AddActor(imgActorSagittal);
	renderer->AddActor(imgActorAxial);
	renderer->AddActor(imgActorCoronal);
	renderer->AddActor(axes);
	renderer->SetBackground(0.8, 0.8, 0.8);

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(renderer);
	renderWindow->Render();
	renderWindow->SetSize(640, 480);
	renderWindow->SetWindowName("Extract3Dslice");

	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	vtkSmartPointer<vtkInteractorStyleTrackballCamera> imagestyle =
		vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	vtkSmartPointer<vtkVolumeImageInteractionCallback> cb =
		vtkSmartPointer<vtkVolumeImageInteractionCallback>::New();
	cb->SetImageActor(imgActorSagittal, imgActorCoronal, imgActorAxial);
	cb->SetInteractor(rwi);
	imagestyle->AddObserver(vtkCommand::MouseMoveEvent, cb);
	imagestyle->AddObserver(vtkCommand::RightButtonPressEvent, cb);
	imagestyle->AddObserver(vtkCommand::RightButtonReleaseEvent, cb);

	rwi->SetInteractorStyle(imagestyle);
	rwi->SetRenderWindow(renderWindow);
	renderWindow->Render();
	rwi->Initialize();
	rwi->Start();

	return 0;
}

灰度图像变为彩色opencv 灰度图转换为彩色_灰度图像变为彩色opencv_09

灰度图像变为彩色opencv 灰度图转换为彩色_灰度图像变为彩色opencv_10

如上图,两幅图是通过鼠标右键拖动达到的效果,鼠标拖动的X变化决定矢状面的移动,Y的变化决定冠状面的变化,轴向面一直保持不变。

如果要直接使用普通jpg图片,也可以尝试,通过鼠标拖动改变一幅jpg图片的位置,达到类似的效果,三实际上,上面演示的,位置和图像都在改变。