【VTK】读取一张dicom—计算窗宽窗位并动态交互显示像素位置和像素值

参考VTK官网:https://vtk.org/Wiki/VTK/Examples/Cxx/Images/PickPixel2

结果显示:

#include <vtkVersion.h>
#include <vtkAssemblyPath.h>
#include <vtkCell.h>
#include <vtkCommand.h>
#include <vtkCornerAnnotation.h>
#include <vtkImageActor.h>
#include <vtkImageData.h>
#include <vtkImageViewer2.h>
#include <vtkInteractorStyleImage.h>
#include <vtkTIFFReader.h>
#include <vtkPointData.h>
#include <vtkPropPicker.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkTextProperty.h>
#include <vtkImageNoiseSource.h>
#include <vtkImageCast.h>
#include <vtkMath.h>
#include <vtkDICOMImageReader.h>

#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);


// Template for image value reading
template<typename T>
void vtkValueMessageTemplate(vtkImageData* image, int* position,
	std::string& message)
{
	T* tuple = ((T*)image->GetScalarPointer(position));
	int components = image->GetNumberOfScalarComponents();
	for (int c = 0; c < components; ++c)
	{
		message += vtkVariant(tuple[c]).ToString();
		if (c != (components - 1))
		{
			message += ", ";
		}
	}
	message += " )";
}

// The mouse motion callback, to pick the image and recover pixel values
// 自定义交互方式
class vtkImageInteractionCallback : public vtkCommand
{
public:
	static vtkImageInteractionCallback *New()
	{
		return new vtkImageInteractionCallback;
	}

	vtkImageInteractionCallback()
	{
		this->Viewer = NULL;
		this->Picker = NULL;
		this->Annotation = NULL;
	}

	~vtkImageInteractionCallback()
	{
		this->Viewer = NULL;
		this->Picker = NULL;
		this->Annotation = NULL;
	}

	void SetPicker(vtkPropPicker *picker)
	{
		this->Picker = picker;
	}

	void SetAnnotation(vtkCornerAnnotation *annotation)
	{
		this->Annotation = annotation;
	}

	void SetViewer(vtkImageViewer2 *viewer)
	{
		this->Viewer = viewer;
	}

	virtual void Execute(vtkObject *, unsigned long vtkNotUsed(event), void *)
	{
		vtkRenderWindowInteractor *interactor =
			this->Viewer->GetRenderWindow()->GetInteractor();
		vtkRenderer* renderer = this->Viewer->GetRenderer();
		vtkImageActor* actor = this->Viewer->GetImageActor();
		vtkImageData* image = this->Viewer->GetInput();
		vtkInteractorStyle *style = vtkInteractorStyle::SafeDownCast(
			interactor->GetInteractorStyle());

#if VTK_MAJOR_VERSION <= 5
		image->Update();
#endif

		// Pick at the mouse location provided by the interactor
		this->Picker->Pick(interactor->GetEventPosition()[0],
			interactor->GetEventPosition()[1],
			0.0, renderer);

		// There could be other props assigned to this picker, so 
		// make sure we picked the image actor
		vtkAssemblyPath* path = this->Picker->GetPath();
		bool validPick = false;

		if (path)
		{
			vtkCollectionSimpleIterator sit;
			path->InitTraversal(sit);
			vtkAssemblyNode *node;
			for (int i = 0; i < path->GetNumberOfItems() && !validPick; ++i)
			{
				node = path->GetNextNode(sit);
				if (actor == vtkImageActor::SafeDownCast(node->GetViewProp()))
				{
					validPick = true;
				}
			}
		}

		if (!validPick)
		{
			this->Annotation->SetText(0, "Off Image");
			interactor->Render();
			// Pass the event further on
			style->OnMouseMove();
			return;
		}

		// Get the world coordinates of the pick
		double pos[3];
		this->Picker->GetPickPosition(pos);

		int image_coordinate[3];

		int axis = this->Viewer->GetSliceOrientation();
		switch (axis)
		{
		case vtkImageViewer2::SLICE_ORIENTATION_XZ:
			image_coordinate[0] = vtkMath::Round(pos[0]);
			image_coordinate[1] = this->Viewer->GetSlice();
			image_coordinate[2] = vtkMath::Round(pos[2]);
			break;
		case vtkImageViewer2::SLICE_ORIENTATION_YZ:
			image_coordinate[0] = this->Viewer->GetSlice();
			image_coordinate[1] = vtkMath::Round(pos[0]);
			image_coordinate[2] = vtkMath::Round(pos[1]);
			break;
		default:  // vtkImageViewer2::SLICE_ORIENTATION_XY
			image_coordinate[0] = vtkMath::Round(pos[0]);
			image_coordinate[1] = vtkMath::Round(pos[1]);
			image_coordinate[2] = this->Viewer->GetSlice();
			break;
		}

		std::string message = "Location: ( ";
		message += vtkVariant(image_coordinate[0]).ToString();
		message += ", ";
		message += vtkVariant(image_coordinate[1]).ToString();
		message += ", ";
		message += vtkVariant(image_coordinate[2]).ToString();
		message += " )\nValue: ( ";

		switch (image->GetScalarType())
		{
			vtkTemplateMacro((vtkValueMessageTemplate<VTK_TT>(image,
				image_coordinate,
				message)));

		default:
			return;
		}

		this->Annotation->SetText(0, message.c_str());
		interactor->Render();
		style->OnMouseMove();
	}

private:
	vtkImageViewer2*      Viewer;      // Pointer to the viewer
	vtkPropPicker*        Picker;      // Pointer to the picker
	vtkCornerAnnotation*  Annotation;  // Pointer to the annotation
};


