From bbb9427a59a56c9e9f3a139814adb104031eae2b Mon Sep 17 00:00:00 2001 From: Simon Rit Date: Thu, 22 Mar 2012 18:56:50 +0100 Subject: [PATCH] Added animated GIF video snapshot (CLITK_EXPERIMENTAL yet) --- vv/CMakeLists.txt | 12 ++++- vv/vvAnimatedGIFWriter.cxx | 100 +++++++++++++++++++++++++++++++++++++ vv/vvAnimatedGIFWriter.h | 50 +++++++++++++++++++ vv/vvMainWindow.cxx | 31 ++++++++++-- 4 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 vv/vvAnimatedGIFWriter.cxx create mode 100644 vv/vvAnimatedGIFWriter.h diff --git a/vv/CMakeLists.txt b/vv/CMakeLists.txt index ccfe267..6b0af07 100644 --- a/vv/CMakeLists.txt +++ b/vv/CMakeLists.txt @@ -204,9 +204,19 @@ endforeach(tool) #on them) SET(foundationLibraries clitkCommon ${ITK_LIBRARIES} QVTK vtkHybrid) +#========================================================= +# Use CxImage to create animated gifs +IF(CLITK_EXPERIMENTAL) + SET(vvCxImage clitkCxImage) + SET(vv_SRCS ${vv_SRCS} vvAnimatedGIFWriter.cxx) + INCLUDE_DIRECTORIES(${CLITK_SOURCE_DIR}/utilities/CxImage) + ADD_SUBDIRECTORY(${CLITK_SOURCE_DIR}/utilities/CxImage ${PROJECT_BINARY_DIR}/utilities/CxImage) +ENDIF(CLITK_EXPERIMENTAL) +#========================================================= + #========================================================= #Create binary and libs for tests -SET(vvExternalLibs ${QT_QTNETWORK_LIBRARY} clitkSegmentationGgoLib clitkDicomRTStruct ${toolLibs} ${foundationLibraries}) +SET(vvExternalLibs ${QT_QTNETWORK_LIBRARY} clitkSegmentationGgoLib clitkDicomRTStruct ${toolLibs} ${foundationLibraries} ${vvCxImage}) # QtNetwork is required by vvRegisterForm ADD_LIBRARY(vvLib ${vv_SRCS} ${vv_UI_CXX}) diff --git a/vv/vvAnimatedGIFWriter.cxx b/vv/vvAnimatedGIFWriter.cxx new file mode 100644 index 0000000..75352ac --- /dev/null +++ b/vv/vvAnimatedGIFWriter.cxx @@ -0,0 +1,100 @@ +#include "vvAnimatedGIFWriter.h" +#include "clitkDD.h" + +#include "ximagif.h" + +#include +#include +#include +#include +#include +#include + +//--------------------------------------------------------------------------- +vtkStandardNewMacro(vvAnimatedGIFWriter); + +//--------------------------------------------------------------------------- +vvAnimatedGIFWriter::vvAnimatedGIFWriter() +{ + Rate = 5; + Loops = 0; +} + +//--------------------------------------------------------------------------- +vvAnimatedGIFWriter::~vvAnimatedGIFWriter() +{ +} + +//--------------------------------------------------------------------------- +void vvAnimatedGIFWriter::Start() +{ + // Create one volume with all slices + RGBvolume = vtkSmartPointer::New(); + RGBvolume->SetAppendAxis(2); + RGBslices.clear(); +} + +//--------------------------------------------------------------------------- +void vvAnimatedGIFWriter::Write() +{ + // get the data + this->GetInput()->UpdateInformation(); + int *wExtent = this->GetInput()->GetWholeExtent(); + this->GetInput()->SetUpdateExtent(wExtent); + this->GetInput()->Update(); + + RGBslices.push_back( vtkSmartPointer::New() ); + RGBslices.back()->ShallowCopy(this->GetInput()); + RGBvolume->AddInput(RGBslices.back()); +} + +//--------------------------------------------------------------------------- +void vvAnimatedGIFWriter::End() +{ + RGBvolume->Update(); + + // Quantize to 8 bit colors + vtkSmartPointer quant = vtkSmartPointer::New(); + quant->SetNumberOfColors(256); + quant->SetInput(RGBvolume->GetOutput()); + quant->Update(); + + // Convert to 8 bit image + vtkSmartPointer cast = vtkSmartPointer::New(); + cast->SetInput( quant->GetOutput() ); + cast->SetOutputScalarTypeToUnsignedChar(); + cast->Update(); + + // Create a stack of CxImages + DWORD width = cast->GetOutput()->GetExtent()[1]-cast->GetOutput()->GetExtent()[0]+1; + DWORD height = cast->GetOutput()->GetExtent()[3]-cast->GetOutput()->GetExtent()[2]+1; + std::vector cximages( RGBslices.size() ); + for(unsigned int i=0; iCreateFromArray((BYTE *)cast->GetOutput()->GetScalarPointer(0,0,i), + width, height, 8, width, false); + cximages[i]->SetFrameDelay(100/Rate); + cximages[i]->SetPalette((RGBQUAD*)(quant->GetLookupTable()->GetPointer(0))); + } + + // Create gif + FILE * pFile; + pFile = fopen (this->FileName, "wb"); + CxImageGIF cximagegif; + cximagegif.SetLoops(Loops); + bool result = cximagegif.Encode(pFile,&(cximages[0]), (int)RGBslices.size(), true); + + // Cleanup + fclose(pFile); + for(unsigned int i=0; iSuperclass::PrintSelf(os, indent); +} diff --git a/vv/vvAnimatedGIFWriter.h b/vv/vvAnimatedGIFWriter.h new file mode 100644 index 0000000..8242779 --- /dev/null +++ b/vv/vvAnimatedGIFWriter.h @@ -0,0 +1,50 @@ +#ifndef __vvAnimatedGIFWriter_h +#define __vvAnimatedGIFWriter_h + +#include + +#include +#include + +class vtkImageAppend; + +class VTK_IO_EXPORT vvAnimatedGIFWriter : public vtkGenericMovieWriter +{ +public: + static vvAnimatedGIFWriter *New(); + vtkTypeMacro(vvAnimatedGIFWriter,vtkGenericMovieWriter); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // These methods start writing an Movie file, write a frame to the file + // and then end the writing process. + void Start(); + void Write(); + void End(); + + // Description: + // Set/Get the frame rate, in frame/s. + vtkSetClampMacro(Rate, int, 1, 5000); + vtkGetMacro(Rate, int); + + // Description: + // Set/Get the number of loops, 0 means infinite + vtkSetClampMacro(Loops, int, 0, 5000); + vtkGetMacro(Loops, int); + +protected: + vvAnimatedGIFWriter(); + ~vvAnimatedGIFWriter(); + + int Rate; + int Loops; + + vtkSmartPointer RGBvolume; + std::vector< vtkSmartPointer > RGBslices; + +private: + vvAnimatedGIFWriter(const vvAnimatedGIFWriter&); // Not implemented + void operator=(const vvAnimatedGIFWriter&); // Not implemented +}; + +#endif diff --git a/vv/vvMainWindow.cxx b/vv/vvMainWindow.cxx index 986d7b9..9dbd407 100644 --- a/vv/vvMainWindow.cxx +++ b/vv/vvMainWindow.cxx @@ -71,6 +71,9 @@ #include #include #include +#ifdef CLITK_EXPERIMENTAL +# include +#endif #ifdef VTK_USE_VIDEO_FOR_WINDOWS # include #endif @@ -2735,11 +2738,14 @@ void vvMainWindow::SaveScreenshot(QVTKWidget *widget) Extensions += "Images( *.bmp);;"; Extensions += "Images( *.tif);;"; Extensions += "Images( *.ppm)"; -#ifdef VTK_USE_FFMPEG_ENCODER - Extensions += "Images( *.avi)"; +#if defined(VTK_USE_FFMPEG_ENCODER) || defined(VTK_USE_VIDEO_FOR_WINDOWS) + Extensions += ";;Video( *.avi)"; #endif #ifdef VTK_USE_MPEG2_ENCODER - Extensions += "Images( *.mpg)"; + Extensions += ";;Video( *.mpg)"; +#endif +#ifdef CLITK_EXPERIMENTAL + Extensions += ";;Video( *.gif)"; #endif int smIndex=GetSlicerIndexFromItem(DataTree->selectedItems()[0]); @@ -2779,6 +2785,25 @@ void vvMainWindow::SaveScreenshot(QVTKWidget *widget) // Video vtkGenericMovieWriter *vidwriter = NULL; +#ifdef CLITK_EXPERIMENTAL + if (!strcmp(ext, ".gif")) { + vvAnimatedGIFWriter *gif = vvAnimatedGIFWriter::New(); + vidwriter = gif; + + // FPS + bool ok; + int fps = QInputDialog::getInt(this, tr("Number of frames per second"), + tr("FPS:"), 5, 0, 1000, 1, &ok); + if(ok) + gif->SetRate(fps); + + // Loops + int loops = QInputDialog::getInt(this, tr("Loops"), + tr("Number of loops (0 means infinite):"), 0, 0, 1000000000, 1, &ok); + if(ok) + gif->SetLoops(loops); + } +#endif #ifdef VTK_USE_VIDEO_FOR_WINDOWS if (!strcmp(ext, ".avi")) { vtkAVIWriter *mpg = vtkAVIWriter::New(); -- 2.46.1