diff --git a/Code/Core/otbWrapperApplication.cxx b/Code/Core/otbWrapperApplication.cxx index 96f45e1201acc3f08d7892fe870a6a76655977b7..83b45af4a840d20cd1e87e22eebcf4db9d7f637b 100644 --- a/Code/Core/otbWrapperApplication.cxx +++ b/Code/Core/otbWrapperApplication.cxx @@ -39,15 +39,80 @@ namespace Wrapper Application::Application() : m_Name(""), - m_Description("") + m_Description(""), + m_ThreadId1(0), + m_ThreadId2(0), + m_ThreadId3(0), + m_ThreadId4(0), + m_Thread1HasFinished(true), + m_Thread2HasFinished(true), + m_Thread3HasFinished(true), + m_Thread4HasFinished(true) { // Don't call Init from the constructor, since it calls a virtual method ! + m_Threader = ThreaderType::New(); + m_ProgressSourceList = ObjectListType::New(); } Application::~Application() { } +void +Application +::StartProcess1() +{ + m_ThreadId1 = m_Threader->SpawnThread(RunProcess1_static, this); +} + +void +Application +::StopProcess1() +{ + m_Threader->TerminateThread(m_ThreadId1); +} + +void +Application +::StartProcess2() +{ + m_ThreadId2 = m_Threader->SpawnThread(RunProcess2_static, this); +} + +void +Application +::StopProcess2() +{ + m_Threader->TerminateThread(m_ThreadId2); +} + +void +Application +::StartProcess3() +{ + m_ThreadId3 = m_Threader->SpawnThread(RunProcess3_static, this); +} + +void +Application +::StopProcess3() +{ + m_Threader->TerminateThread(m_ThreadId3); +} + +void +Application +::StartProcess4() +{ + m_ThreadId4 = m_Threader->SpawnThread(RunProcess4_static, this); +} + +void +Application +::StopProcess4() +{ + m_Threader->TerminateThread(m_ThreadId4); +} std::vector<std::string> Application::GetParametersKeys(bool recursive) @@ -90,13 +155,33 @@ void Application::UpdateParameters() void Application::Execute() { - this->DoExecute(); + //this->DoExecute(); + std::cout<<"Application::Execute starts"<<std::endl; + this->StartProcess1(); + + if( m_ProgressSourceList->Size() == 0 ) + { + this->StartProcess2(); + } + std::cout<<"Application::Execute done"<<std::endl; } void Application::ExecuteAndWriteOutput() { this->Execute(); + while( m_Thread2HasFinished == false || m_Thread2HasFinished == false) + { + this->Sleep(500); + } + + this->StartProcess3(); + this->StartProcess4(); +} + + +void Application::DoWriteOutput() +{ std::vector<std::string> paramList = GetParametersKeys(true); for (std::vector<std::string>::const_iterator it = paramList.begin(); it != paramList.end(); @@ -106,11 +191,74 @@ void Application::ExecuteAndWriteOutput() { Parameter* param = GetParameterByKey(*it); OutputImageParameter* outputParam = dynamic_cast<OutputImageParameter*>(param); + m_CurWriter = outputParam->GetWriter(); outputParam->Write(); } } } +void Application::DoWatchExecute() +{ + std::cout<<"Application::DoWatchExecute starts"<<std::endl; + /* + double last = 0; + double updateThres = 0.01; + double current = -1; + */ + unsigned int nbProcessDone = 0; + unsigned int nbProcess( m_ProgressSourceList->Size() ); + unsigned int nbCurProcess( nbProcess ); + + while ( nbProcessDone < nbProcess && m_Thread1HasFinished == false) + { + itk::OStringStream oss; + for( unsigned int i=0; i<nbProcess; i++ ) + { + unsigned int progressPercent = static_cast<unsigned int>(m_ProgressSourceList->GetNthElement( i )->GetProgress()*100); + std::string stars(progressPercent, '*'); + std::string blanks(100-progressPercent, ' '); + oss<< "\rProcessing progress " << i <<": " << progressPercent << "% [" << stars << blanks << "]\n" ; + //std::cout << m_ProgressSourceList->GetNthElement( i )->GetProgress() << std:endl; + //std::cout << "\rProcessing progress: " << progressPercent << "% [" << stars << blanks << "]" << std::flush; + if( m_ProgressSourceList->GetNthElement( i )->GetProgress()==1 ) + { + nbProcessDone++; + } + } + std::cout << oss.str() << std::endl;//flush; + Sleep(500); + + /* + current = m_ProcessObject->GetProgress(); + if (current - last > updateThres) + { + // Make the main fltk loop update progress fields + m_View->AwakeProgressFields(m_ProcessObject->GetProgress()); + last = current; + } + } + // Sleep for a while + Sleep(500); + m_ProcessObject = m_Model->GetProcessObjectModel(); + */ + } + std::cout<<"Application::DoWatchExecute done"<<std::endl; +} + +void Application::DoWatchWrite() +{ + while( m_CurWriter.IsNotNull() && m_Thread3HasFinished==false ) + { + unsigned int progressPercent = static_cast<unsigned int>(m_CurWriter->GetProgress()*100); + std::string stars(progressPercent, '*'); + std::string blanks(100-progressPercent, ' '); + std::cout << "\rProcessing progress: " << progressPercent << "% [" << stars << blanks << "]" << std::endl;//flush; + + Sleep(500); + } +} + + /* Enable the use of an optional parameter. Returns the previous state */ void Application::EnableParameter(std::string paramKey) { diff --git a/Code/Core/otbWrapperApplication.h b/Code/Core/otbWrapperApplication.h index 68bfa7210f98b9a221beb6c609e633052cde7032..c5e2d77173c99d38dd26afb4ffbca19c344f19d3 100644 --- a/Code/Core/otbWrapperApplication.h +++ b/Code/Core/otbWrapperApplication.h @@ -22,6 +22,8 @@ #include "otbMacro.h" #include "itkObject.h" #include "itkObjectFactory.h" +#include "otbObjectList.h" +#include "otbThreads.h" #include "otbWrapperTypes.h" #include "otbWrapperParameterGroup.h" @@ -46,8 +48,8 @@ public: typedef itk::SmartPointer<Self> Pointer; typedef itk::SmartPointer<const Self> ConstPointer; - /** Defining ::New() static method */ - //itkNewMacro(Self); + typedef ObjectList< itk::ProcessObject > ObjectListType; + typedef itk::MultiThreader ThreaderType; /** RTTI support */ itkTypeMacro(Application,itk::Object); @@ -246,6 +248,57 @@ public: */ std::vector<std::string> GetParametersKeys(bool recursive = true); + /** + * Get the progress report sources. + */ + itkSetObjectMacro( ProgressSourceList, ObjectListType ); + itkGetObjectMacro( ProgressSourceList, ObjectListType ); + + void AddProgressSource( itk::ProcessObject * obj ) + { + m_ProgressSourceList->PushBack( obj ); + this->Modified(); + } + + itk::ProcessObject * GetNthProgressSource( unsigned int i ) + { + if( m_ProgressSourceList->Size() < i ) + { + itkExceptionMacro( "invalid index "<<i<<". Only "<<m_ProgressSourceList->Size()<<" progress sources availbale." ); + } + return m_ProgressSourceList->GetNthElement( i ); + } + + /** + * Multi thread methods + */ + void StartProcess1(); + void StopProcess1(); + void StartProcess2(); + void StopProcess2(); + void StartProcess3(); + void StopProcess3(); + void StartProcess4(); + void StopProcess4(); + + void SetThreader(ThreaderType::Pointer threader) + { + m_Threader = threader; + } + ThreaderType::Pointer GetThreader() + { + return m_Threader; + } + + itkGetConstMacro(Thread1HasFinished, bool); + itkSetMacro(Thread1HasFinished, bool); + itkGetConstMacro(Thread2HasFinished, bool); + itkSetMacro(Thread2HasFinished, bool); + itkGetConstMacro(Thread3HasFinished, bool); + itkSetMacro(Thread3HasFinished, bool); + itkGetConstMacro(Thread4HasFinished, bool); + itkSetMacro(Thread4HasFinished, bool); + protected: /** Constructor */ Application(); @@ -286,7 +339,101 @@ private: std::string m_Name; std::string m_Description; ParameterGroup::Pointer m_ParameterList; + ObjectListType::Pointer m_ProgressSourceList; + + /** + * Multi thread methods + */ + static ITK_THREAD_RETURN_TYPE RunProcess1_static(void * t) + { + struct itk::MultiThreader:: ThreadInfoStruct * pInfo = (itk::MultiThreader::ThreadInfoStruct *) (t); + Application::Pointer lThis = (Application*) (pInfo->UserData); + lThis->RunProcess1(t); + return 0; + } + + + virtual void RunProcess1(void * itkNotUsed(t)) + { + //itkExceptionMacro(<< "The RunProcess1 method has to be overloaded."); + m_Thread1HasFinished = false; + this->DoExecute(); + m_Thread1HasFinished = true; + } + + + static ITK_THREAD_RETURN_TYPE RunProcess2_static(void * t) + { + struct itk::MultiThreader:: ThreadInfoStruct * pInfo = (itk::MultiThreader::ThreadInfoStruct *) (t); + Application::Pointer lThis = (Application*) (pInfo->UserData); + lThis->RunProcess2(t); + return 0; + } + + virtual void RunProcess2(void * itkNotUsed(t)) + { + //itkExceptionMacro(<< "The RunProcess2 method has to be overloaded."); + m_Thread2HasFinished = false; + this->DoWatchExecute(); + m_Thread2HasFinished = true; + } + + + static ITK_THREAD_RETURN_TYPE RunProcess3_static(void * t) + { + struct itk::MultiThreader:: ThreadInfoStruct * pInfo = (itk::MultiThreader::ThreadInfoStruct *) (t); + Application::Pointer lThis = (Application*) (pInfo->UserData); + lThis->RunProcess3(t); + return 0; + } + + virtual void RunProcess3(void * itkNotUsed(t)) + { + //itkExceptionMacro(<< "The RunProcess2 method has to be overloaded."); + m_Thread3HasFinished = false; + this->DoWriteOutput(); + m_Thread3HasFinished = true; + } + + static ITK_THREAD_RETURN_TYPE RunProcess4_static(void * t) + { + struct itk::MultiThreader:: ThreadInfoStruct * pInfo = (itk::MultiThreader::ThreadInfoStruct *) (t); + Application::Pointer lThis = (Application*) (pInfo->UserData); + lThis->RunProcess4(t); + return 0; + } + + virtual void RunProcess4(void * itkNotUsed(t)) + { + //itkExceptionMacro(<< "The RunProcess2 method has to be overloaded."); + m_Thread4HasFinished = false; + this->DoWatchWrite(); + m_Thread4HasFinished = true; + } + + + void DoWatchExecute(); + void DoWatchWrite(); + void DoWriteOutput(); + + // Internal call to openthread::Thread::microSleep + // by the intermediate of the otb class Threads + static int Sleep(unsigned int microsec) + { + return Threads::Sleep(microsec); + } + + ThreaderType::Pointer m_Threader; + int m_ThreadId1; + int m_ThreadId2; + int m_ThreadId3; + int m_ThreadId4; + bool m_Thread1HasFinished; + bool m_Thread2HasFinished; + bool m_Thread3HasFinished; + bool m_Thread4HasFinished; + itk::ProcessObject::Pointer m_CurWriter; }; //end class } // end namespace Wrapper diff --git a/Code/Core/otbWrapperOutputImageParameter.h b/Code/Core/otbWrapperOutputImageParameter.h index 79313d3d3db7ae6d34e5628ae26300e92b1ccbf6..58a35a28117f3791e69d7118e328f925352e37f9 100644 --- a/Code/Core/otbWrapperOutputImageParameter.h +++ b/Code/Core/otbWrapperOutputImageParameter.h @@ -39,6 +39,8 @@ public: typedef itk::SmartPointer<Self> Pointer; typedef itk::SmartPointer<const Self> ConstPointer; + typedef otb::StreamingImageFileWriter<VectorImageType> WriterType; + /** Defining ::New() static method */ itkNewMacro(Self); @@ -65,17 +67,17 @@ public: itkSetStringMacro(FileName); itkGetStringMacro(FileName); + + itkGetObjectMacro( Writer, WriterType ); void Write() { if (m_Image.IsNotNull()) { - typedef otb::StreamingImageFileWriter<VectorImageType> WriterType; - - WriterType::Pointer writer = WriterType::New(); - writer->SetInput(m_Image); - writer->SetFileName(this->GetFileName()); - writer->Update(); + m_Writer = WriterType::New(); + m_Writer->SetInput(m_Image); + m_Writer->SetFileName(this->GetFileName()); + m_Writer->Update(); } } @@ -85,6 +87,7 @@ protected: { this->SetName("Output Image"); this->SetKey("out"); + m_Writer = WriterType::New(); } /** Destructor */ @@ -93,6 +96,7 @@ protected: VectorImageType::Pointer m_Image; std::string m_FileName; + WriterType::Pointer m_Writer; private: OutputImageParameter(const Parameter &); //purposely not implemented diff --git a/Example/otbRescale.cxx b/Example/otbRescale.cxx index 41d088677c041dc87f9c1b1171ce4dbc0a6bcddf..c3935d04d24a11efd902a3fb4495f85918d947c1 100644 --- a/Example/otbRescale.cxx +++ b/Example/otbRescale.cxx @@ -53,6 +53,8 @@ private: SetDescription("Rescale the image between two given values."); m_RescaleFilter = RescaleImageFilterType::New(); m_MinMaxFilter = MinMaxFilterType::New(); + + this->AddProgressSource(m_MinMaxFilter); } virtual ~Rescale() @@ -76,7 +78,8 @@ private: } void DoExecute() - { + { + std::cout<<"rescale::DoExecute starts"<<std::endl; VectorImageType::Pointer inImage = GetParameterImage("in"); std::cout<<"first step"<<std::endl; @@ -104,6 +107,8 @@ private: SetParameterOutputImage("out", m_RescaleFilter->GetOutput()); std::cout<<"output updated"<<std::endl; + + std::cout<<"rescale::DoExecute starts"<<std::endl; } RescaleImageFilterType::Pointer m_RescaleFilter; diff --git a/Testing/Python/PythonRescaleTest.py b/Testing/Python/PythonRescaleTest.py index c2eaa0f6569c9e9d68fc17a2969084ae7a9a9ef2..af2a73c9aee3908b33588083e90613a0c6132842 100644 --- a/Testing/Python/PythonRescaleTest.py +++ b/Testing/Python/PythonRescaleTest.py @@ -5,9 +5,7 @@ # from sys import argv import otbApplication as otb - print "Available applications : " + str(otb.Registry.GetAvailableApplications()) - app = otb.Registry.CreateApplication("Rescale") print app.GetParametersKeys() @@ -16,6 +14,7 @@ app.SetParameterString("in", argv[1]) app.SetParameterFloat("outmin", 1) app.SetParameterFloat("outmax", 100) app.SetParameterString("out", argv[2] + ".tif") + app.Execute() print dir(app)