diff --git a/Modules/IGT/IGTFilters/mitkNavigationDataRecorder.cpp b/Modules/IGT/IGTFilters/mitkNavigationDataRecorder.cpp index 79379b396a..816471362e 100644 --- a/Modules/IGT/IGTFilters/mitkNavigationDataRecorder.cpp +++ b/Modules/IGT/IGTFilters/mitkNavigationDataRecorder.cpp @@ -1,309 +1,325 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2007-12-11 14:46:19 +0100 (Di, 11 Dez 2007) $ Version: $Revision: 13129 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkNavigationDataRecorder.h" #include #include #include #include mitk::NavigationDataRecorder::NavigationDataRecorder() { //set default values m_NumberOfInputs = 0; m_RecordingMode = NormalFile; m_Recording = false; m_NumberOfRecordedFiles = 0; m_Stream = NULL; m_FileName = ""; m_SystemTimeClock = RealTimeClock::New(); m_OutputFormat = mitk::NavigationDataRecorder::xml; m_RecordCounter = 0; m_RecordCountLimit = -1; + m_DoNotOverwriteFiles = false; //To get a start time mitk::TimeStamp::GetInstance()->Start(this); } mitk::NavigationDataRecorder::~NavigationDataRecorder() { } void mitk::NavigationDataRecorder::GenerateData() { } void mitk::NavigationDataRecorder::AddNavigationData( const NavigationData* nd ) { // Process object is not const-correct so the const_cast is required here this->SetNthInput(m_NumberOfInputs, const_cast< mitk::NavigationData * >( nd ) ); m_NumberOfInputs++; this->Modified(); } void mitk::NavigationDataRecorder::SetRecordingMode( RecordingMode mode ) { m_RecordingMode = mode; this->Modified(); } void mitk::NavigationDataRecorder::Update() { if (m_Recording) { DataObjectPointerArray inputs = this->GetInputs(); //get all inputs mitk::NavigationData::TimeStampType timestamp=0.0; // timestamp for mitk time timestamp = mitk::TimeStamp::GetInstance()->GetElapsed(); mitk::NavigationData::TimeStampType sysTimestamp = 0.0; // timestamp for system time sysTimestamp = m_SystemTimeClock->GetCurrentStamp(); // cast system time double value to stringstream to avoid low precision rounding std::ostringstream strs; strs.precision(15); // rounding precision for system time double value strs << sysTimestamp; std::string sysTimeStr = strs.str(); //if csv-mode: write csv header and timpstamp at beginning if (m_OutputFormat == mitk::NavigationDataRecorder::csv) { //write header only when it's the first line if (m_firstLine) { m_firstLine = false; *m_Stream << "TimeStamp"; for (unsigned int index = 0; index < inputs.size(); index++){ *m_Stream << ";Valid_Tool" << index << ";X_Tool" << index << ";Y_Tool" << index << ";Z_Tool" << index << ";QX_Tool" << index << ";QY_Tool" << index << ";QZ_Tool" << index << ";QR_Tool" << index;} *m_Stream << "\n"; } //write timestamp (always) *m_Stream << timestamp; } //write tool data for every tool for (unsigned int index = 0; index < inputs.size(); index++) { mitk::NavigationData* nd = dynamic_cast(inputs[index].GetPointer()); nd->Update(); // call update to propagate update to previous filters mitk::NavigationData::PositionType position; mitk::NavigationData::OrientationType orientation(0.0, 0.0, 0.0, 0.0); mitk::NavigationData::CovarianceMatrixType matrix; bool hasPosition = true; bool hasOrientation = true; bool dataValid = false; position.Fill(0.0); matrix.SetIdentity(); position = nd->GetPosition(); orientation = nd->GetOrientation(); matrix = nd->GetCovErrorMatrix(); hasPosition = nd->GetHasPosition(); hasOrientation = nd->GetHasOrientation(); dataValid = nd->IsDataValid(); //use this one if you want the timestamps of the source //timestamp = nd->GetTimeStamp(); //a timestamp is never < 0! this case happens only if you are using the timestamp of the nd object instead of getting a new one if (timestamp >= 0) { if (this->m_OutputFormat == mitk::NavigationDataRecorder::xml) { TiXmlElement* elem = new TiXmlElement("NavigationData"); elem->SetDoubleAttribute("Time", timestamp); elem->SetAttribute("SystemTime", sysTimeStr); // tag for system time elem->SetDoubleAttribute("Tool", index); elem->SetDoubleAttribute("X", position[0]); elem->SetDoubleAttribute("Y", position[1]); elem->SetDoubleAttribute("Z", position[2]); elem->SetDoubleAttribute("QX", orientation[0]); elem->SetDoubleAttribute("QY", orientation[1]); elem->SetDoubleAttribute("QZ", orientation[2]); elem->SetDoubleAttribute("QR", orientation[3]); elem->SetDoubleAttribute("C00", matrix[0][0]); elem->SetDoubleAttribute("C01", matrix[0][1]); elem->SetDoubleAttribute("C02", matrix[0][2]); elem->SetDoubleAttribute("C03", matrix[0][3]); elem->SetDoubleAttribute("C04", matrix[0][4]); elem->SetDoubleAttribute("C05", matrix[0][5]); elem->SetDoubleAttribute("C10", matrix[1][0]); elem->SetDoubleAttribute("C11", matrix[1][1]); elem->SetDoubleAttribute("C12", matrix[1][2]); elem->SetDoubleAttribute("C13", matrix[1][3]); elem->SetDoubleAttribute("C14", matrix[1][4]); elem->SetDoubleAttribute("C15", matrix[1][5]); if (dataValid) elem->SetAttribute("Valid",1); else elem->SetAttribute("Valid",0); if (hasOrientation) elem->SetAttribute("hO",1); else elem->SetAttribute("hO",0); if (hasPosition) elem->SetAttribute("hP",1); else elem->SetAttribute("hP",0); *m_Stream << " " << *elem << std::endl; delete elem; } else if (this->m_OutputFormat == mitk::NavigationDataRecorder::csv) { *m_Stream << ";" << dataValid << ";" << position[0] << ";" << position[1] << ";" << position[2] << ";" << orientation[0] << ";" << orientation[1] << ";" << orientation[2] << ";" << orientation[3]; } } } if (this->m_OutputFormat == mitk::NavigationDataRecorder::csv) { *m_Stream << "\n"; } } m_RecordCounter++; if ((m_RecordCountLimit<=m_RecordCounter)&&(m_RecordCountLimit != -1)) {StopRecording();} } void mitk::NavigationDataRecorder::StartRecording() { if (m_Recording) { std::cout << "Already recording please stop before start new recording session" << std::endl; return; } if (m_Stream == NULL) { std::stringstream ss; std::ostream* stream; //An existing extension will be cut and replaced with .xml std::string tmpPath = itksys::SystemTools::GetFilenamePath(m_FileName); m_FileName = itksys::SystemTools::GetFilenameWithoutExtension(m_FileName); - if (m_OutputFormat == mitk::NavigationDataRecorder::csv) ss << tmpPath << "/" << m_FileName << "-" << m_NumberOfRecordedFiles << ".csv"; - else ss << tmpPath << "/" << m_FileName << "-" << m_NumberOfRecordedFiles << ".xml"; + std::string extension = ".xml"; + if (m_OutputFormat == mitk::NavigationDataRecorder::csv) + extension = ".csv"; + + ss << tmpPath << "/" << m_FileName << "-" << m_NumberOfRecordedFiles << extension; + + if( m_DoNotOverwriteFiles ) + { + unsigned int index = m_NumberOfRecordedFiles+1; + while( itksys::SystemTools::FileExists( ss.str().c_str() ) ) + { + ss.str(""); + ss << tmpPath << "/" << m_FileName << "-" << index << extension; + index++; + } + } + switch(m_RecordingMode) { case Console: stream = &std::cout; break; case NormalFile: //Check if there is a file name and path if (m_FileName == "") { stream = &std::cout; std::cout << "No file name or file path set the output is redirected to the console"; } else { stream = new std::ofstream(ss.str().c_str()); } break; case ZipFile: stream = &std::cout; std::cout << "Sorry no ZipFile support yet"; break; default: stream = &std::cout; break; } m_firstLine = true; m_RecordCounter = 0; StartRecording(stream); } } void mitk::NavigationDataRecorder::StartRecording(std::ostream* stream) { if (m_Recording) { std::cout << "Already recording please stop before start new recording session" << std::endl; return; } m_Stream = stream; m_Stream->precision(10); //TODO store date and GMT time if (m_Stream) { if (m_OutputFormat == mitk::NavigationDataRecorder::xml) { *m_Stream << "" << std::endl; /**m_Stream << "" << std::endl;*/ // should be a generic version, meaning a member variable, which has the actual version *m_Stream << " " << "" << std::endl; } m_Recording = true; } } void mitk::NavigationDataRecorder::StopRecording() { if (!m_Recording) { std::cout << "You have to start a recording first" << std::endl; return; } if ((m_Stream) && (m_OutputFormat == mitk::NavigationDataRecorder::xml)) { *m_Stream << "" << std::endl; } m_NumberOfRecordedFiles++; m_Recording = false; m_Stream->flush(); m_Stream = NULL; } \ No newline at end of file diff --git a/Modules/IGT/IGTFilters/mitkNavigationDataRecorder.h b/Modules/IGT/IGTFilters/mitkNavigationDataRecorder.h index a7801a076c..f0f22a4ff7 100644 --- a/Modules/IGT/IGTFilters/mitkNavigationDataRecorder.h +++ b/Modules/IGT/IGTFilters/mitkNavigationDataRecorder.h @@ -1,186 +1,193 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-02-08 13:23:19 +0100 (Fr, 08 Feb 2008) $ Version: $Revision: 13561 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _MITK_NavigationDataRecorder_H #define _MITK_NavigationDataRecorder_H #include #include "mitkNavigationData.h" #include #include namespace mitk { /**Documentation * \brief This class records NavigationData objects. * * The output of this class is formated as a XML document. * * Internal this class uses streams for recording NavigationData objects. Therefore different types of output are possible * and can be set with the SetOutputMode() method. The default output is directed to the console. If you want to save into a * file you have to set a file name and the path. The recording is started with the call of the method StartRecording(). Now * every Update() stores the current state of the added NavigationDatas. With StopRecording() the stream is stopped. With * another call of StartRecording() the output is written to a new file with incremented filename counter. * * \warning At the moment there is no check if the file is already existing and this class will override existing files. * \ingroup IGT */ class MitkIGT_EXPORT NavigationDataRecorder : public itk::ProcessObject { public: mitkClassMacro( NavigationDataRecorder, itk::ProcessObject ); itkNewMacro( Self ); /** * \brief sets the file name for the OutputMode NormalFile and ZipFile * * Any extensions will be cut * \warning existing files will be overridden * \warning do not use "." in file names at the end */ itkSetStringMacro(FileName); /** * \brief Returns the file name of the recording file (in OutputMode NormalFile and ZipFile) */ itkGetStringMacro(FileName); + /** + * \brief If true the recorder will never overwrite a file + */ + itkSetMacro(DoNotOverwriteFiles,bool); + /** * \brief Returns whether the NavigationDataRecorder is recording or not */ itkGetMacro(Recording,bool); /** * \brief Returns the number of data sets / frames which were recorded by the NavigationDataRecorder since start */ itkGetMacro(RecordCounter,int); /** * \brief Sets a limit of recorded data sets / frames. Recording will be stopped if the number is reached. -1 disables the limit, -1 is default value as well. */ itkSetMacro(RecordCountLimit,int); /** * \brief Adds the input NavigationDatas */ virtual void AddNavigationData(const NavigationData* nd); /**Documentation * \brief Starts the recording with the presetted OutputMode * this method calls StartRecording(std::ostream*) */ void StartRecording(); /**Documentation * \brief Starts the recording with an own preinitialized stream */ void StartRecording(std::ostream* stream); /**Documentation * \brief Stops the recording and closes the stream */ void StopRecording(); /**Documentation * \brief Every call of update causes one line for each added NavigationData in the output if the recording was started */ virtual void Update(); /**Documentation * \brief Determines where the output is directed to * * Console: std::cout * NormalFile: std::ofstream * ZipFile: Not supported yet -> std::cout */ enum RecordingMode { Console, NormalFile, ZipFile }; /**Documentation * \brief Determines the output format * * xml: XML format, also default, can be read by NavigationDataPlayer * csv: use to export in excel, matlab, etc. */ enum OutputFormatEnum { xml, csv }; /**Documentation * \brief Sets the recording mode which causes different types of output streams * see enum RecordingMode */ void SetRecordingMode(RecordingMode mode); /**Documentation * \brief Sets the output format which causes different formats of output streams. The XML format is default. * Also see enum OutputFormat for more information. */ itkSetMacro(OutputFormat,mitk::NavigationDataRecorder::OutputFormatEnum); protected: /**Documentation * \brief filter execute method here it is not used * */ virtual void GenerateData(); NavigationDataRecorder(); virtual ~NavigationDataRecorder(); std::string m_FileName; ///< stores the file name and path unsigned int m_NumberOfInputs; ///< counts the numbers of added input NavigationDatas std::ostream* m_Stream; ///< the output stream RecordingMode m_RecordingMode; ///< stores the mode see enum RecordingMode OutputFormatEnum m_OutputFormat; ///< stores the output format; see enum OutputFormat bool m_Recording; ///< indicates whether the recording is started or not int m_RecordCounter; ///< counts the number of frames which are recorded since StartRecording int m_RecordCountLimit; ///< limits the number of frames, recording will be stopped if the limit is reached. -1 disables the limit bool m_firstLine; //for the csv writer to detect wether the header must be written unsigned int m_NumberOfRecordedFiles; ///< necessary for the naming of the file if there is more than one start-stop cycle mitk::RealTimeClock::Pointer m_SystemTimeClock; ///< system time clock for system time tag in output xml file + bool m_DoNotOverwriteFiles; ///< do not overwrite any files if true + }; } #endif // #define _MITK_POINT_SET_SOURCE_H diff --git a/Modules/IGT/IGTTrackingDevices/mitkSerialCommunication.cpp b/Modules/IGT/IGTTrackingDevices/mitkSerialCommunication.cpp index b6712f834c..c36d25015d 100644 --- a/Modules/IGT/IGTTrackingDevices/mitkSerialCommunication.cpp +++ b/Modules/IGT/IGTTrackingDevices/mitkSerialCommunication.cpp @@ -1,442 +1,442 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkSerialCommunication.h" #ifdef WIN32 //#include #include #else // Posix #include #include #include #include #include #include #include #include #define INVALID_HANDLE_VALUE -1 #endif #define OK 1 #define ERROR_VALUE 0 mitk::SerialCommunication::SerialCommunication() : itk::Object(), m_DeviceName(""), m_PortNumber(COM1), m_BaudRate(BaudRate9600), m_DataBits(DataBits8), m_Parity(None), m_StopBits(StopBits1), m_HardwareHandshake(HardwareHandshakeOff), m_ReceiveTimeout(500), m_SendTimeout(500), m_Connected(false) { #ifdef WIN32 // Windows m_ComPortHandle = INVALID_HANDLE_VALUE; #else // Posix m_FileDescriptor = INVALID_HANDLE_VALUE; #endif } mitk::SerialCommunication::~SerialCommunication() { CloseConnection(); } int mitk::SerialCommunication::OpenConnection() { if (m_Connected) return ERROR_VALUE; #ifdef WIN32 std::stringstream ss; if (m_DeviceName.empty()) - ss << "COM" << static_cast(m_PortNumber); // use m_PortNumber + ss << "\\\\.\\COM" << static_cast(m_PortNumber); // use m_PortNumber else - ss << m_DeviceName; // use m_DeviceName + ss << "\\\\.\\" << m_DeviceName; // use m_DeviceName m_ComPortHandle = CreateFile(ss.str().c_str(), GENERIC_READ | GENERIC_WRITE, NULL, /* no sharing */ NULL, /* no security flags */ OPEN_EXISTING, /* open com port, don't create it */ NULL, /* no flags */ NULL); /* no template */ if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; GetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock); GetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout); GetCommMask(m_ComPortHandle, &m_PreviousMask); if (this->ApplyConfiguration() != OK) // set interface parameters { CloseHandle(m_ComPortHandle); m_ComPortHandle = INVALID_HANDLE_VALUE; return ERROR_VALUE; } m_Connected = true; return OK; #else // Posix std::stringstream ss; if (m_DeviceName.empty()) ss << "/dev/ttyS" << static_cast(m_PortNumber) - 1; // use m_PortNumber, COM1 = ttyS0 else ss << m_DeviceName; // use m_DeviceName //m_FileDescriptor = open(ss.str().c_str(), O_RDWR | O_NONBLOCK | O_NDELAY | O_NOCTTY | O_EXCL); // open device file m_FileDescriptor = open(ss.str().c_str(), O_RDWR|O_NONBLOCK|O_EXCL); // open device file if (m_FileDescriptor < 0) return ERROR_VALUE; fcntl(m_FileDescriptor, F_SETFL, 0); // change to blocking mode tcflush(m_FileDescriptor, TCIOFLUSH); // flush buffers if (this->ApplyConfiguration() != OK) // set interface parameters { close(m_FileDescriptor); m_FileDescriptor = INVALID_HANDLE_VALUE; return ERROR_VALUE; } m_Connected = true; return OK; #endif } void mitk::SerialCommunication::CloseConnection() { #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return; ClearReceiveBuffer(); ClearSendBuffer(); SetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock); // restore previous settings SetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout); // restore previous timeout values SetCommMask(m_ComPortHandle, m_PreviousMask); // restore previous mask value PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // empty buffers CloseHandle(m_ComPortHandle); // close handle m_ComPortHandle = INVALID_HANDLE_VALUE; m_Connected = false; return; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return; ClearReceiveBuffer(); ClearSendBuffer(); close(m_FileDescriptor); m_FileDescriptor = INVALID_HANDLE_VALUE; m_Connected = false; return; #endif } int mitk::SerialCommunication::Receive(std::string& answer, unsigned int numberOfBytes) { if (numberOfBytes == 0) return OK; if (m_Connected == false) return ERROR_VALUE; #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DWORD numberOfBytesRead = 0; char* buffer = new char[numberOfBytes]; if (ReadFile(m_ComPortHandle, buffer, numberOfBytes, &numberOfBytesRead, NULL) != 0) { if (numberOfBytesRead > 0) // data read { answer.assign(buffer, numberOfBytesRead); // copy buffer to answer delete buffer; if (numberOfBytesRead == numberOfBytes) { return OK; // everything was received } else { return ERROR_VALUE; // some data was received, but not as much as expected } } else // error { answer = ""; delete buffer; return ERROR_VALUE; } } delete buffer; return OK; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return ERROR_VALUE; unsigned long bytesRead = 0; unsigned long bytesLeft = numberOfBytes; char* buffer = new char[numberOfBytes]; while ((bytesLeft > 0) && (bytesRead < numberOfBytes)) { int num = read(m_FileDescriptor, &buffer[bytesRead], 1); // read one byte if (num == -1) // ERROR_VALUE { if (errno == EAGAIN) // nonblocking, no byte there right now, but maybe next time continue; else break; // ERROR_VALUE, stop trying to read } if (num == 0) // timeout or eof(?) break; bytesLeft -= num; // n is number of chars left to read bytesRead += num; // i is the number of chars read } if (bytesRead > 0) answer.assign(buffer, bytesRead); // copy buffer to answer delete buffer; if (bytesRead == numberOfBytes) return OK; // everything was received else return ERROR_VALUE; // some data was received, but not as much as expected #endif } int mitk::SerialCommunication::Send(const std::string& input) { //long retval = E2ERR_OPENFAILED; if (input.empty()) return OK; if (m_Connected == false) return ERROR_VALUE; #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DWORD bytesWritten = 0; if (WriteFile(m_ComPortHandle, input.data(), static_cast(input.size()), &bytesWritten, NULL) == TRUE) return OK; else return GetLastError(); #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return ERROR_VALUE; long bytesWritten = 0; long bytesLeft = input.size(); while (bytesLeft > 0) { bytesWritten = write(m_FileDescriptor, input.data() + bytesWritten, bytesLeft); if (bytesWritten <= 0) return ERROR_VALUE; //return ERROR_VALUE bytesLeft -= bytesWritten; } return OK; #endif } int mitk::SerialCommunication::ApplyConfiguration() { #ifdef WIN32 // Windows implementation if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DCB controlSettings; if (GetCommState(m_ComPortHandle, &controlSettings) == 0) { return ERROR_VALUE; } std::ostringstream o; o << "baud=" << m_BaudRate << " parity=" << static_cast(m_Parity) << " data=" << m_DataBits << " stop=" << m_StopBits; if (BuildCommDCBA(o.str().c_str(), &controlSettings) == 0) // Build device-control block return ERROR_VALUE; if (m_HardwareHandshake == HardwareHandshakeOn) // Modify hardware handshake values { controlSettings.fDtrControl = DTR_CONTROL_ENABLE; controlSettings.fRtsControl = RTS_CONTROL_ENABLE; controlSettings.fOutxCtsFlow = TRUE; controlSettings.fRtsControl = RTS_CONTROL_HANDSHAKE; } else { controlSettings.fDtrControl = DTR_CONTROL_DISABLE; controlSettings.fRtsControl = RTS_CONTROL_DISABLE; controlSettings.fOutxCtsFlow = FALSE; controlSettings.fRtsControl = RTS_CONTROL_DISABLE; } if (SetCommState(m_ComPortHandle, &controlSettings) == FALSE) // Configure com port return GetLastError(); COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = m_ReceiveTimeout; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = m_ReceiveTimeout; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = m_SendTimeout; if (SetCommTimeouts(m_ComPortHandle, &timeouts) == FALSE) // set timeout values return GetLastError(); PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // clear read and write buffers return OK; #else // Posix if ( m_FileDescriptor == INVALID_HANDLE_VALUE ) return ERROR_VALUE; struct termios termIOStructure; if ( tcgetattr(m_FileDescriptor, &termIOStructure) != 0 ) // retrieve parameters from com port return ERROR_VALUE; cfmakeraw(&termIOStructure); // set flags to raw mode termIOStructure.c_cflag |= CLOCAL; if (m_HardwareHandshake == HardwareHandshakeOn) { // enable termIOStructure.c_cflag |= CRTSCTS; termIOStructure.c_iflag &= ~(IXON|IXOFF); } else { // disable termIOStructure.c_cflag &= ~CRTSCTS; termIOStructure.c_iflag &= ~(IXON|IXOFF); } termIOStructure.c_cflag &= ~CSIZE; // set number of data bits switch (m_DataBits) { case DataBits7: termIOStructure.c_cflag |= CS7; break; case DataBits8: default: termIOStructure.c_cflag |= CS8; } switch (m_StopBits) // set number of stop bits { case StopBits2: termIOStructure.c_cflag |= CSTOPB; break; case StopBits1: default: termIOStructure.c_cflag &= ~CSTOPB; } switch (m_Parity) // set parity { case Odd: termIOStructure.c_cflag |= (PARENB|PARODD); break; case Even: termIOStructure.c_cflag |= PARENB; termIOStructure.c_cflag &= ~PARODD; case None: default: termIOStructure.c_cflag &= ~PARENB; break; } speed_t baudrate; // set baudrate switch (m_BaudRate) { case BaudRate9600: baudrate = B9600; break; case BaudRate14400: baudrate = B9600; //14400 is not defined for posix, use 9600 instead break; case BaudRate19200: baudrate = B19200; break; case BaudRate38400: baudrate = B38400; break; case BaudRate57600: baudrate = B57600; break; case BaudRate115200: baudrate = B115200; break; default: baudrate = B9600; break; } cfsetispeed(&termIOStructure, baudrate); cfsetospeed(&termIOStructure, baudrate); termIOStructure.c_cc[VMIN] = 0; termIOStructure.c_cc[VTIME] = m_ReceiveTimeout / 100; // timeout in 1/10 sec, not in ms. Rounded down. if (tcsetattr(m_FileDescriptor, TCSANOW, &termIOStructure) == 0) return OK; else return ERROR_VALUE; #endif } void mitk::SerialCommunication::SendBreak(unsigned int ms) { #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return; SetCommBreak(m_ComPortHandle); itksys::SystemTools::Delay(ms); ClearCommBreak(m_ComPortHandle); return; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return; tcsendbreak(m_FileDescriptor, ms); return; #endif } void mitk::SerialCommunication::ClearReceiveBuffer() { #ifdef WIN32 if (m_ComPortHandle != INVALID_HANDLE_VALUE) PurgeComm(m_ComPortHandle, PURGE_RXCLEAR); #else // Posix if (m_FileDescriptor != INVALID_HANDLE_VALUE) tcflush(m_FileDescriptor, TCIFLUSH); #endif } void mitk::SerialCommunication::ClearSendBuffer() { #ifdef WIN32 if ( m_ComPortHandle != INVALID_HANDLE_VALUE ) PurgeComm(m_ComPortHandle, PURGE_TXCLEAR); #else // Posix if ( m_FileDescriptor != INVALID_HANDLE_VALUE ) tcflush(m_FileDescriptor, TCOFLUSH); #endif } diff --git a/Modules/IGT/IGTTrackingDevices/mitkSerialCommunication.h b/Modules/IGT/IGTTrackingDevices/mitkSerialCommunication.h index 7f579e26b0..baf035ceb0 100644 --- a/Modules/IGT/IGTTrackingDevices/mitkSerialCommunication.h +++ b/Modules/IGT/IGTTrackingDevices/mitkSerialCommunication.h @@ -1,298 +1,302 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKSERIALCOMMUNICATION_H_HEADER_INCLUDED_ #define MITKSERIALCOMMUNICATION_H_HEADER_INCLUDED_ #include #include "mitkCommon.h" #include #include #ifdef WIN32 #include #else // Posix #include #endif namespace mitk { /**Documentation * \brief serial communication interface * * This class allows to send and receive data over a serial communication interface (COM Port). * Define the serial interface that should be used either with SetPortNumber() or SetDeviceName() * Next, define communication parameters: baud rate, number of data bits, number of stop bits, * parity mode, usage of hardware handshake and timeout values (in ms). * Use OpenConnection() to establish a connection on the serial interface with the selected * parameters. While the connection is established, changes to the parameters will not take * effect. You have to close the connection using CloseConnection() and then reopen it with * the new parameters with OpenConnection(). * * \ingroup IGT */ class MitkIGT_EXPORT SerialCommunication : public itk::Object { public: mitkClassMacro(SerialCommunication, itk::Object); itkNewMacro(Self); enum PortNumber { COM1 = 1, COM2 = 2, COM3 = 3, COM4 = 4, COM5 = 5, COM6 = 6, COM7 = 7, COM8 = 8, - COM9 = 9 + COM9 = 9, + COM10 = 10, + COM11 = 11, + COM12 = 12, + COM13 = 13 }; enum BaudRate { BaudRate9600 = 9600, BaudRate14400 = 14400, BaudRate19200 = 19200, BaudRate38400 = 38400, BaudRate57600 = 57600, BaudRate115200 = 115200 }; enum DataBits { DataBits8 = 8, DataBits7 = 7 }; enum Parity { None = 'N', Odd = 'O', Even = 'E' }; enum StopBits { StopBits1 = 1, StopBits2 = 2 }; enum HardwareHandshake { HardwareHandshakeOn = 1, HardwareHandshakeOff = 0 }; /** * \brief Opens connection to the COM port with port number m_PortNumber * or the device name m_DeviceName and all port settings. * */ int OpenConnection(); /** * \brief Closes the connection * */ void CloseConnection(); /** * \brief Read numberOfBytes characters from the serial interface * * This method tries to read numberOfBytes characters from the serial * interface. If The ReceiveTimeout is set to 0, the Receive() method will * wait indefinetly until all characters are received. If the ReceiveTimeout * is set to another value, it will return after m_ReceiveTimeout milliseconds * (or after all characters are read). * The received characters are stored in the string answer. Note that this will * overwrite the content of answer! */ int Receive(std::string& answer, unsigned int numberOfBytes); /** * \brief Send the string input * * This method will send the string input to the serial interface. * It does not send the string termination character \\0. */ int Send(const std::string& input); /** * \brief Send the break signal for ms milliseconds */ void SendBreak(unsigned int ms = 400); /** * \brief erase the receive buffer of the serial interface */ void ClearReceiveBuffer(); /** * \brief erase the send buffer of the serial interface */ void ClearSendBuffer(); /** * \brief Get the port number of the serial interface * * Returns the port number that will be used in the connection. * The port number is only used if the m_DeviceName is empty (""). */ itkGetConstMacro(PortNumber, PortNumber); /** * \brief Set the port number of the serial interface * * SerialCommunication can either use PortNumber to create serial interface device names * COM1 to COM9 for windows and /dev/ttyS0 to /dev/ttyS8 on linux * (SetPortNumber(COM1) is mapped to /dev/ttyS0 and so on). Alternatively, use SetDeviceName() * to set the device name directly (e.g. "CNCA0" for a com0com virtual com port or * "/dev/ttyUSB0" for a USB to serial adapter on linux. If a device name is set (m_DeviceName != "") * then OpenConnection() will try to open that device. Otherwise, it will build the device * name using the port number */ itkSetMacro(PortNumber, PortNumber); /** * \brief Get the device name * * SerialCommunication can either use m_PortNumber to create serial interface device names * or use m_DeviceName directly. This method allows to set an arbitrary device name * that will be used to connect to the device. Common names are COM1, CNCA0, CNCB9 * on windows and /dev/ttyS0 or /dev/ttyUSB0 on linux. */ itkGetStringMacro(DeviceName); /** * \brief Set the device name * * if the device name is set (!=""), OpenConnection() will try to open the * serial device on that device name. Normally, the serial interfaces are named COM1-COM9 * on windows and /dev/ttyS0 to /dev/ttyS9 on linux, but other names are possible too * (e.g. /dev/ttyUSB0). */ itkSetStringMacro(DeviceName); /** * \brief Get the baud rate of the serial interface */ itkGetConstMacro(BaudRate, BaudRate); /** * \brief Set the baud rate of the serial interface */ itkSetMacro(BaudRate, BaudRate); /** * \brief Get the number of data bits of the serial interface */ itkGetConstMacro(DataBits, DataBits); /** * \brief Set the number of data bits of the serial interface */ itkSetMacro(DataBits, DataBits); /** * \brief Get the parity mode of the serial interface */ itkGetConstMacro(Parity, Parity); /** * \brief Set the parity mode of the serial interface */ itkSetMacro(Parity, Parity); /** * \brief Get number of stop bits of the serial interface */ itkGetConstMacro(StopBits, StopBits); /** * \brief Set number of stop bits of the serial interface */ itkSetMacro(StopBits, StopBits); /** * \brief returns true if hardware handshake should is used */ itkGetConstMacro(HardwareHandshake, HardwareHandshake); /** * \brief Set if hardware handshake should be used */ itkSetMacro(HardwareHandshake, HardwareHandshake); /** * \brief returns the send timeout in milliseconds */ itkGetConstMacro(SendTimeout, unsigned int); /** * \brief set the send timeout in milliseconds */ itkSetMacro(SendTimeout, unsigned int); /** * \brief returns the receive timeout in milliseconds */ itkGetConstMacro(ReceiveTimeout, unsigned int); /** * \brief set the send timeout in milliseconds * * Specify the receive timeout in milliseconds. * Setting this value to 0 will cause the Receive() * method to wait until all expected characters are received. */ itkSetMacro(ReceiveTimeout, unsigned int); protected: SerialCommunication(); virtual ~SerialCommunication(); /** * \brief configures the serial interface with all parameters */ int ApplyConfiguration(); std::string m_DeviceName; ///< device name that is used to connect to the serial interface (will be used if != "") PortNumber m_PortNumber; ///< port number of the device BaudRate m_BaudRate; ///< baud rate of the serial interface connection DataBits m_DataBits; ///< number of data bits per symbol Parity m_Parity; ///< parity mode StopBits m_StopBits; ///< number of stop bits per symbol HardwareHandshake m_HardwareHandshake; ///< whether to use hardware handshake for the connection unsigned int m_ReceiveTimeout; ///< timeout for receiving data from the serial interface in milliseconds unsigned int m_SendTimeout; ///< timeout for sending data to the serial interface in milliseconds bool m_Connected; ///< is set to true if a connection currently established #ifdef WIN32 HANDLE m_ComPortHandle; DWORD m_PreviousMask; COMMTIMEOUTS m_PreviousTimeout; DCB m_PreviousDeviceControlBlock; #else int m_FileDescriptor; #endif }; } // namespace mitk #endif /* MITKSERIALCOMMUNICATION_H_HEADER_INCLUDED_ */ diff --git a/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp b/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp index acd5e05809..a8c36f37cb 100644 --- a/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp +++ b/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp @@ -1,428 +1,435 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkOpenCVVideoSource.h" #include #include mitk::OpenCVVideoSource::OpenCVVideoSource() : m_VideoCapture(0), m_CurrentImage(0), m_CurrentVideoTexture(0), m_PauseImage(0), m_GrabbingDeviceNumber(-1), m_RepeatVideo(false), m_UseCVCAMLib(false), m_UndistortImage(false), m_RotationAngle(0.0), m_RotationEnabled(false) { } mitk::OpenCVVideoSource::~OpenCVVideoSource() { this->Reset(); } void mitk::OpenCVVideoSource::SetVideoFileInput(const char * filename, bool repeatVideo, bool /*useCVCAMLib*/) { this->Reset(); m_VideoFileName = filename; m_VideoCapture = cvCaptureFromFile(filename); if(!m_VideoCapture) MITK_WARN << "Error in initializing video file input!"; m_RepeatVideo = repeatVideo; //m_CurrentImage = cvCreateImage(cvSize(m_CaptureWidth,m_CaptureHeight),8,3); this->Modified(); } void mitk::OpenCVVideoSource::SetVideoCameraInput(int cameraindex, bool /*useCVCAMLib*/) { this->Reset(); m_GrabbingDeviceNumber = cameraindex; m_VideoCapture = cvCaptureFromCAM(m_GrabbingDeviceNumber); if(!m_VideoCapture) MITK_ERROR << "Error in initializing CVHighGUI video camera!"<< std::endl; this->Modified(); } double mitk::OpenCVVideoSource::GetVideoCaptureProperty(int property_id) { return cvGetCaptureProperty(m_VideoCapture, property_id); } int mitk::OpenCVVideoSource::SetVideoCaptureProperty(int property_id, double value) { return cvSetCaptureProperty(m_VideoCapture, property_id, value); } //method extended for "static video feature" if enabled unsigned char* mitk::OpenCVVideoSource::GetVideoTexture() { // Fetch Frame and return pointer to opengl texture FetchFrame(); if (m_RotationEnabled) { //store pointer to release memory for the image after rotation IplImage * tmpImage = m_CurrentImage; //rotate the image to get a static video m_CurrentImage = this->RotateImage(m_CurrentImage); // release memory cvReleaseImage(&tmpImage); // } //transfer the image to a texture this->UpdateVideoTexture(); return this->m_CurrentVideoTexture; this->Modified(); } cv::Mat mitk::OpenCVVideoSource::GetImage() { if(m_CurrentImage) { cv::Mat copy( m_CurrentImage, false ); return copy.clone(); } return cv::Mat(); } const IplImage * mitk::OpenCVVideoSource::GetCurrentFrame() { return m_CurrentImage; } void mitk::OpenCVVideoSource::GetCurrentFrameAsOpenCVImage(IplImage * image) { // get last captured frame for processing the image data if(m_CurrentImage) { if(image) { image->origin = m_CurrentImage->origin; memcpy(image->imageData,m_CurrentImage->imageData,m_CurrentImage->width*m_CurrentImage->height*m_CurrentImage->nChannels); } } } void mitk::OpenCVVideoSource::FetchFrame() { // main procedure for updating video data if(m_CapturingInProcess) { if(m_VideoCapture) // we use highgui { if(!m_CapturePaused) { // release old image here m_CurrentImage = cvQueryFrame(m_VideoCapture); ++m_FrameCount; } if(m_CurrentImage == NULL) // do we need to repeat the video if it is from video file? { double framePos = this->GetVideoCaptureProperty(CV_CAP_PROP_POS_AVI_RATIO); MITK_DEBUG << "End of video file found. framePos: " << framePos; if(m_RepeatVideo && framePos >= 0.99) { MITK_DEBUG << "Restarting video file playback."; this->SetVideoCaptureProperty(CV_CAP_PROP_POS_AVI_RATIO, 0); m_FrameCount = 0; m_CurrentImage = cvQueryFrame(m_VideoCapture); } + else + { + std::ostringstream s; + s << "End of video file " << m_VideoFileName; + std::logic_error err( s.str() ); + throw err; + } } else { // only undistort if not paused if(m_UndistortImage && m_UndistortCameraImage.IsNotNull()) m_UndistortCameraImage->UndistortImageFast(m_CurrentImage, 0); } if(m_CaptureWidth == 0 || m_CaptureHeight == 0) { MITK_DEBUG << "Trying to set m_CaptureWidth & m_CaptureHeight."; m_CaptureWidth = m_CurrentImage->width; m_CaptureHeight = m_CurrentImage->height; MITK_INFO << "frame width: " << m_CaptureWidth << ", height: " << m_CaptureHeight; m_CurrentImage->origin = 0; } } } } void mitk::OpenCVVideoSource::UpdateVideoTexture() { //write the grabbed frame into an opengl compatible array, that means flip it and swap channel order if(!m_CurrentImage) return; if(m_CurrentVideoTexture == NULL) m_CurrentVideoTexture = new unsigned char[m_CaptureWidth*m_CaptureHeight*3]; int width = m_CurrentImage->width; int height = m_CurrentImage->height; int widthStep = m_CurrentImage->widthStep; int nChannels = m_CurrentImage->nChannels; unsigned char* tex = m_CurrentVideoTexture; char* data = m_CurrentImage->imageData; char* currentData = m_CurrentImage->imageData; int hIndex=0; int wIndex=0; int iout,jout; for(int i=0;i= width) { wIndex=0; hIndex++; } // vertically flip the image iout = -hIndex+height-1; jout = wIndex; currentData = data + iout*widthStep; tex[i+2] = currentData[jout*nChannels + 0]; // B tex[i+1] = currentData[jout*nChannels + 1]; // G tex[i] = currentData[jout*nChannels + 2]; // R } } void mitk::OpenCVVideoSource::StartCapturing() { if(m_VideoCapture != NULL) m_CapturingInProcess = true; else m_CapturingInProcess = false; } void mitk::OpenCVVideoSource::StopCapturing() { m_CapturingInProcess = false; } bool mitk::OpenCVVideoSource::OnlineImageUndistortionEnabled() const { return m_UndistortCameraImage; } void mitk::OpenCVVideoSource::PauseCapturing() { m_CapturePaused = !m_CapturePaused; if(m_CapturePaused) { m_PauseImage = cvCloneImage(m_CurrentImage); // undistort this pause image if necessary if(m_UndistortImage) m_UndistortCameraImage->UndistortImageFast(m_PauseImage, 0); m_CurrentImage = m_PauseImage; } else { cvReleaseImage( &m_PauseImage ); // release old pause image if necessary m_CurrentImage = 0; m_PauseImage = 0; } } void mitk::OpenCVVideoSource::EnableOnlineImageUndistortion(mitk::Point3D focal, mitk::Point3D principal, mitk::Point4D distortion) { // Initialize Undistortion m_UndistortImage = true; float kc[4]; kc[0] = distortion[0]; kc[1] = distortion[1]; kc[2] = distortion[2]; kc[3] = distortion[3]; if(m_CaptureWidth == 0 || m_CaptureHeight == 0) FetchFrame(); m_UndistortCameraImage = mitk::UndistortCameraImage::New(); m_UndistortCameraImage->SetUndistortImageFastInfo(focal[0], focal[1], principal[0], principal[1], kc, (float)m_CaptureWidth, (float)m_CaptureHeight); } void mitk::OpenCVVideoSource::DisableOnlineImageUndistortion() { m_UndistortImage = false; } // functions for compatibility with ITK segmentation only void mitk::OpenCVVideoSource::GetCurrentFrameAsItkHSVPixelImage(HSVPixelImageType::Pointer &Image) { FetchFrame(); // Prepare iteration HSVConstIteratorType itImage( Image, Image->GetLargestPossibleRegion()); itImage.Begin(); HSVPixelType pixel; int rowsize = 3 * m_CaptureWidth; char* bufferend; char* picture; picture = this->m_CurrentImage->imageData; bufferend = this->m_CurrentImage->imageData + 3*(m_CaptureHeight*m_CaptureWidth); float r,g,b,h,s,v; try { // we have to flip the image for(char* datapointer = bufferend - rowsize;datapointer >= picture; datapointer -= rowsize) { for(char* current = datapointer; current < datapointer + rowsize; current++) { b = *current; current++; g = *current; current++; r = *current; RGBtoHSV(r,g,b,h,s,v); pixel[0] = h; pixel[1] = s; pixel[2] = v; itImage.Set(pixel); ++itImage; } } } catch( ... ) { std::cout << "Exception raised mitkOpenCVVideoSource: get hsv itk image conversion error." << std::endl; } } void mitk::OpenCVVideoSource::RGBtoHSV(float r, float g, float b, float &h, float &s, float &v) { if(r > 1.0) r = r/255; if(b > 1.0) b = b/255; if(g > 1.0) g = g/255; float mn=r,mx=r; int maxVal=0; if (g > mx){ mx=g;maxVal=1;} if (b > mx){ mx=b;maxVal=2;} if (g < mn) mn=g; if (b < mn) mn=b; float delta = mx - mn; v = mx; if( mx != 0 ) s = delta / mx; else { s = 0; h = 0; return; } if (s==0.0f) { h=-1; return; } else { switch (maxVal) { case 0:{h = ( g - b ) / delta;break;} // yel < h < mag case 1:{h = 2 + ( b - r ) / delta;break;} // cyan < h < yel case 2:{h = 4 + ( r - g ) / delta;break;} // mag < h < cyan } } h *= 60; if( h < 0 ) h += 360; } /* * Rotate input image according to rotation angle around the viewing direction. * Angle is supposed to be calculated in QmitkARRotationComponet in the update() method. */ IplImage* mitk::OpenCVVideoSource::RotateImage(IplImage* input) { if(input == NULL) { //warn the user and quit std::cout<<"openCVVideoSource: Current video image is null! "<< std::endl; return input; } IplImage* dst = cvCloneImage( input ); double angle = this->GetRotationAngle(); //degree CvPoint2D32f centre; CvMat *translate = cvCreateMat(2, 3, CV_32FC1); cvSetZero(translate); centre.x = m_CaptureWidth/2; centre.y = m_CaptureHeight/2; cv2DRotationMatrix(centre, angle, 1.0, translate); cvWarpAffine(input, dst, translate,CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS , cvScalarAll(0)); cvReleaseMat(&translate); return dst; } void mitk::OpenCVVideoSource::Reset() { // set capturing to false this->StopCapturing(); if(m_VideoCapture) cvReleaseCapture(&m_VideoCapture); m_VideoCapture = 0; m_CurrentImage = 0; m_CaptureWidth = 0; m_CaptureHeight = 0; delete m_CurrentVideoTexture; m_CurrentVideoTexture = 0; if(m_PauseImage) cvReleaseImage(&m_PauseImage); m_PauseImage = 0; m_CapturePaused = false; m_VideoFileName.clear(); m_GrabbingDeviceNumber = -1; // do not touch repeat video //m_RepeatVideo = false; m_UseCVCAMLib = false; // do not touch undistort settings // bool m_UndistortImage; } void mitk::OpenCVVideoSource::EnableRotation(bool enable= true) { m_RotationEnabled = enable; this->Modified(); } void mitk::OpenCVVideoSource::SetRotationAngle(double rotationAngle) { m_RotationAngle = rotationAngle; this->Modified(); } double mitk::OpenCVVideoSource::GetRotationAngle() { return m_RotationAngle; }