int main(int argc, char* argv[])
{
	vtkSmartPointer<vtkImageViewer2> imageViewer =
		vtkSmartPointer<vtkImageViewer2>::New();

	// Verify input arguments
	vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New();
	reader->SetFileName("D:\\NeuboronFile\\dcm\\dcm\\CHC\\CTsim image\\CT.4278314-2.20.dcm");
	reader->Update();

	// create a noise image
	vtkSmartPointer<vtkImageNoiseSource> noiseSource =
		vtkSmartPointer<vtkImageNoiseSource>::New();
	noiseSource->SetWholeExtent(0, 512, 0, 512, 0, 0);
	noiseSource->SetMinimum(0.0);
	noiseSource->SetMaximum(65535.0);

	// cast noise image to unsigned short
	vtkSmartPointer<vtkImageCast> imageCast =
		vtkSmartPointer<vtkImageCast>::New();
	imageCast->SetInputConnection(noiseSource->GetOutputPort());
	imageCast->SetOutputScalarTypeToUnsignedShort();
	imageCast->Update();

	// connect to image viewer pipeline
	imageViewer->SetInputConnection(imageCast->GetOutputPort());

	// Picker to pick pixels
	vtkSmartPointer<vtkPropPicker> propPicker =
		vtkSmartPointer<vtkPropPicker>::New();
	propPicker->PickFromListOn();

	// Give the picker a prop to pick
	vtkImageActor* imageActor = imageViewer->GetImageActor();
	propPicker->AddPickList(imageActor);

	// disable interpolation, so we can see each pixel
	imageActor->InterpolateOff();

	// Visualize
	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	imageViewer->SetInputConnection(reader->GetOutputPort());
	imageViewer->SetupInteractor(renderWindowInteractor);
	imageViewer->SetSize(600, 600);

	vtkRenderer* renderer = imageViewer->GetRenderer();
	renderer->ResetCamera();
	renderer->GradientBackgroundOn();
	renderer->SetBackground(0.6, 0.6, 0.5);
	renderer->SetBackground2(0.3, 0.3, 0.2);

	// Annotate the image with window/level and mouse over pixel
	// information
	vtkSmartPointer<vtkCornerAnnotation> cornerAnnotation =
		vtkSmartPointer<vtkCornerAnnotation>::New();
	cornerAnnotation->SetLinearFontScaleFactor(2);
	cornerAnnotation->SetNonlinearFontScaleFactor(1);
	cornerAnnotation->SetMaximumFontSize(20);
	cornerAnnotation->SetText(0, "Off Image");
	cornerAnnotation->SetText(3, "<window>\n<level>");
	cornerAnnotation->GetTextProperty()->SetColor(1, 0, 0);

	imageViewer->GetRenderer()->AddViewProp(cornerAnnotation);

	// Callback listens to MouseMoveEvents invoked by the interactor's style
	vtkSmartPointer<vtkImageInteractionCallback> callback =
		vtkSmartPointer<vtkImageInteractionCallback>::New();
	callback->SetViewer(imageViewer);
	callback->SetAnnotation(cornerAnnotation);
	callback->SetPicker(propPicker);

	// InteractorStyleImage allows for the following controls:
	// 1) middle mouse + move = camera pan
	// 2) left mouse + move = window/level
	// 3) right mouse + move = camera zoom
	// 4) middle mouse wheel scroll = zoom
	// 5) 'r' = reset window/level
	// 6) shift + 'r' = reset camera
	vtkInteractorStyleImage* imageStyle =
		imageViewer->GetInteractorStyle();
	imageStyle->AddObserver(vtkCommand::MouseMoveEvent, callback);

	renderWindowInteractor->Initialize();
	renderWindowInteractor->Start();

	return EXIT_SUCCESS;
}

博主创作不易,请她喝杯蜜雪冰城吧🤟

  

微信                                       支付宝

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值