flip mpr image become abnormal

My vtk version is 9.2 .When I perform the flipping function of mpr reconstruction, everything is normal before flipping, and after flipping, the image rotated by the camera becomes abnormal,I found that before flipping, rotating vtkPlaneSource will not affect the rotation of the image. However, after flipping, the rotation of vtkPlaneSource will double or reverse the rotation of my image. Here is my code. thank you.

#include "vtkSmartPointer.h"
#include "vtkCamera.h"
#include "vtkCellPicker.h"
#include "vtkCommand.h"
#include "vtkImageActor.h"
#include "vtkImageReslice.h"
#include "vtkInteractorStyleImage.h"
#include "vtkImageMapToColors.h"
#include "vtkImagePlaneWidget.h"
#include "vtkImageReader.h"
#include "vtkInteractorEventRecorder.h"
#include "vtkLookupTable.h"
#include "vtkOutlineFilter.h"
#include "vtkDICOMImageReader.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkImageData.h"
#include "vtkPointData.h"
#include "vtkPlaneSource.h"
#include "vtkPlane.h"
#include "vtkResliceCursorActor.h"
#include "vtkResliceCursorPolyDataAlgorithm.h"
#include "vtkResliceCursor.h"
#include "vtkResliceCursorWidget.h"
#include "vtkResliceCursorLineRepresentation.h"
#include "vtkBiDimensionalWidget.h"
#include"vtkAutoInit.h"
#include"vtkAxesActor.h"
#include"vtkTransform.h"
#include"vtkTextActor.h"
#include"vtkProperty2D.h"
#include<vtkActor2D.h>
#include<vtkResliceImageViewer.h>
#include<vtkImageFlip.h>
#include"vtkAutoInit.h"
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType)

class myrep :public vtkResliceCursorLineRepresentation {

public:
	static myrep* New()
	{
		return new myrep;
	}
	
	void SetResliceParameters(
		double outputSpacingX, double outputSpacingY, int extentX, int extentY)override
	{
		vtkImageReslice* reslice = vtkImageReslice::SafeDownCast(this->Reslice);

		if (reslice)
		{
			// Set the default color the minimum scalar value
			double range[2];
			vtkImageData::SafeDownCast(reslice->GetInput())->GetScalarRange(range);
			reslice->SetBackgroundLevel(range[0]);

			auto flip = vtkSmartPointer< vtkImageFlip>::New();
			flip->SetFilteredAxis(1);
			flip->SetInputConnection(reslice->GetOutputPort());

			this->ColorMap->SetInputConnection(flip->GetOutputPort());
			reslice->TransformInputSamplingOff();
			reslice->AutoCropOutputOn();
			reslice->SetResliceAxes(this->ResliceAxes);
			reslice->SetOutputSpacing(outputSpacingX, outputSpacingY, 1);
			reslice->SetOutputOrigin(0.5 * outputSpacingX, 0.5 * outputSpacingY, 0);
			reslice->SetOutputExtent(0, extentX - 1, 0, extentY - 1, 0, 0);
		}
	}



};
class vtkResliceCursorCallback : public vtkCommand
{
public:
	static vtkResliceCursorCallback* New()
	{
		return new vtkResliceCursorCallback;
	}
	void Execute(vtkObject* caller, unsigned long ev,
		void* callData) override
	{
		if (ev == vtkResliceCursorWidget::WindowLevelEvent ||
			ev == vtkCommand::WindowLevelEvent ||
			ev == vtkResliceCursorWidget::ResliceThicknessChangedEvent)
		{
			// Render everything
			for (int i = 0; i < 3; i++)
			{
				this->RCW[i]->Render();
			}
			this->IPW[0]->GetInteractor()->GetRenderWindow()->Render();
			//return;

		}

		vtkResliceCursorWidget* rcw = dynamic_cast<
			vtkResliceCursorWidget*>(caller);
		if (rcw)
		{
			vtkResliceCursorLineRepresentation* rep = dynamic_cast<
				vtkResliceCursorLineRepresentation*>(rcw->GetRepresentation());
			double window[2];
			rep->GetWindowLevel(window);

			//同步的前提下才能实现
			for (size_t i = 0; i < 3; i++)
			{
				RCW[i]->GetResliceCursorRepresentation()->SetWindowLevel(window[0], window[1]);
			}
			rep->GetResliceCursorActor()->GetCursorAlgorithm()->GetResliceCursor();
			for (int i = 0; i < 3; i++)
			{
				vtkPlaneSource* ps = static_cast<vtkPlaneSource*>(
					this->IPW[i]->GetPolyDataAlgorithm());
				ps->SetOrigin(this->RCW[i]->GetResliceCursorRepresentation()->
					GetPlaneSource()->GetOrigin());
				ps->SetPoint1(this->RCW[i]->GetResliceCursorRepresentation()->
					GetPlaneSource()->GetPoint1());
				ps->SetPoint2(this->RCW[i]->GetResliceCursorRepresentation()->
					GetPlaneSource()->GetPoint2());

				// If the reslice plane has modified, update it on the 3D widget
				this->IPW[i]->UpdatePlacement();
			}
		}


		// Render everything
		for (int i = 0; i < 3; i++)
		{
			this->RCW[i]->Render();
		}
		this->IPW[0]->GetInteractor()->GetRenderWindow()->Render();
	}

