/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #include "QuickView.h" #include "itkRescaleIntensityImageFilter.h" #include "itkVectorRescaleIntensityImageFilter.h" #include "itkRGBToVectorImageAdaptor.h" #include "itkFlipImageFilter.h" #include "vtkVersion.h" #include "vtkRenderWindowInteractor.h" #include "vtkImageMapper3D.h" #include "vtkImageActor.h" #include "vtkActor2D.h" #include "vtkInteractorStyleImage.h" #include "vtkRenderer.h" #include "vtkCamera.h" #include "vtkTextProperty.h" #include "vtkTextMapper.h" #include "vtkCaptureScreen.h" #include "vtkPNGWriter.h" #include "vtkJPEGWriter.h" #include "vtkBMPWriter.h" #include "vtkTIFFWriter.h" #include "itkImageToVTKImageFilter.h" using UnsignedCharRGBImageType = itk::Image, 2>; using FloatRGBImageType = itk::Image, 2>; using UnsignedCharImageType = itk::Image; using CharImageType = itk::Image; using UnsignedShortImageType = itk::Image; using ShortImageType = itk::Image; using UnsignedIntImageType = itk::Image; using IntImageType = itk::Image; using UnsignedLongImageType = itk::Image; using LongImageType = itk::Image; using FloatImageType = itk::Image; using DoubleImageType = itk::Image; template void ITKVtkGlue_EXPORT QuickView::AddImage(CharImageType * image, bool FlipVertical, std::string Description); template void ITKVtkGlue_EXPORT QuickView::AddImage(UnsignedShortImageType * image, bool FlipVertical, std::string Description); template void ITKVtkGlue_EXPORT QuickView::AddImage(ShortImageType * image, bool FlipVertical, std::string Description); template void ITKVtkGlue_EXPORT QuickView::AddImage(UnsignedIntImageType * image, bool FlipVertical, std::string Description); template void ITKVtkGlue_EXPORT QuickView::AddImage(IntImageType * image, bool FlipVertical, std::string Description); template void ITKVtkGlue_EXPORT QuickView::AddImage(UnsignedLongImageType * image, bool FlipVertical, std::string Description); template void ITKVtkGlue_EXPORT QuickView::AddImage(LongImageType * image, bool FlipVertical, std::string Description); template void ITKVtkGlue_EXPORT QuickView::AddImage(FloatImageType * image, bool FlipVertical, std::string Description); template void ITKVtkGlue_EXPORT QuickView::AddImage(DoubleImageType * image, bool FlipVertical, std::string Description); template <> void ITKVtkGlue_EXPORT QuickView::AddImage(UnsignedCharImageType * image, bool FlipVertical, std::string Description) { if (FlipVertical) { using FlipFilterType = itk::FlipImageFilter; FlipFilterType::Pointer flipper = FlipFilterType::New(); bool flipAxes[3] = { false, true, false }; flipper = FlipFilterType::New(); flipper->SetFlipAxes(flipAxes); flipper->SetInput(image); flipper->Update(); ImageInfo myImage(flipper->GetOutput(), Description); this->Images.push_back(myImage); } else { ImageInfo myImage(image, Description); this->Images.push_back(myImage); } } template void ITK_TEMPLATE_EXPORT QuickView::AddImage(TImage * image, bool FlipVertical, std::string Description) { using rescaleFilterType = itk::RescaleIntensityImageFilter; typename rescaleFilterType::Pointer rescaler = rescaleFilterType::New(); rescaler->SetOutputMinimum(0); rescaler->SetOutputMaximum(255); rescaler->SetInput(image); rescaler->Update(); this->AddImage(rescaler->GetOutput(), FlipVertical, Description); } template <> void ITKVtkGlue_EXPORT QuickView::AddImage(UnsignedCharRGBImageType * image, bool FlipVertical, std::string Description) { if (FlipVertical) { using FlipFilterType = itk::FlipImageFilter; FlipFilterType::Pointer flipper = FlipFilterType::New(); bool flipAxes[3] = { false, true, false }; flipper = FlipFilterType::New(); flipper->SetFlipAxes(flipAxes); flipper->SetInput(image); flipper->Update(); RGBImageInfo myImage(flipper->GetOutput(), Description); this->RGBImages.push_back(myImage); } else { RGBImageInfo myImage(image, Description); this->RGBImages.push_back(myImage); } } template <> void ITKVtkGlue_EXPORT QuickView::AddRGBImage(UnsignedCharRGBImageType * image, bool FlipVertical, std::string Description) { if (FlipVertical) { using FlipFilterType = itk::FlipImageFilter; FlipFilterType::Pointer flipper = FlipFilterType::New(); bool flipAxes[3] = { false, true, false }; flipper = FlipFilterType::New(); flipper->SetFlipAxes(flipAxes); flipper->SetInput(image); flipper->Update(); RGBImageInfo myImage(flipper->GetOutput(), Description); this->RGBImages.push_back(myImage); } else { RGBImageInfo myImage(image, Description); this->RGBImages.push_back(myImage); } } template <> void ITKVtkGlue_EXPORT QuickView::AddRGBImage(FloatRGBImageType * image, bool FlipVertical, std::string Description) { using AdaptorType = itk::RGBToVectorImageAdaptor; AdaptorType::Pointer adaptor = AdaptorType::New(); adaptor->SetImage(image); using rescaleFilterType = itk::VectorRescaleIntensityImageFilter; rescaleFilterType::Pointer rescaler = rescaleFilterType::New(); rescaler->SetOutputMaximumMagnitude(255); rescaler->SetInput(adaptor); rescaler->Update(); this->AddRGBImage(rescaler->GetOutput(), FlipVertical, Description); } template <> void ITKVtkGlue_EXPORT QuickView::AddImage(FloatRGBImageType * image, bool FlipVertical, std::string Description) { using AdaptorType = itk::RGBToVectorImageAdaptor; AdaptorType::Pointer adaptor = AdaptorType::New(); adaptor->SetImage(image); using rescaleFilterType = itk::VectorRescaleIntensityImageFilter; rescaleFilterType::Pointer rescaler = rescaleFilterType::New(); rescaler->SetOutputMaximumMagnitude(255); rescaler->SetInput(adaptor); rescaler->Update(); this->AddRGBImage(rescaler->GetOutput(), FlipVertical, Description); } void QuickView::Visualize(bool interact) { unsigned int rendererSize = this->m_ViewPortSize; unsigned int numberOfImages = this->Images.size() + this->RGBImages.size(); unsigned int numberOfRows = (numberOfImages - 1) / this->m_NumberOfColumns + 1; unsigned int numberOfColumns = numberOfImages / (numberOfRows) + 1; if (numberOfColumns > numberOfImages) { numberOfColumns = numberOfImages; } // Setup the render window and interactor vtkSmartPointer renderWindow = vtkSmartPointer::New(); renderWindow->SetSize(rendererSize * numberOfColumns, rendererSize * numberOfRows); vtkSmartPointer interactor = vtkSmartPointer::New(); interactor->SetRenderWindow(renderWindow); // Render all of the images std::vector viewports; using ConnectorType = itk::ImageToVTKImageFilter>; using RGBConnectorType = itk::ImageToVTKImageFilter, 2>>; std::vector connectors; // Force the connectors to persist (not lose scope) after each iteration of the loop std::vector RGBconnectors; // Force the connectors to persist after each iteration of the loop double background[6] = { .4, .5, .6, .6, .5, .4 }; vtkSmartPointer sharedCamera = vtkSmartPointer::New(); for (unsigned int row = 0; row < numberOfRows; ++row) { for (unsigned int col = 0; col < numberOfColumns; ++col) { size_t i = row * numberOfColumns + col; // (xmin, ymin, xmax, ymax) double viewport[4] = { static_cast(col) * rendererSize / (numberOfColumns * rendererSize), static_cast(numberOfRows - (row + 1)) * rendererSize / (numberOfRows * rendererSize), static_cast(col + 1) * rendererSize / (numberOfColumns * rendererSize), static_cast(numberOfRows - row) * rendererSize / (numberOfRows * rendererSize) }; viewports.push_back(viewport); // Grayscale images if (i < this->Images.size()) { ConnectorType::Pointer connector = ConnectorType::New(); connectors.push_back(connector); connector->SetInput(this->Images[i].m_Image); vtkSmartPointer actor = vtkSmartPointer::New(); #if VTK_MAJOR_VERSION <= 5 actor->SetInput(connector->GetOutput()); #else connector->Update(); actor->GetMapper()->SetInputData(connector->GetOutput()); #endif // Setup renderer vtkSmartPointer renderer = vtkSmartPointer::New(); renderWindow->AddRenderer(renderer); renderer->SetViewport(viewports[i]); renderer->SetBackground(background); if (m_ShareCamera) { renderer->SetActiveCamera(sharedCamera); } else { vtkSmartPointer aCamera = vtkSmartPointer::New(); renderer->SetActiveCamera(aCamera); } std::rotate(background, background + 1, background + 6); if (!this->Images[i].m_Description.empty()) { vtkSmartPointer textProperty = vtkSmartPointer::New(); textProperty->SetFontSize(10); textProperty->SetFontFamilyToCourier(); textProperty->SetJustificationToCentered(); vtkSmartPointer textMapper = vtkSmartPointer::New(); textMapper->SetTextProperty(textProperty); textMapper->SetInput(this->Images[i].m_Description.c_str()); vtkSmartPointer textActor = vtkSmartPointer::New(); textActor->SetMapper(textMapper); textActor->SetPosition(rendererSize / 2, 16); renderer->AddActor(textActor); } if (m_Interpolate) { actor->InterpolateOn(); } else { actor->InterpolateOff(); } renderer->AddActor(actor); renderer->ResetCamera(); } // RGB Images else if (i >= this->Images.size() && i < numberOfImages) { unsigned int j = row * numberOfColumns + col - this->Images.size(); RGBConnectorType::Pointer connector = RGBConnectorType::New(); RGBconnectors.push_back(connector); connector->SetInput(this->RGBImages[j].m_Image); vtkSmartPointer actor = vtkSmartPointer::New(); #if VTK_MAJOR_VERSION <= 5 actor->SetInput(connector->GetOutput()); #else connector->Update(); actor->GetMapper()->SetInputData(connector->GetOutput()); #endif // Setup renderer vtkSmartPointer renderer = vtkSmartPointer::New(); renderWindow->AddRenderer(renderer); renderer->SetViewport(viewports[i]); renderer->SetBackground(background); if (m_ShareCamera) { renderer->SetActiveCamera(sharedCamera); } else { vtkSmartPointer aCamera = vtkSmartPointer::New(); renderer->SetActiveCamera(aCamera); } std::rotate(background, background + 1, background + 6); if (!this->RGBImages[j].m_Description.empty()) { vtkSmartPointer textProperty = vtkSmartPointer::New(); textProperty->SetFontSize(10); textProperty->SetFontFamilyToCourier(); textProperty->SetJustificationToCentered(); vtkSmartPointer textMapper = vtkSmartPointer::New(); textMapper->SetTextProperty(textProperty); textMapper->SetInput(this->RGBImages[j].m_Description.c_str()); vtkSmartPointer textActor = vtkSmartPointer::New(); textActor->SetMapper(textMapper); textActor->SetPosition(rendererSize / 2, 16); renderer->AddActor(textActor); } if (m_Interpolate) { actor->InterpolateOn(); } else { actor->InterpolateOff(); } renderer->AddActor(actor); renderer->ResetCamera(); } else { // Fill empty viewports vtkSmartPointer renderer = vtkSmartPointer::New(); renderWindow->AddRenderer(renderer); renderer->SetViewport(viewports[i]); renderer->SetBackground(background); continue; } } } renderWindow->Render(); if (m_Snapshot) { std::string filename; std::stringstream temp; temp << m_SnapshotPath << m_SnapshotPrefix << m_Counter << "."; filename = temp.str(); filename.append(m_SnapshotExtension); if (m_SnapshotExtension == "png") { vtkCaptureScreen capture(renderWindow); capture(filename); } if ((m_SnapshotExtension == "jpg") || (m_SnapshotExtension == "jpeg")) { vtkCaptureScreen capture(renderWindow); capture(filename); } if (m_SnapshotExtension == "bmp") { vtkCaptureScreen capture(renderWindow); capture(filename); } if ((m_SnapshotExtension == "tif") || (m_SnapshotExtension == "tiff")) { vtkCaptureScreen capture(renderWindow); capture(filename); } m_Counter++; } vtkSmartPointer style = vtkSmartPointer::New(); interactor->SetInteractorStyle(style); if (interact) { interactor->Start(); } }