diff --git a/Modules/ToFHardware/Testing/mitkToFImageRecorderTest.cpp b/Modules/ToFHardware/Testing/mitkToFImageRecorderTest.cpp index 2623414640..b95a1a7dbb 100644 --- a/Modules/ToFHardware/Testing/mitkToFImageRecorderTest.cpp +++ b/Modules/ToFHardware/Testing/mitkToFImageRecorderTest.cpp @@ -1,151 +1,151 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include class mitkToFImageRecorderTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkToFImageRecorderTestSuite); //Removed due to random fails on linux continuous bug #12977 -// MITK_TEST(StartRecording_ValidDepthImage_WritesImageToFile); -// MITK_TEST(StartRecording_ValidAmplitudeImage_WritesImageToFile); -// MITK_TEST(StartRecording_ValidIntensityImage_WritesImageToFile); + MITK_TEST(StartRecording_ValidDepthImage_WritesImageToFile); + MITK_TEST(StartRecording_ValidAmplitudeImage_WritesImageToFile); + MITK_TEST(StartRecording_ValidIntensityImage_WritesImageToFile); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different (sub-)tests. All members are initialized via setUp(). * Every recorder needs a device. Here we use a player device. * The player device needs data to load. The ground truth is loaded via IOUtil. */ mitk::ToFImageRecorder::Pointer m_ToFImageRecorder; mitk::ToFCameraMITKPlayerDevice::Pointer m_PlayerDevice; std::string m_DistanceImageName; std::string m_AmplitudeImageName; std::string m_IntensityImageName; mitk::Image::Pointer m_GroundTruthDepthImage; mitk::Image::Pointer m_GroundTruthIntensityImage; mitk::Image::Pointer m_GroundTruthAmplitudeImage; public: /** * @brief Setup a recorder including a device. Here, we use a player, because in an automatic test * hardware is not useful. */ void setUp() { m_ToFImageRecorder = mitk::ToFImageRecorder::New(); m_DistanceImageName = "test_DistanceImage.nrrd"; m_AmplitudeImageName = "test_AmplitudeImage.nrrd"; m_IntensityImageName = "test_IntensityImage.nrrd"; m_PlayerDevice = mitk::ToFCameraMITKPlayerDevice::New(); m_ToFImageRecorder->SetCameraDevice(m_PlayerDevice); //the test data set has 20 frames, so we record 20 per default m_ToFImageRecorder->SetNumOfFrames(20); m_ToFImageRecorder->SetRecordMode(mitk::ToFImageRecorder::PerFrames); std::string dirName = MITK_TOF_DATA_DIR; std::string distanceFileName = dirName + "/PMDCamCube2_MF0_IT0_20Images_DistanceImage.pic"; std::string amplitudeFileName = dirName + "/PMDCamCube2_MF0_IT0_20Images_AmplitudeImage.pic"; std::string intensityFileName = dirName + "/PMDCamCube2_MF0_IT0_20Images_IntensityImage.pic"; m_PlayerDevice->SetProperty("DistanceImageFileName",mitk::StringProperty::New(distanceFileName)); m_PlayerDevice->SetProperty("AmplitudeImageFileName",mitk::StringProperty::New(amplitudeFileName)); m_PlayerDevice->SetProperty("IntensityImageFileName",mitk::StringProperty::New(intensityFileName)); //comparing against IOUtil seems fair enough m_GroundTruthDepthImage = mitk::IOUtil::LoadImage(distanceFileName); m_GroundTruthAmplitudeImage = mitk::IOUtil::LoadImage(amplitudeFileName); m_GroundTruthIntensityImage = mitk::IOUtil::LoadImage(intensityFileName); m_PlayerDevice->ConnectCamera(); m_PlayerDevice->StartCamera(); } void tearDown() { m_PlayerDevice->StopCamera(); m_PlayerDevice->DisconnectCamera(); } void StartRecording_ValidDepthImage_WritesImageToFile() { m_ToFImageRecorder->SetDistanceImageFileName(m_DistanceImageName); m_ToFImageRecorder->StartRecording(); m_ToFImageRecorder->WaitForThreadBeingTerminated(); // wait to allow recording m_ToFImageRecorder->StopRecording(); mitk::Image::Pointer recordedImage = mitk::IOUtil::LoadImage(m_DistanceImageName); MITK_ASSERT_EQUAL( m_GroundTruthDepthImage, recordedImage, "Recorded image should be equal to the test data."); if( remove( m_DistanceImageName.c_str() ) != 0 ) { MITK_ERROR<<"File: test_distance.nrrd not successfully deleted!"; } } void StartRecording_ValidAmplitudeImage_WritesImageToFile() { m_ToFImageRecorder->SetAmplitudeImageFileName(m_AmplitudeImageName); m_ToFImageRecorder->SetAmplitudeImageSelected(true); m_ToFImageRecorder->SetDistanceImageSelected(false); m_ToFImageRecorder->StartRecording(); m_ToFImageRecorder->WaitForThreadBeingTerminated(); // wait to allow recording m_ToFImageRecorder->StopRecording(); mitk::Image::Pointer recordedImage = mitk::IOUtil::LoadImage(m_AmplitudeImageName); MITK_ASSERT_EQUAL( m_GroundTruthAmplitudeImage, recordedImage, "Recorded image should be equal to the test data."); if( remove( m_AmplitudeImageName.c_str() ) != 0 ) { MITK_ERROR<<"File: test_amplitude.nrrd not successfully deleted!"; } } void StartRecording_ValidIntensityImage_WritesImageToFile() { m_ToFImageRecorder->SetIntensityImageFileName(m_IntensityImageName); m_ToFImageRecorder->SetIntensityImageSelected(true); m_ToFImageRecorder->SetDistanceImageSelected(false); m_ToFImageRecorder->StartRecording(); m_ToFImageRecorder->WaitForThreadBeingTerminated(); // wait to allow recording m_ToFImageRecorder->StopRecording(); mitk::Image::Pointer recordedImage = mitk::IOUtil::LoadImage(m_IntensityImageName); MITK_ASSERT_EQUAL( m_GroundTruthIntensityImage, recordedImage, "Recorded image should be equal to the test data."); if( remove( m_IntensityImageName.c_str() ) != 0 ) { MITK_ERROR<<"File: test_intensity.nrrd not successfully deleted!"; } } }; MITK_TEST_SUITE_REGISTRATION(mitkToFImageRecorder) diff --git a/Modules/ToFHardware/mitkToFImageRecorder.cpp b/Modules/ToFHardware/mitkToFImageRecorder.cpp index 7eb8605e30..3ad365601b 100644 --- a/Modules/ToFHardware/mitkToFImageRecorder.cpp +++ b/Modules/ToFHardware/mitkToFImageRecorder.cpp @@ -1,268 +1,316 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkToFImageRecorder.h" #include "mitkRealTimeClock.h" #include "itkMultiThreader.h" #include #pragma GCC visibility push(default) #include #pragma GCC visibility pop namespace mitk { ToFImageRecorder::ToFImageRecorder() { this->m_ToFCameraDevice = NULL; this->m_MultiThreader = itk::MultiThreader::New(); this->m_AbortMutex = itk::FastMutexLock::New(); this->m_ThreadID = 0; this->m_NumOfFrames = 1; //lets record one frame per default this->m_ToFImageWriter = NULL; this->m_DistanceImageSelected = true; //lets assume a device only has depth data by default this->m_AmplitudeImageSelected = false; this->m_IntensityImageSelected = false; this->m_RGBImageSelected = false; this->m_Abort = false; this->m_ToFCaptureWidth = 0; this->m_ToFCaptureHeight = 0; this->m_RGBCaptureWidth = 0; this->m_RGBCaptureHeight = 0; this->m_FileFormat = ".nrrd"; //lets make nrrd the default this->m_ToFPixelNumber = 0; this->m_RGBPixelNumber = 0; this->m_SourceDataSize = 0; this->m_ToFImageType = ToFImageWriter::ToFImageType3D; this->m_RecordMode = ToFImageRecorder::PerFrames; this->m_DistanceImageFileName = ""; this->m_AmplitudeImageFileName = ""; this->m_IntensityImageFileName = ""; this->m_RGBImageFileName = ""; this->m_ImageSequence = 0; this->m_DistanceArray = NULL; this->m_AmplitudeArray = NULL; this->m_IntensityArray = NULL; this->m_RGBArray = NULL; this->m_SourceDataArray = NULL; } ToFImageRecorder::~ToFImageRecorder() { delete[] m_DistanceArray; delete[] m_AmplitudeArray; delete[] m_IntensityArray; delete[] m_RGBArray; delete[] m_SourceDataArray; } void ToFImageRecorder::StopRecording() { this->m_AbortMutex->Lock(); this->m_Abort = true; this->m_AbortMutex->Unlock(); } void ToFImageRecorder::StartRecording() { if (this->m_ToFCameraDevice.IsNull()) { throw std::invalid_argument("ToFCameraDevice is NULL."); return; } if (this->m_FileFormat.compare(".csv") == 0) { this->m_ToFImageWriter = ToFImageCsvWriter::New(); } else if(this->m_FileFormat.compare(".nrrd") == 0) { this->m_ToFImageWriter = ToFNrrdImageWriter::New(); this->m_ToFImageWriter->SetExtension(m_FileFormat); } else { throw std::logic_error("No file format specified!"); } this->m_RGBCaptureWidth = this->m_ToFCameraDevice->GetRGBCaptureWidth(); this->m_RGBCaptureHeight = this->m_ToFCameraDevice->GetRGBCaptureHeight(); this->m_RGBPixelNumber = this->m_RGBCaptureWidth * this->m_RGBCaptureHeight; this->m_ToFCaptureWidth = this->m_ToFCameraDevice->GetCaptureWidth(); this->m_ToFCaptureHeight = this->m_ToFCameraDevice->GetCaptureHeight(); this->m_ToFPixelNumber = this->m_ToFCaptureWidth * this->m_ToFCaptureHeight; this->m_SourceDataSize = this->m_ToFCameraDevice->GetSourceDataSize(); // allocate buffer if(m_IntensityArray == NULL) { this->m_IntensityArray = new float[m_ToFPixelNumber]; } if(this->m_DistanceArray == NULL) { this->m_DistanceArray = new float[m_ToFPixelNumber]; } if(this->m_AmplitudeArray == NULL) { this->m_AmplitudeArray = new float[m_ToFPixelNumber]; } if(this->m_RGBArray == NULL) { this->m_RGBArray = new unsigned char[m_RGBPixelNumber*3]; } if(this->m_SourceDataArray == NULL) { this->m_SourceDataArray = new char[m_SourceDataSize]; } this->m_ToFImageWriter->SetDistanceImageFileName(this->m_DistanceImageFileName); this->m_ToFImageWriter->SetAmplitudeImageFileName(this->m_AmplitudeImageFileName); this->m_ToFImageWriter->SetIntensityImageFileName(this->m_IntensityImageFileName); this->m_ToFImageWriter->SetRGBImageFileName(this->m_RGBImageFileName); this->m_ToFImageWriter->SetRGBCaptureWidth(this->m_RGBCaptureWidth); this->m_ToFImageWriter->SetRGBCaptureHeight(this->m_RGBCaptureHeight); //this->m_ToFImageWriter->SetToFCaptureHeight(this->m_ToFCaptureHeight); this->m_ToFImageWriter->SetToFCaptureWidth(this->m_ToFCaptureWidth); this->m_ToFImageWriter->SetToFCaptureHeight(this->m_ToFCaptureHeight); this->m_ToFImageWriter->SetToFImageType(this->m_ToFImageType); this->m_ToFImageWriter->SetDistanceImageSelected(this->m_DistanceImageSelected); this->m_ToFImageWriter->SetAmplitudeImageSelected(this->m_AmplitudeImageSelected); this->m_ToFImageWriter->SetIntensityImageSelected(this->m_IntensityImageSelected); this->m_ToFImageWriter->SetRGBImageSelected(this->m_RGBImageSelected); this->m_ToFImageWriter->Open(); this->m_AbortMutex->Lock(); this->m_Abort = false; this->m_AbortMutex->Unlock(); - this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->RecordData, this); +// this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->RecordData, this); + + ToFCameraDevice::Pointer toFCameraDevice = this->GetCameraDevice(); + + mitk::RealTimeClock::Pointer realTimeClock; + realTimeClock = mitk::RealTimeClock::New(); + double t1 = 0; + t1 = realTimeClock->GetCurrentStamp(); + int requiredImageSequence = 0; + int numOfFramesRecorded = 0; + + bool abort = false; + this->m_AbortMutex->Lock(); + abort = this->m_Abort; + this->m_AbortMutex->Unlock(); + + while ( !abort ) + { + if ( ((this->m_RecordMode == ToFImageRecorder::PerFrames) && (numOfFramesRecorded < this->m_NumOfFrames)) || + (this->m_RecordMode == ToFImageRecorder::Infinite) ) + { + + toFCameraDevice->GetAllImages(this->m_DistanceArray, this->m_AmplitudeArray, + this->m_IntensityArray, this->m_SourceDataArray, requiredImageSequence, this->m_ImageSequence, this->m_RGBArray ); + + if (this->m_ImageSequence >= requiredImageSequence) + { + if (this->m_ImageSequence > requiredImageSequence) + { + MITK_INFO << "Problem! required: " << requiredImageSequence << " captured: " << this->m_ImageSequence; + } + requiredImageSequence = this->m_ImageSequence + 1; + this->m_ToFImageWriter->Add( this->m_DistanceArray, + this->m_AmplitudeArray, this->m_IntensityArray, this->m_RGBArray ); + numOfFramesRecorded++; + } + this->m_AbortMutex->Lock(); + abort = this->m_Abort; + this->m_AbortMutex->Unlock(); + } + else + { + abort = true; + } + } // end of while loop + + this->InvokeEvent(itk::AbortEvent()); + + this->m_ToFImageWriter->Close(); } void ToFImageRecorder::WaitForThreadBeingTerminated() { this->m_MultiThreader->TerminateThread(this->m_ThreadID); } ITK_THREAD_RETURN_TYPE ToFImageRecorder::RecordData(void* pInfoStruct) { struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } ToFImageRecorder* toFImageRecorder = (ToFImageRecorder*)pInfo->UserData; if (toFImageRecorder!=NULL) { ToFCameraDevice::Pointer toFCameraDevice = toFImageRecorder->GetCameraDevice(); mitk::RealTimeClock::Pointer realTimeClock; realTimeClock = mitk::RealTimeClock::New(); int n = 100; double t1 = 0; double t2 = 0; t1 = realTimeClock->GetCurrentStamp(); bool overflow = false; bool printStatus = false; int requiredImageSequence = 0; int numOfFramesRecorded = 0; bool abort = false; toFImageRecorder->m_AbortMutex->Lock(); abort = toFImageRecorder->m_Abort; toFImageRecorder->m_AbortMutex->Unlock(); while ( !abort ) { if ( ((toFImageRecorder->m_RecordMode == ToFImageRecorder::PerFrames) && (numOfFramesRecorded < toFImageRecorder->m_NumOfFrames)) || (toFImageRecorder->m_RecordMode == ToFImageRecorder::Infinite) ) { toFCameraDevice->GetAllImages(toFImageRecorder->m_DistanceArray, toFImageRecorder->m_AmplitudeArray, toFImageRecorder->m_IntensityArray, toFImageRecorder->m_SourceDataArray, requiredImageSequence, toFImageRecorder->m_ImageSequence, toFImageRecorder->m_RGBArray ); if (toFImageRecorder->m_ImageSequence >= requiredImageSequence) { if (toFImageRecorder->m_ImageSequence > requiredImageSequence) { MITK_INFO << "Problem! required: " << requiredImageSequence << " captured: " << toFImageRecorder->m_ImageSequence; } requiredImageSequence = toFImageRecorder->m_ImageSequence + 1; toFImageRecorder->m_ToFImageWriter->Add( toFImageRecorder->m_DistanceArray, toFImageRecorder->m_AmplitudeArray, toFImageRecorder->m_IntensityArray, toFImageRecorder->m_RGBArray ); numOfFramesRecorded++; if (numOfFramesRecorded % n == 0) { printStatus = true; } if (printStatus) { t2 = realTimeClock->GetCurrentStamp() - t1; MITK_INFO << " Framerate (fps): " << n / (t2/1000) << " Sequence: " << toFImageRecorder->m_ImageSequence; t1 = realTimeClock->GetCurrentStamp(); printStatus = false; } } toFImageRecorder->m_AbortMutex->Lock(); abort = toFImageRecorder->m_Abort; toFImageRecorder->m_AbortMutex->Unlock(); } else { abort = true; } } // end of while loop toFImageRecorder->InvokeEvent(itk::AbortEvent()); toFImageRecorder->m_ToFImageWriter->Close(); } return ITK_THREAD_RETURN_VALUE; } void ToFImageRecorder::SetCameraDevice(ToFCameraDevice* aToFCameraDevice) { this->m_ToFCameraDevice = aToFCameraDevice; } ToFCameraDevice* ToFImageRecorder::GetCameraDevice() { return this->m_ToFCameraDevice; } ToFImageWriter::ToFImageType ToFImageRecorder::GetToFImageType() { return this->m_ToFImageType; } void ToFImageRecorder::SetToFImageType(ToFImageWriter::ToFImageType toFImageType) { this->m_ToFImageType = toFImageType; } ToFImageRecorder::RecordMode ToFImageRecorder::GetRecordMode() { return this->m_RecordMode; } void ToFImageRecorder::SetRecordMode(ToFImageRecorder::RecordMode recordMode) { this->m_RecordMode = recordMode; } }