	vtkResliceCursorCallback() {}
	vtkImagePlaneWidget* IPW[3];
	vtkResliceCursorWidget* RCW[3];

	vtkResliceImageViewer* RIW[3];
};
int main()
{
	vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New();
	std::string dict = "C:\\Users\\12820\\Desktop\\DICOM参考数据\\CT-head\\1.25-240";
	std::string dict1 = "C:\\Users\\12820\\source\\repos\\vtkProject\\vtkProject\\imaghe\\rt_ct";
	reader->SetDirectoryName(dict1.c_str());
	reader->Update();
	int imageDims[3];
	reader->GetOutput()->GetDimensions(imageDims);

	vtkSmartPointer< vtkResliceImageViewer >riw[3];
	vtkSmartPointer< vtkRenderWindow >renderWindow[3];
	vtkSmartPointer< vtkRenderWindowInteractor >renderWindowInteractor[3];
	vtkSmartPointer< vtkResliceCursor > resliceCursor = vtkSmartPointer< vtkResliceCursor >::New();
	vtkSmartPointer< myrep > rep[3];

	resliceCursor->SetCenter(reader->GetOutput()->GetCenter());

	resliceCursor->SetImage(reader->GetOutput());
	for (int i = 0; i < 3; i++)
	{
		riw[i] = vtkSmartPointer< vtkResliceImageViewer >::New();
		rep[i] = vtkSmartPointer< myrep >::New();
		renderWindowInteractor[i] = vtkSmartPointer< vtkRenderWindowInteractor >::New();
		riw[i]->SetupInteractor(renderWindowInteractor[i]);
	}

	for (int i = 0; i < 3; i++)
	{
		riw[i]->GetResliceCursorWidget()->SetRepresentation(rep[i]);
		riw[i]->SetResliceCursor(resliceCursor);
		rep[i]->GetResliceCursorActor()->GetCursorAlgorithm()->SetReslicePlaneNormal(i);

		rep[i]->GetResliceCursorActor()->GetCenterlineProperty(0)->SetRepresentationToWireframe();//代表12窗口竖线
		rep[i]->GetResliceCursorActor()->GetCenterlineProperty(1)->SetRepresentationToWireframe();//0竖线,2横线
		rep[i]->GetResliceCursorActor()->GetCenterlineProperty(2)->SetRepresentationToWireframe();//01横线

		riw[i]->SetInputData(reader->GetOutput());

		riw[i]->GetRenderWindow()->SetSize(500, 500);
		riw[i]->GetRenderWindow()->SetPosition(800 + i * 500, 500);
		if (i == 2)
			riw[i]->GetRenderWindow()->SetPosition(800, 0);
		riw[i]->SetSliceOrientation(1);
		riw[i]->SetSliceOrientation(i);
	}

	for (int i = 0; i < 3; i++)
	{
		riw[i]->SetResliceMode(1);
		riw[i]->GetRenderer()->ResetCamera();
		riw[i]->Render();
	}

	vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New();
	vtkSmartPointer<vtkProperty> ipwProp = vtkSmartPointer<vtkProperty>::New();
	vtkSmartPointer< vtkRenderer > ren = vtkSmartPointer< vtkRenderer >::New();
	auto renderWindow4 = vtkSmartPointer<vtkRenderWindow>::New();;//第四个窗口
	auto iren = vtkSmartPointer<vtkRenderWindowInteractor>::New();//第四个窗口的vtkRenderWindowInteractor

	renderWindow4->SetInteractor(iren);
	renderWindow4->AddRenderer(ren);
	vtkSmartPointer<vtkImagePlaneWidget>planeWidget[3];
	for (int i = 0; i < 3; i++)
	{
		planeWidget[i] = vtkSmartPointer<vtkImagePlaneWidget>::New();
		planeWidget[i]->SetInteractor(iren);
		planeWidget[i]->SetPicker(picker);
		planeWidget[i]->RestrictPlaneToVolumeOn();
		double color[3] = { 0, 0, 0 };
		color[i] = 1;
		planeWidget[i]->GetPlaneProperty()->SetColor(color);

		color[0] /= 4.0;
		color[1] /= 4.0;
		color[2] /= 4.0;
		riw[i]->GetRenderer()->SetBackground(0, 0, 0);

		planeWidget[i]->SetTexturePlaneProperty(ipwProp);
		planeWidget[i]->TextureInterpolateOff();
		planeWidget[i]->SetResliceInterpolateToLinear();
		planeWidget[i]->SetInputConnection(reader->GetOutputPort());
		planeWidget[i]->SetPlaneOrientation(i);
		planeWidget[i]->SetSliceIndex(imageDims[i] / 2);
		planeWidget[i]->DisplayTextOn();
		planeWidget[i]->SetDefaultRenderer(ren);
		planeWidget[i]->SetWindowLevel(1358, -27);
		planeWidget[i]->On();
		planeWidget[i]->InteractionOn();
	}
	auto cbk = vtkSmartPointer<vtkResliceCursorCallback>::New();

	for (int i = 0; i < 3; i++)
	{
		cbk->RIW[i] = riw[i];
		cbk->IPW[i] = planeWidget[i];
		cbk->RCW[i] = riw[i]->GetResliceCursorWidget();

		vtkWidgetEventTranslator* WidgetTrans = riw[i]->GetResliceCursorWidget()->GetEventTranslator();

		riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResliceAxesChangedEvent, cbk);

		riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::WindowLevelEvent, cbk);

		riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResliceThicknessChangedEvent, cbk);
		riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResetCursorEvent, cbk);

		riw[i]->SetLookupTable(riw[0]->GetLookupTable());
		planeWidget[i]->GetColorMap()->SetLookupTable(riw[0]->GetLookupTable());
		// planeWidget[i]->GetColorMap()->(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap()->GetInput());
		planeWidget[i]->SetColorMap(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap());

	}

	auto style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	iren->SetInteractorStyle(style);
	renderWindow4->SetSize(500, 500);
	renderWindow4->SetPosition(1300, 0);
	renderWindow4->Render();

	iren->Initialize();
	iren->Start();

}

sorry i am new user ,don not allow me upload video, you can run my code and press “ctrl” rotate image,then you can found the question.

someone help me

Here is the video from @marlon.ma , if that helps:

The problem occurs because you put vtkImageFlip after vtkImageReslice. So if there is a rotation, the flip occurs in the rotated coordinate system.

The flip must be before vtkImageReslice.

In my code, flip is before reslice isn’t it?

This is your code:

In your pipeline, flip happens after reslice.

thank you very much,i have a try

If I put the flip before reslice, then I flip the volume data. This is not in line with my idea. Can I flip only the single slice image? My current solution is to prohibit the rotation of the vtkplanesouse. It can work. The side effect is that the size of the vtkplanesouse will not change with the rotation

Doing it for just one slice might be difficult. In SetResliceParameters(), how will you know the slice direction, so that you know whether to flip or not to flip? Maybe you can check the ResliceAxes.

What you are trying to do is contrary to what vtkResliceCursor is designed to do, so it will probably be hard to achieve good results.

Also, maybe use can use vtkImageReslice to do the flip. This way, you don’t need to add vtkImageFlip to the pipeline.

Where the code says reslice->SetResliceAxes(this->ResliceAxes), you can add a transform that flips the image:

auto transform = vtkSmartPointer<vtkTransform>::New();
transform->PostMultiply();
transform->Translate(-centerX, -centerY, -centerZ);
transform->RotateWXYZ(180, 0, 0, 1);  // you can also try Scale(+1, -1, +1)
transform->Translate(+centerX, +centerY, +centerZ);

reslice->SetResliceTransform(transform);
reslice->SetResliceAxes(this->ResliceAxes);

This is just an idea, so I’m not sure if it will work. The vtkResliceCursor code is complicated, so adding the transform might cause problems in other parts of the code.

I have tried this method. There are always other problems. After setting the transform, rotating the slice line will move the center of the slice image, which looks terrible

But the problem is, when I forbid vtkplansoe rotation, only everything becomes normal. Before flipping, rotate vtkplansoe, and the image will not rotate. But after flipping, the image will rotate with vtkplansoe, which is incomprehensible to me.

void myrep::TransformPlane(vtkPlaneSource* planeToTransform,
	double targetCenter[3], double targetNormal[3], double targetViewUp[3])
{

	
	planeToTransform->SetNormal(targetNormal);
	double currentViewUp[3];
	vtkMath::Subtract(planeToTransform->GetPoint2(), planeToTransform->GetOrigin(), currentViewUp);

	double angle = vtkMath::SignedAngleBetweenVectors(currentViewUp, targetViewUp, targetNormal);
	angle = vtkMath::DegreesFromRadians(angle);

	angle = 0;
	planeToTransform->Rotate(-angle, targetNormal);
	planeToTransform->SetCenter(targetCenter);
}

In this way, I forbid vtkplanesouse rotation