diff --git a/CMake/BuildConfigurations/camiPhotoacousticsSetup.cmake b/CMake/BuildConfigurations/camiPhotoacousticsSetup.cmake new file mode 100644 index 0000000000..5b08ebc880 --- /dev/null +++ b/CMake/BuildConfigurations/camiPhotoacousticsSetup.cmake @@ -0,0 +1,26 @@ +message(STATUS "Configuring MITK Photoacoustics Setup Build") + +set(MITK_CONFIG_PACKAGES + ACVD + QT + BLUEBERRY +) + +# Enable open cv and open igt link, which is a necessary configuration +set(MITK_USE_OpenCV ON CACHE BOOL "MITK Use OpenCV Library" FORCE) +set(MITK_USE_OpenIGTLink ON CACHE BOOL "MITK Use OpenIGTLink Library" FORCE) +set(MITK_USE_US_DiPhAS_SDK ON CACHE BOOL "Use DiPhAS SDK" FORCE) +#set(MITK_USE_OPOTEK_HARDWARE ON CACHE BOOL "Use hardware build-in in OPOTEK Phocus Mobile" FORCE) +set(MITK_US_DiPhAS_SDK_PATH "C:/Users/dkfz/Source/Repos/UltrasoundResearchPlatform_SDK/UltrasoundResearchPlatformSDK_Cpp/x64/Release" CACHE PATH "DiPhAS SDK Path") + +# Enable default plugins and the navigation modules +set(MITK_CONFIG_PLUGINS + org.mitk.gui.qt.datamanager + org.mitk.gui.qt.stdmultiwidgeteditor + org.mitk.gui.qt.imagenavigator + org.mitk.gui.qt.properties + org.mitk.gui.qt.viewnavigator + org.mitk.gui.qt.ultrasound + org.mitk.gui.qt.lasercontrol +) + diff --git a/Modules/IGT/Common/mitkSerialCommunication.cpp b/Modules/IGT/Common/mitkSerialCommunication.cpp index 3b5afa64f6..39485df6f5 100644 --- a/Modules/IGT/Common/mitkSerialCommunication.cpp +++ b/Modules/IGT/Common/mitkSerialCommunication.cpp @@ -1,504 +1,509 @@ /*=================================================================== 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 "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(); } +bool mitk::SerialCommunication::IsConnected() +{ + return m_Connected; +} + 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 else ss << "\\\\.\\" << m_DeviceName; // use m_DeviceName m_ComPortHandle = CreateFile(ss.str().c_str(), GENERIC_READ | GENERIC_WRITE, 0, // no sharing 0, // no security flags OPEN_EXISTING, // open com port, don't create it 0, // no flags 0); // 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, const char *eol) { 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, nullptr) != 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; auto 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 (eol && *eol == buffer[bytesRead-1]) // end of line char reached break; } if (bytesRead > 0) answer.assign(buffer, bytesRead); // copy buffer to answer delete buffer; if ( bytesRead == numberOfBytes || // everything was received (eol && answer.size() > 0 && *eol == answer.at(answer.size()-1)) ) // end of line char reached return OK; else return ERROR_VALUE; // some data was received, but not as much as expected #endif } int mitk::SerialCommunication::Send(const std::string& input, bool block) { //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, nullptr) == 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; } if (block) { // wait for output to be physically sent if (tcdrain(m_FileDescriptor) == -1) return ERROR_VALUE; } return OK; #endif } int mitk::SerialCommunication::ApplyConfiguration() { #ifdef WIN32 // Windows implementation return ApplyConfigurationWin(); #else // Posix return ApplyConfigurationUnix(); #endif } /** * The Code for Baud rates is highly platform specific and divided into separate subroutines for readability. */ #ifdef WIN32 int mitk::SerialCommunication::ApplyConfigurationWin() { 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 /** * \brief Applies the configuration for Linux */ int mitk::SerialCommunication::ApplyConfigurationUnix() { 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; case BaudRate230400: baudrate = B230400; break; // the following baud rates do not work for apple #ifndef __APPLE__ case BaudRate460800: baudrate = B460800; break; case BaudRate500000: baudrate = B500000; break; case BaudRate576000: baudrate = B576000; break; case BaudRate921600: baudrate = B921600; break; case BaudRate1000000: baudrate = B1000000; break; case BaudRate1152000: baudrate = B1152000; break; //case BaudRate1228739: //baudrate = B1228739; //break; case BaudRate1500000: baudrate = B1500000; break; case BaudRate2000000: baudrate = B2000000; break; case BaudRate2500000: baudrate = B2500000; break; case BaudRate3000000: baudrate = B3000000; break; case BaudRate3500000: baudrate = B3500000; break; case BaudRate4000000: baudrate = B4000000; break; #endif default: MITK_WARN("mitk::SerialCommunication") << "Baud rate not recognized, using default of 9600 Baud."; 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/Common/mitkSerialCommunication.h b/Modules/IGT/Common/mitkSerialCommunication.h index 589795f466..2ce452f350 100644 --- a/Modules/IGT/Common/mitkSerialCommunication.h +++ b/Modules/IGT/Common/mitkSerialCommunication.h @@ -1,346 +1,351 @@ /*=================================================================== 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. ===================================================================*/ #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: mitkClassMacroItkParent(SerialCommunication, itk::Object); itkFactorylessNewMacro(Self) itkCloneMacro(Self) enum PortNumber { COM1 = 1, COM2 = 2, COM3 = 3, COM4 = 4, COM5 = 5, COM6 = 6, COM7 = 7, COM8 = 8, COM9 = 9, COM10 = 10, COM11 = 11, COM12 = 12, COM13 = 13 }; enum BaudRate { BaudRate9600 = 9600, BaudRate14400 = 14400, BaudRate19200 = 19200, BaudRate38400 = 38400, BaudRate57600 = 57600, BaudRate115200 = 115200, // Highest supported rate for NDI Aurora BaudRate230400 = 230400, BaudRate460800 = 460800, BaudRate500000 = 500000, BaudRate576000 = 576000, BaudRate921600 = 921600, BaudRate1000000 = 1000000, BaudRate1152000 = 1152000, // BaudRate1228739 = 1228739, // Highest supported rate for NDI Polaris According to handbook, unknown value to most compilers though BaudRate1500000 = 1500000, BaudRate2000000 = 2000000, BaudRate2500000 = 2500000, BaudRate3000000 = 3000000, BaudRate3500000 = 3500000, BaudRate4000000 = 4000000 }; 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 Returns m_Connected + * + */ + bool IsConnected(); /** * \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 or until an eol byte is received, whichever comes first. If * The ReceiveTimeout is set to 0, the Receive() method will wait * indefinetly until all characters are received or an eol character is * received. If the ReceiveTimeout is set to another value, it will return * after m_ReceiveTimeout milliseconds (or after all characters are read or * an eol character is received). * * \param[out] answer String that stores the received characters. Note * that this will overwrite the content of answer! * \param[in] numberOfBytes The number of bytes to read. When an eol * character is used this is interpretted as the * maximum number of bytes to read. * \param[in] eol Pointer to an End-of-Line character. If this is nullptr * (the default) then no End-of-Line character is used. */ int Receive(std::string& answer, unsigned int numberOfBytes, const char *eol=nullptr); /** * \brief Send the string input * * \param[in] input The string to send to the serial interface. The string * termination character \\0 is not sent. * \param[in] block If false, the this method will return immediately. If * true, this method will block until all bytes have been * physically transmitted over the serial interface. */ int Send(const std::string& input, bool block = false); /** * \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 * * Only applies to WIN32, not POSIX */ 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 * * This automatically reroutes the call to the hardware specific function */ int ApplyConfiguration(); #ifdef WIN32 /** * \brief Applies the configuration for Windows */ int ApplyConfigurationWin(); #else /** * \brief Applies the configuration for Linux */ int ApplyConfigurationUnix(); #endif 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/ModuleList.cmake b/Modules/ModuleList.cmake index c29c522e5d..3197835d83 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,80 +1,82 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(mitk_modules Core CommandLine AppUtil DCMTesting RDF LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMReaderServices DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction SceneSerialization Gizmo GraphAlgorithms Multilabel ImageStatistics ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation OpenViewCore QtWidgets QtWidgetsExt Chart QmlItems SegmentationUI Classification DiffusionImaging GPGPU OpenIGTLink IGTBase IGT CameraCalibration OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI + PhotoacousticsHardware + PhotoacousticsAlgorithms US USUI DicomUI Simulation Remeshing Python QtPython Persistence OpenIGTLinkUI IGTUI VtkShaders DicomRT RTUI IOExt XNAT TubeGraph BiophotonicsHardware TumorInvasionAnalysis MatchPointRegistration MatchPointRegistrationUI BoundingShape RenderWindowManager RenderWindowManagerUI CEST DICOMQI ) if(MITK_ENABLE_PIC_READER) list(APPEND mitk_modules IpPicSupportIO) endif() diff --git a/Modules/OpenCL/mitkOclImage.cpp b/Modules/OpenCL/mitkOclImage.cpp index 068314e1d3..3ca46fe7fb 100644 --- a/Modules/OpenCL/mitkOclImage.cpp +++ b/Modules/OpenCL/mitkOclImage.cpp @@ -1,342 +1,363 @@ /*=================================================================== 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 "mitkOclImage.h" #include "mitkImageDataItem.h" #include "mitkCommon.h" #include "mitkLogMacros.h" #include "mitkOclUtils.h" #include #include mitk::OclImage::OclImage() : m_gpuImage(nullptr), m_context(nullptr), m_bufferSize(0), m_gpuModified(false), m_cpuModified(false), m_Image(nullptr), m_dim(0), m_Dims(nullptr), m_BpE(1), m_formatSupported(false) { } mitk::OclImage::~OclImage() { MITK_INFO << "OclImage Destructor"; //release GMEM Image buffer if (m_gpuImage) clReleaseMemObject(m_gpuImage); } cl_mem mitk::OclImage::CreateGPUImage(unsigned int _wi, unsigned int _he, unsigned int _de, unsigned int _bpp) { MITK_INFO << "CreateGPUImage call with: BPP=" << _bpp; this->m_Dims = new unsigned int[MAX_DIMS]; m_Dims[0] = _wi; m_Dims[1] = _he; m_Dims[2] = _de; for (unsigned int i=3; i ref = GetModuleContext()->GetServiceReference(); OclResourceService* resources = GetModuleContext()->GetService(ref); cl_context gpuContext = resources->GetContext(); int clErr; m_gpuImage = clCreateBuffer( gpuContext, CL_MEM_READ_WRITE, m_bufferSize * m_BpE, nullptr, &clErr); CHECK_OCL_ERR(clErr); return m_gpuImage; } void mitk::OclImage::InitializeByMitkImage(mitk::Image::Pointer _image) { this->m_Image = _image; this->m_cpuModified = true; this->m_gpuModified = false; this->m_gpuImage = nullptr; // compute the size of the GMEM buffer this->m_dim = this->m_Image->GetDimension(); this->m_Dims = this->m_Image->GetDimensions(); MITK_INFO << "Image: " << this->m_Dims[0] <<"x"<< this->m_Dims[1] <<"x"<< this->m_Dims[2]; // get the dimensions this->m_bufferSize = 1; for (unsigned int i=0; im_dim; i++) { this->m_bufferSize *= this->m_Dims[i]; } // multiply by sizeof(PixelType) this->m_BpE = ( this->m_Image->GetPixelType().GetBpe() / 8); } bool mitk::OclImage::IsModified(int _type) { if (_type) return m_cpuModified; else return m_gpuModified; } void mitk::OclImage::Modified(int _type) { // defines... GPU: 0, CPU: 1 m_cpuModified = _type; m_gpuModified = !_type; } int mitk::OclImage::TransferDataToGPU(cl_command_queue gpuComQueue) { cl_int clErr = 0; // check whether an image present if (!m_Image->IsInitialized()){ MITK_ERROR("ocl.Image") << "(mitk) Image not initialized!\n"; return -1; } // there is a need for copy only if RAM-Data newer then GMEM data if (m_cpuModified) { //check the buffer if(m_gpuImage == nullptr) { clErr = this->AllocateGPUImage(); } if (m_Image->IsInitialized() && (clErr == CL_SUCCESS)) { const size_t origin[3] = {0, 0, 0}; const size_t region[3] = {m_Dims[0], m_Dims[1], m_Dims[2]}; if( this->m_formatSupported ) { mitk::ImageReadAccessor accessor(m_Image); clErr = clEnqueueWriteImage( gpuComQueue, m_gpuImage, CL_TRUE, origin, region, 0, 0, accessor.GetData(), 0, nullptr, nullptr); } else { MITK_ERROR << "Selected image format currently not supported..."; } CHECK_OCL_ERR(clErr); } m_gpuModified = true; } return clErr; } cl_int mitk::OclImage::AllocateGPUImage() { cl_int clErr = 0; us::ServiceReference ref = GetModuleContext()->GetServiceReference(); OclResourceService* resources = GetModuleContext()->GetService(ref); cl_context gpuContext = resources->GetContext(); // initialize both proposed and supported format variables to same value this->m_proposedFormat = this->ConvertPixelTypeToOCLFormat(); this->m_supportedFormat = this->m_proposedFormat; // test the current format for HW support this->m_formatSupported = resources->GetIsFormatSupported( &(this->m_supportedFormat) ); // create an transfer kernel object in case the proposed format is not supported if( !(this->m_formatSupported) ) { mitkThrowException(mitk::ImageTypeIsNotSupportedByGPU) << "Original format not supported on the installed graphics card."; } - // create new buffer - m_gpuImage = clCreateImage(gpuContext, CL_MEM_READ_ONLY, &m_supportedFormat, nullptr, nullptr, &clErr); + _cl_image_desc imageDescriptor; + + imageDescriptor.image_width = *(m_Dims); + imageDescriptor.image_height = *(m_Dims + 1); + imageDescriptor.image_depth = *(m_Dims + 2); + imageDescriptor.image_array_size = 0; + imageDescriptor.image_row_pitch = 0; + imageDescriptor.image_slice_pitch = 0; + imageDescriptor.num_mip_levels = 0; + imageDescriptor.num_samples = 0; + imageDescriptor.buffer = nullptr; + // create new buffer + if( this->m_dim > 2) + { + //Create a 3D Image + imageDescriptor.image_type = CL_MEM_OBJECT_IMAGE3D; + } + else + { + //Create a 2D Image + imageDescriptor.image_type = CL_MEM_OBJECT_IMAGE2D; + } + m_gpuImage = clCreateImage(gpuContext, CL_MEM_READ_ONLY, &m_supportedFormat, &imageDescriptor, nullptr, &clErr); CHECK_OCL_ERR(clErr); return clErr; } cl_mem mitk::OclImage::GetGPUImage(cl_command_queue gpuComQueue) { // clGetMemObjectInfo() cl_mem_object_type memInfo; cl_int clErr = 0; // query image object info only if already initialized if( this->m_gpuImage ) { clErr = clGetMemObjectInfo(this->m_gpuImage, CL_MEM_TYPE, sizeof(cl_mem_object_type), &memInfo, nullptr ); CHECK_OCL_ERR(clErr); } MITK_INFO << "Querying info for object, recieving: " << memInfo; // test if m_gpuImage CL_MEM_IMAGE_2/3D // if not, copy buffer to image if (memInfo == CL_MEM_OBJECT_BUFFER) { MITK_WARN << " Passed oclImage is a buffer-object, creating image"; //hold a copy of the buffer gmem pointer cl_mem tempBuffer = this->m_gpuImage; const size_t origin[3] = {0, 0, 0}; size_t region[3] = {this->m_Dims[0], this->m_Dims[1], 1}; clErr = this->AllocateGPUImage(); this->m_dim = 3; //copy last data to the image data clErr = clEnqueueCopyBufferToImage( gpuComQueue, tempBuffer, m_gpuImage, 0, origin, region, 0, nullptr, nullptr); CHECK_OCL_ERR(clErr); //release pointer clReleaseMemObject(tempBuffer); } return m_gpuImage; } void mitk::OclImage::SetPixelType(const cl_image_format *_image) { this->m_proposedFormat.image_channel_data_type = _image->image_channel_data_type; this->m_proposedFormat.image_channel_order = _image->image_channel_order; } void* mitk::OclImage::TransferDataToCPU(cl_command_queue gpuComQueue) { cl_int clErr = 0; // if image created on GPU, needs to create mitk::Image if( m_Image.IsNull() ){ MITK_INFO << "Image not initialized, creating new one."; m_Image = mitk::Image::New(); } // check buffersize/image size char* data = new char[m_bufferSize * m_BpE]; // debug info oclPrintMemObjectInfo( m_gpuImage ); clErr = clEnqueueReadBuffer( gpuComQueue, m_gpuImage, CL_FALSE, 0, m_bufferSize * m_BpE, data ,0, nullptr, nullptr); CHECK_OCL_ERR(clErr); clFlush( gpuComQueue ); // the cpu data is same as gpu this->m_gpuModified = false; return (void*) data; } cl_image_format mitk::OclImage::ConvertPixelTypeToOCLFormat() { cl_image_format texFormat; //single channel Gray-Valued Images texFormat.image_channel_order = CL_R; MITK_INFO << "Class own value: " << this->m_BpE; switch ( this->m_BpE ) { case 1: texFormat.image_channel_data_type = CL_UNSIGNED_INT8; MITK_INFO<< "PixelType: UCHAR => CLFormat: [CL_UNORM_INT8, CL_R]"; break; case 2: texFormat.image_channel_data_type = CL_SIGNED_INT16; // texFormat.image_channel_order = CL_R; MITK_INFO<< "PixelType: SHORT => CLFormat: [CL_SIGNED_INT16, CL_R]"; break; case 4: texFormat.image_channel_data_type = CL_FLOAT; MITK_INFO<< "Choosing CL_FLOAT"; break; default: texFormat.image_channel_data_type = CL_UNORM_INT8; texFormat.image_channel_order = CL_RG; MITK_INFO<< "Choosing (default) short: 2-Channel UCHAR"; break; } return texFormat; } int mitk::OclImage::GetDimension(int idx) const { if (this->m_dim > idx) { return m_Dims[idx]; } else { MITK_WARN << "Trying to access non-existing dimension."; return 1; } } void mitk::OclImage::SetDimensions(unsigned int* Dims) { m_Dims = Dims; } void mitk::OclImage::SetDimension(unsigned short dim) { m_dim = dim; } float mitk::OclImage::GetSpacing(int idx) { if (this->m_dim > idx) { const mitk::Vector3D imSpacing = m_Image->GetSlicedGeometry()->GetSpacing(); return imSpacing[idx]; } else { MITK_WARN << "Trying to access non-existing dimension."; return 1; } } void mitk::OclImage::InitializeMITKImage() { this->m_Image = mitk::Image::New(); } void mitk::OclImage::GetOffset(float* _imOffset) const { itk::Vector result2; result2.Fill(0.0f); result2 = this->m_Image->GetGeometry()->GetIndexToWorldTransform()->GetOffset(); _imOffset[0] = result2[0]; _imOffset[1] = result2[1]; _imOffset[2] = result2[2]; } diff --git a/Modules/OpenCL/mitkOclImageToImageFilter.cpp b/Modules/OpenCL/mitkOclImageToImageFilter.cpp index 62daa1001e..f78d6f9def 100644 --- a/Modules/OpenCL/mitkOclImageToImageFilter.cpp +++ b/Modules/OpenCL/mitkOclImageToImageFilter.cpp @@ -1,148 +1,193 @@ /*=================================================================== 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 "mitkOclImageToImageFilter.h" #include "mitkOclImage.h" #include "mitkException.h" mitk::OclImageToImageFilter::OclImageToImageFilter() { m_Output = mitk::OclImage::New(); } mitk::OclImageToImageFilter::~OclImageToImageFilter() { } mitk::OclImage::Pointer mitk::OclImageToImageFilter::GetGPUOutput() { // initialize some variables m_Output->SetPixelType(m_Input->GetPixelType()); // create new image, for passing the essential information to the output m_Output->InitializeMITKImage(); const unsigned int dimension = m_Input->GetDimension(); unsigned int* dimensions = m_Input->GetDimensions(); m_Output->SetDimensions( dimensions ); m_Output->SetDimension( (unsigned short)dimension ); m_Output->GetMITKImage()->Initialize( this->GetOutputType(), dimension, dimensions); const mitk::SlicedGeometry3D::Pointer p_slg = m_Input->GetMITKImage()->GetSlicedGeometry(0); m_Output->GetMITKImage()->SetSpacing( p_slg->GetSpacing() ); m_Output->GetMITKImage()->SetGeometry( m_Input->GetMITKImage()->GetGeometry() ); return this->m_Output; } mitk::Image::Pointer mitk::OclImageToImageFilter::GetOutput() { if (m_Output->IsModified(GPU_DATA)) { void* pData = m_Output->TransferDataToCPU(m_CommandQue); const unsigned int dimension = m_Input->GetDimension(); unsigned int* dimensions = m_Input->GetDimensions(); const mitk::SlicedGeometry3D::Pointer p_slg = m_Input->GetMITKImage()->GetSlicedGeometry(); MITK_DEBUG << "Creating new MITK Image."; m_Output->GetMITKImage()->Initialize( this->GetOutputType(), dimension, dimensions); m_Output->GetMITKImage()->SetSpacing( p_slg->GetSpacing()); m_Output->GetMITKImage()->SetGeometry( m_Input->GetMITKImage()->GetGeometry() ); m_Output->GetMITKImage()->SetImportVolume( pData, 0, 0, mitk::Image::ReferenceMemory); } MITK_DEBUG << "Image Initialized."; return m_Output->GetMITKImage(); } mitk::PixelType mitk::OclImageToImageFilter::GetOutputType() { // get the current image format from the input image const cl_image_format* currentImFormat = this->m_Input->GetPixelType(); // return the value according to the current channel type switch( currentImFormat->image_channel_data_type ) { case CL_UNORM_INT8: return mitk::MakeScalarPixelType(); case CL_UNSIGNED_INT8: return mitk::MakeScalarPixelType(); case CL_UNORM_INT16: return mitk::MakeScalarPixelType(); default: return mitk::MakeScalarPixelType(); } } int mitk::OclImageToImageFilter::GetBytesPerElem() { return (this->m_CurrentType + 1); } bool mitk::OclImageToImageFilter::InitExec(cl_kernel ckKernel) { cl_int clErr = 0; if( m_Input.IsNull() ) mitkThrow() << "Input image is null."; // get image size once const unsigned int uiImageWidth = m_Input->GetDimension(0); const unsigned int uiImageHeight = m_Input->GetDimension(1); const unsigned int uiImageDepth = m_Input->GetDimension(2); // compute work sizes this->SetWorkingSize( 8, uiImageWidth, 8, uiImageHeight , 8, uiImageDepth ); cl_mem clBuffIn = m_Input->GetGPUImage(this->m_CommandQue); cl_mem clBuffOut = m_Output->GetGPUBuffer(); if (!clBuffIn) { if ( m_Input->TransferDataToGPU(m_CommandQue) != CL_SUCCESS ) { mitkThrow()<< "Could not create / initialize gpu image."; } clBuffIn = m_Input->GetGPUImage(m_CommandQue); } // output image not initialized if (!clBuffOut) { //TODO bpp, or SetImageWidth/Height/... MITK_DEBUG << "Create GPU Image call " << uiImageWidth<< "x"<CreateGPUImage(uiImageWidth, uiImageHeight, uiImageDepth, this->m_CurrentType + 1); } clErr = 0; clErr = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), &clBuffIn); clErr |= clSetKernelArg(ckKernel, 1, sizeof(cl_mem), &clBuffOut); CHECK_OCL_ERR( clErr ); if( clErr != CL_SUCCESS ) mitkThrow() << "OpenCL Part initialization failed with " << GetOclErrorAsString(clErr); return( clErr == CL_SUCCESS ); } + + bool mitk::OclImageToImageFilter::InitExec(cl_kernel ckKernel, unsigned int* dimensions) + { + cl_int clErr = 0; + + if( m_Input.IsNull() ) + mitkThrow() << "Input image is null."; + + // get image size once + const unsigned int uiImageWidth = dimensions[0]; + const unsigned int uiImageHeight = dimensions[1]; + const unsigned int uiImageDepth = dimensions[2]; + + // compute work sizes + this->SetWorkingSize( 8, uiImageWidth, 8, uiImageHeight , 8, uiImageDepth ); + + cl_mem clBuffIn = m_Input->GetGPUImage(this->m_CommandQue); + cl_mem clBuffOut = m_Output->GetGPUBuffer(); + + if (!clBuffIn) + { + if ( m_Input->TransferDataToGPU(m_CommandQue) != CL_SUCCESS ) + { + mitkThrow()<< "Could not create / initialize gpu image."; + } + + clBuffIn = m_Input->GetGPUImage(m_CommandQue); + } + + // output image not initialized + //TODO bpp, or SetImageWidth/Height/... + MITK_INFO << "Create GPU Image call " << uiImageWidth<< "x"<CreateGPUImage(uiImageWidth, uiImageHeight, uiImageDepth, this->m_CurrentType + 1); + + + clErr = 0; + clErr = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), &clBuffIn); + clErr |= clSetKernelArg(ckKernel, 1, sizeof(cl_mem), &clBuffOut); + CHECK_OCL_ERR( clErr ); + + if( clErr != CL_SUCCESS ) + mitkThrow() << "OpenCL Part initialization failed with " << GetOclErrorAsString(clErr); + + return( clErr == CL_SUCCESS ); +} \ No newline at end of file diff --git a/Modules/OpenCL/mitkOclImageToImageFilter.h b/Modules/OpenCL/mitkOclImageToImageFilter.h index faee659489..19fa41e5f2 100644 --- a/Modules/OpenCL/mitkOclImageToImageFilter.h +++ b/Modules/OpenCL/mitkOclImageToImageFilter.h @@ -1,81 +1,82 @@ /*=================================================================== 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. ===================================================================*/ #ifndef __mitkOclImageToImageFilter_h #define __mitkOclImageToImageFilter_h #include "mitkOclImageFilter.h" namespace mitk { class OclImageFilter; class OclImageToImageFilter; /** @class OclImageToImageFilter * @brief The OclImageToImageFilter is the base class for all OpenCL image filter generating images. */ class MITKOPENCL_EXPORT OclImageToImageFilter: public OclImageFilter { public: /*! * \brief Returns an mitk::Image::Pointer containing the filtered data. */ mitk::Image::Pointer GetOutput(); /*! * \brief Returns a pointer to the graphics memory. * * Use this method when executing two and more filters on the GPU for fast access. * This method does not copy the data to RAM. It returns only a pointer. */ mitk::OclImage::Pointer GetGPUOutput(); protected: /** * @brief OclImageToImageFilter Default constructor. */ OclImageToImageFilter(); /** @brief Destructor */ virtual ~OclImageToImageFilter(); /** Output Image */ mitk::OclImage::Pointer m_Output; /** @brief (Virtual) method Update() to be implemented in derived classes. */ virtual void Update() = 0; /** @brief (Virtual) method returning the format in which the output image will be returned */ virtual mitk::PixelType GetOutputType(); /** * @brief InitExec Initialize the execution * @param ckKernel The GPU kernel. * @throws mitk::Exception if something goes wrong. * @return True for success. */ bool InitExec(cl_kernel ckKernel); + bool InitExec(cl_kernel ckKernel, unsigned int* dimensions); /** @brief Get the memory size needed for each element */ virtual int GetBytesPerElem(); private: /** Block dimensions */ unsigned int m_BlockDims[3]; }; } #endif // __mitkOclImageToImageFilter_h diff --git a/Modules/OpenCL/mitkOclUtils.cpp b/Modules/OpenCL/mitkOclUtils.cpp index 5ff997c581..d743b3d494 100644 --- a/Modules/OpenCL/mitkOclUtils.cpp +++ b/Modules/OpenCL/mitkOclUtils.cpp @@ -1,569 +1,572 @@ /*=================================================================== 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 "mitkOclUtils.h" #include "mitkLogMacros.h" #include #include unsigned int iDivUp(unsigned int dividend, unsigned int divisor){ return (dividend % divisor == 0) ? (dividend / divisor) : (dividend / divisor + 1); } cl_int oclGetPlatformID(cl_platform_id* selectedPlatform) { cl_uint num_platforms = 0; cl_platform_id* clPlatformIDs; cl_int ciErrNum = 0; ciErrNum = clGetPlatformIDs( 0, nullptr, &num_platforms); if ( ciErrNum != CL_SUCCESS) { MITK_ERROR<<" Error " << ciErrNum << " in clGetPlatformIDs() \n"; throw std::bad_exception(); } else { clPlatformIDs = new cl_platform_id[num_platforms]; ciErrNum = clGetPlatformIDs( num_platforms, clPlatformIDs, nullptr); if(ciErrNum == CL_SUCCESS) { *selectedPlatform = clPlatformIDs[0]; } } return CL_SUCCESS; } void oclPrintMemObjectInfo(cl_mem memobj) { cl_int clErr = 0; MITK_INFO << "Examining cl_mem object: " << memobj << "\n------------------\n"; // CL_MEM_TYPE cl_mem_object_type objtype; clErr = clGetMemObjectInfo( memobj, CL_MEM_TYPE, sizeof(cl_mem_object_type),&objtype, nullptr); CHECK_OCL_ERR( clErr ); switch(objtype) { case CL_MEM_OBJECT_BUFFER: MITK_INFO << "CL_MEM_TYPE \t" << "BUFFER_OBJ" << "\n"; break; case CL_MEM_OBJECT_IMAGE2D: MITK_INFO << "CL_MEM_TYPE \t" << "2D IMAGE" << "\n"; break; case CL_MEM_OBJECT_IMAGE3D: MITK_INFO << "CL_MEM_TYPE \t" << "3D IMAGE" << "\n"; break; default: MITK_INFO << "CL_MEM_TYPE \t" << "[could not resolve]" << "\n"; break; } // CL_MEM_FLAGS cl_mem_flags flags; clErr = clGetMemObjectInfo( memobj, CL_MEM_FLAGS, sizeof(cl_mem_flags),&flags, nullptr); CHECK_OCL_ERR( clErr ); switch(flags) { case CL_MEM_READ_ONLY: MITK_INFO << "CL_MEM_FLAGS \t" << "CL_MEM_READ_ONLY" << "\n"; break; case CL_MEM_WRITE_ONLY: MITK_INFO << "CL_MEM_FLAGS \t" << "CL_MEM_WRITE_ONLY" << "\n"; break; case CL_MEM_READ_WRITE: MITK_INFO << "CL_MEM_FLAGS \t" << "CL_MEM_READ_WRITE" << "\n"; break; default: MITK_INFO << "CL_MEM_FLAGS \t" << "not resolved, " << flags << "\n"; break; } // get CL_MEM_SIZE size_t memsize; clErr = clGetMemObjectInfo( memobj, CL_MEM_SIZE, sizeof(memsize),&memsize, nullptr); CHECK_OCL_ERR( clErr ); MITK_INFO << "CL_MEM_SIZE \t" << memsize << "\n"; // get CL_MEM_HOST_PTR float *hostptr; clErr = clGetMemObjectInfo( memobj, CL_MEM_HOST_PTR, sizeof(void*), (void*) &hostptr, nullptr); CHECK_OCL_ERR( clErr ); MITK_INFO << "CL_MEM_HOST_PTR \t" << hostptr << "\n"; // get CL_CONTEXT cl_context gpuctxt; clErr = clGetMemObjectInfo( memobj, CL_MEM_CONTEXT, sizeof(cl_context), &gpuctxt, nullptr); CHECK_OCL_ERR( clErr ); MITK_INFO << "CL_CONTEXT \t\t" << gpuctxt << "\n"; // get CL_MEM_REFERENCE_COUNT cl_uint refs; clErr = clGetMemObjectInfo( memobj, CL_MEM_REFERENCE_COUNT, sizeof(cl_uint), &refs, nullptr); CHECK_OCL_ERR(clErr); MITK_INFO << "CL_REF_COUNT \t" << refs << "\n"; MITK_INFO << "================== \n" << std::endl; } void oclPrintDeviceInfo(cl_device_id device) { char device_string[1024]; clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_string), &device_string, nullptr); MITK_INFO("ocl.log")<< " Device : " << device_string; // CL_DEVICE_INFO cl_device_type type; clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(type), &type, nullptr); if( type & CL_DEVICE_TYPE_CPU ) MITK_INFO("ocl.log")<<" CL_DEVICE_TYPE: CL_DEVICE_TYPE_CPU"; if( type & CL_DEVICE_TYPE_GPU ) MITK_INFO("ocl.log")<<" CL_DEVICE_TYPE: CL_DEVICE_TYPE_GPU"; if( type & CL_DEVICE_TYPE_ACCELERATOR ) MITK_INFO("ocl.log")<<" CL_DEVICE_TYPE: CL_DEVICE_TYPE_ACCELERATOR"; if( type & CL_DEVICE_TYPE_DEFAULT ) MITK_INFO("ocl.log")<<" CL_DEVICE_TYPE: CL_DEVICE_TYPE_DEFAULT"; // CL_DEVICE_MAX_COMPUTE_UNITS cl_uint compute_units; clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_MAX_COMPUTE_UNITS:" << compute_units; // CL_DEVICE_MAX_WORK_GROUP_SIZE size_t workitem_size[3]; clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(workitem_size), &workitem_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_MAX_WORK_ITEM_SIZES:\t"<< workitem_size[0]<< workitem_size[1]<< workitem_size[2]; // CL_DEVICE_MAX_WORK_GROUP_SIZE size_t workgroup_size; clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_MAX_WORK_GROUP_SIZE:" << workgroup_size; // CL_DEVICE_MAX_CLOCK_FREQUENCY cl_uint clock_frequency; clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_MAX_CLOCK_FREQUENCY:"<< clock_frequency / 1000; // CL_DEVICE_IMAGE_SUPPORT cl_bool image_support; clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(image_support), &image_support, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE_SUPPORT:\t" << image_support; // CL_DEVICE_GLOBAL_MEM_SIZE cl_ulong mem_size; clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(mem_size), &mem_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_GLOBAL_MEM_SIZE:\t\t"<<(unsigned int)(mem_size / (1024 * 1024))<<"Mbytes"; // CL_DEVICE_LOCAL_MEM_SIZE clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(mem_size), &mem_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_LOCAL_MEM_SIZE:\t\t"<< (unsigned int)(mem_size / (1024)) <<"KByte\n"; //check for image support properties clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE2D_MAX_WIDTH:\t" << workgroup_size; clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE2D_MAX_HEIGHT:\t" << workgroup_size; clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE3D_MAX_WIDTH:\t" << workgroup_size; clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE3D_MAX_HEIGHT:\t" << workgroup_size; clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(workgroup_size), &workgroup_size, nullptr); MITK_INFO("ocl.log")<<" CL_DEVICE_IMAGE3D_MAX_DEPTH:\t" << workgroup_size; // CL_DEVICE_QUEUE_PROPERTIES cl_command_queue_properties queue_properties; clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, sizeof(queue_properties), &queue_properties, nullptr); if( queue_properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE ) MITK_INFO("ocl.log")<<" CL_DEVICE_QUEUE_PROPERTIES:\t\t"<< "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE"; if( queue_properties & CL_QUEUE_PROFILING_ENABLE ) MITK_INFO("ocl.log")<<" CL_DEVICE_QUEUE_PROPERTIES:\t\t"<< "CL_QUEUE_PROFILING_ENABLE"; } std::string GetOclErrorAsString( int _clErr ) { - std::string returnString("CL_SUCCESS\n"); + std::string returnString("unkown error number: "+std::to_string(_clErr)+" \n"); switch(_clErr) { + case CL_SUCCESS: + returnString = "CL_SUCCESS\n"; + break; case CL_DEVICE_NOT_FOUND: returnString = "CL_DEVICE_NOT_FOUND\n"; break; case CL_DEVICE_NOT_AVAILABLE: returnString = "CL_DEVICE_NOT_AVAILABLE\n"; break; /*case CL_DEVICE_COMPILER_NOT_AVAILABLE: returnString = "CL_DEVICE_COMPILER_NOT_AVAILABLE\n"; break; */ case CL_MEM_OBJECT_ALLOCATION_FAILURE : returnString = "CL_MEM_OBJECT_ALLOCATION_FAILURE\n"; break; case CL_OUT_OF_RESOURCES: returnString = "CL_OUT_OF_RESOURCES\n"; break; case CL_OUT_OF_HOST_MEMORY: returnString = "CL_OUT_OF_HOST_MEMORY\n"; break; case CL_PROFILING_INFO_NOT_AVAILABLE: returnString = "CL_PROFILING_INFO_NOT_AVAILABLE\n"; break; case CL_MEM_COPY_OVERLAP: returnString = "CL_MEM_COPY_OVERLAP\n"; break; case CL_IMAGE_FORMAT_MISMATCH: returnString = "CL_IMAGE_FORMAT_MISMATCH\n"; break; case CL_IMAGE_FORMAT_NOT_SUPPORTED: returnString = "CL_IMAGE_FORMAT_NOT_SUPPORTED\n"; break; case CL_BUILD_PROGRAM_FAILURE: returnString = "CL_BUILD_PROGRAM_FAILURE\n"; break; case CL_MAP_FAILURE: returnString = "CL_MAP_FAILURE\n"; break; case CL_INVALID_VALUE: returnString = "CL_INVALID_VALUE\n"; break; case CL_INVALID_DEVICE_TYPE: returnString = "CL_INVALID_DEVICE_TYPE\n"; break; case CL_INVALID_PLATFORM: returnString = "CL_INVALID_PLATFORM\n"; break; case CL_INVALID_DEVICE: returnString = "CL_INVALID_DEVICE\n"; break; case CL_INVALID_CONTEXT : returnString = "CL_INVALID_CONTEXT\n"; break; case CL_INVALID_QUEUE_PROPERTIES: returnString = "CL_INVALID_QUEUE_PROPERTIES\n"; break; case CL_INVALID_COMMAND_QUEUE: returnString = "CL_INVALID_COMMAND_QUEUE\n"; break; case CL_INVALID_HOST_PTR: returnString = "CL_INVALID_HOST_PTR\n"; break; case CL_INVALID_MEM_OBJECT: returnString = "CL_INVALID_MEM_OBJECT\n"; break; case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: returnString = "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR\n"; break; case CL_INVALID_IMAGE_SIZE: returnString = "CL_INVALID_IMAGE_SIZE\n"; break; case CL_INVALID_SAMPLER : returnString = "CL_INVALID_SAMPLER\n"; break; case CL_INVALID_BINARY: returnString = "CL_INVALID_BINARY\n"; break; case CL_INVALID_BUILD_OPTIONS: returnString = "CL_INVALID_BUILD_OPTIONS\n"; break; case CL_INVALID_PROGRAM: returnString = "CL_INVALID_PROGRAM\n"; break; case CL_INVALID_PROGRAM_EXECUTABLE: returnString = "CL_INVALID_PROGRAM_EXECUTABLE\n"; break; case CL_INVALID_KERNEL_NAME: returnString = "CL_INVALID_KERNEL_NAME\n"; break; case CL_INVALID_KERNEL_DEFINITION: returnString = "CL_INVALID_KERNEL_DEFINITION\n"; break; case CL_INVALID_KERNEL : returnString = "CL_INVALID_KERNEL\n"; break; case CL_INVALID_ARG_INDEX : returnString = "CL_INVALID_ARG_INDEX\n"; break; case CL_INVALID_ARG_VALUE : returnString = "CL_INVALID_ARG_VALUE\n"; break; case CL_INVALID_ARG_SIZE : returnString = "CL_INVALID_ARG_SIZE\n"; break; case CL_INVALID_KERNEL_ARGS : returnString = "CL_INVALID_KERNEL_ARGS\n"; break; case CL_INVALID_WORK_DIMENSION: returnString = "CL_INVALID_WORK_DIMENSION\n"; break; case CL_INVALID_WORK_GROUP_SIZE: returnString = "CL_INVALID_WORK_GROUP_SIZE\n"; break; case CL_INVALID_WORK_ITEM_SIZE: returnString = "CL_INVALID_WORK_ITEM_SIZE\n"; break; case CL_INVALID_GLOBAL_OFFSET: returnString = "CL_INVALID_GLOBAL_OFFSET\n"; break; case CL_INVALID_EVENT_WAIT_LIST: returnString = "CL_INVALID_EVENT_WAIT_LIST\n"; break; case CL_INVALID_EVENT: returnString = "CL_INVALID_EVENT\n"; break; case CL_INVALID_OPERATION: returnString = "CL_INVALID_OPERATION\n"; break; case CL_INVALID_GL_OBJECT: returnString = "CL_INVALID_GL_OBJECT\n"; break; case CL_INVALID_BUFFER_SIZE : returnString = "CL_INVALID_BUFFER_SIZE\n"; break; case CL_INVALID_MIP_LEVEL : returnString = "CL_INVALID_MIP_LEVEL\n"; break; default: break; } return returnString; } void GetOclError(int _clErr) { - if(_clErr == CL_SUCCESS ) + if(_clErr == CL_SUCCESS) MITK_WARN << "Called GetOclErr() with no error value: [CL_SUCCESS]"; else MITK_ERROR << GetOclErrorAsString(_clErr); } bool oclCheckError(int _err, const char* filepath, int lineno) { if (_err) { MITK_ERROR<< "OpenCL Error at " << filepath <<":"<< lineno; GetOclError(_err); return 0; } return 1; } void GetSupportedImageFormats(cl_context _context, cl_mem_object_type _type) { const unsigned int entries = 500; cl_image_format* formats = new cl_image_format[entries]; cl_uint _written = 0; // OpenCL constant to catch error IDs cl_int ciErr1; // Get list of supported image formats for READ_ONLY access ciErr1 = clGetSupportedImageFormats( _context, CL_MEM_READ_ONLY, _type, entries, formats, &_written); CHECK_OCL_ERR(ciErr1); MITK_INFO << "Supported Image Formats, Image: CL_MEM_READ_ONLY \n"; for (unsigned int i=0; i<_written; i++) { MITK_INFO<< "ChannelType: " << GetImageTypeAsString(formats[i].image_channel_data_type) << "| ChannelOrder: "<< GetImageTypeAsString(formats[i].image_channel_order) <<"\n"; } _written = 0; // Get list of supported image formats for READ_WRITE access ciErr1 = clGetSupportedImageFormats( _context, CL_MEM_READ_WRITE, _type, entries, formats, &_written); CHECK_OCL_ERR(ciErr1); MITK_INFO << "Supported Image Formats, Image: CL_MEM_READ_WRITE (found: " << _written <<") \n"; for (unsigned int i=0; i<_written; i++) { MITK_INFO<< "ChannelType: " << GetImageTypeAsString(formats[i].image_channel_data_type) << "| ChannelOrder: "<< GetImageTypeAsString(formats[i].image_channel_order) <<"\n"; } _written = 0; // Get list of supported image formats for WRITE_ONLY access ciErr1 = clGetSupportedImageFormats( _context, CL_MEM_WRITE_ONLY, _type, entries, formats, &_written); CHECK_OCL_ERR(ciErr1); MITK_INFO << "Supported Image Formats, Image: CL_MEM_WRITE_ONLY (found: " << _written <<") \n"; for (unsigned int i=0; i<_written; i++) { MITK_INFO<< "ChannelType: " << GetImageTypeAsString(formats[i].image_channel_data_type) << "| ChannelOrder: "<< GetImageTypeAsString(formats[i].image_channel_order) <<"\n"; } } std::string GetImageTypeAsString( const unsigned int _in) { switch(_in) { case CL_R: return "CL_R "; break; case CL_A: return "CL_A "; break; case CL_RG: return "CL_RG "; break; case CL_RA: return "CL_RA "; break; case CL_RGB: return "CL_RGB "; break; case CL_RGBA: return "CL_RGBA "; break; case CL_BGRA: return "CL_BGRA "; break; case CL_ARGB: return "CL_ARGB "; break; case CL_INTENSITY: return "CL_INTENSITY "; break; case CL_LUMINANCE: return "CL_LUMINANCE "; break; case CL_SNORM_INT8: return "CL_SNORM_INT8 "; break; case CL_SNORM_INT16: return "CL_SNORM_INT16 "; break; case CL_UNORM_INT8: return "CL_UNORM_INT8 "; break; case CL_UNORM_INT16: return "CL_UNORM_INT16 "; break; case CL_UNORM_SHORT_565: return "CL_UNORM_SHORT_565 "; break; case CL_UNORM_SHORT_555: return "CL_UNORM_SHORT_555 "; break; case CL_UNORM_INT_101010: return "CL_UNORM_INT_101010 "; break; case CL_SIGNED_INT8: return "CL_SIGNED_INT8 "; break; case CL_SIGNED_INT16: return "CL_SIGNED_INT16 "; break; case CL_SIGNED_INT32: return "CL_SIGNED_INT32 "; break; case CL_UNSIGNED_INT8: return "CL_UNSIGNED_INT8 "; break; case CL_UNSIGNED_INT16: return "CL_UNSIGNED_INT16 "; break; case CL_UNSIGNED_INT32: return "CL_UNSIGNED_INT32 "; break; case CL_HALF_FLOAT: return "CL_HALF_FLOAT "; break; case CL_FLOAT: return "CL_FLOAT "; break; default: return "--"; break; } } void oclLogBinary(cl_program clProg, cl_device_id clDev) { // Grab the number of devices associated with the program cl_uint num_devices; clGetProgramInfo(clProg, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &num_devices, nullptr); // Grab the device ids cl_device_id* devices = (cl_device_id*) malloc(num_devices * sizeof(cl_device_id)); clGetProgramInfo(clProg, CL_PROGRAM_DEVICES, num_devices * sizeof(cl_device_id), devices, 0); // Grab the sizes of the binaries size_t* binary_sizes = (size_t*)malloc(num_devices * sizeof(size_t)); clGetProgramInfo(clProg, CL_PROGRAM_BINARY_SIZES, num_devices * sizeof(size_t), binary_sizes, nullptr); // Now get the binaries char** ptx_code = (char**)malloc(num_devices * sizeof(char*)); for( unsigned int i=0; i + +#include "itkFFT1DComplexToComplexImageFilter.h" +#include "itkFFT1DRealToComplexConjugateImageFilter.h" +#include "itkImageRegionSplitterDirection.h" + +namespace itk +{ +/** \class AnalyticSignalImageFilter + * \brief Generates the analytic signal from one direction of an image. + * + * This filter generates the complex valued analytic signal along one direction + * of an image. This input is a real valued image, and the output is a complex + * image. + * + * The analytic signal is given by + * + * f_a(x) = f(x) - i f_H(x) + * + * Where i is the square root of one and f_H(x) is the Hibert transform of f(x). + * + * Since the Hilbert transform in the Fourier domain is + * + * F_H(k) = F(k) i sign(k), + * + * f_a(x) is calculated by + * + * f_a(x) = F^{-1}( F(k) 2 U(k) ) + * + * where U(k) is the unit step function. + * + * \ingroup FourierTransform + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage > +class AnalyticSignalImageFilter: + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension); + + typedef AnalyticSignalImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkTypeMacro( AnalyticSignalImageFilter, ImageToImageFilter ); + itkNewMacro( Self ); + + /** Get the direction in which the filter is to be applied. */ + virtual unsigned int GetDirection() const + { + return this->m_FFTRealToComplexFilter->GetDirection(); + } + + /** Set the direction in which the filter is to be applied. */ + virtual void SetDirection( const unsigned int direction ) + { + if( this->m_FFTRealToComplexFilter->GetDirection() != direction ) + { + this->m_FFTRealToComplexFilter->SetDirection( direction ); + this->m_FFTComplexToComplexFilter->SetDirection( direction ); + this->Modified(); + } + } + +protected: + AnalyticSignalImageFilter(); + virtual ~AnalyticSignalImageFilter() {} + + void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + + // These behave like their analogs in FFT1DRealToComplexConjugateImageFilter. + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + virtual void BeforeThreadedGenerateData() ITK_OVERRIDE; + virtual void ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId ) ITK_OVERRIDE; + virtual void AfterThreadedGenerateData() ITK_OVERRIDE; + + typedef FFT1DRealToComplexConjugateImageFilter< InputImageType, OutputImageType > FFTRealToComplexType; + typedef FFT1DComplexToComplexImageFilter< OutputImageType, OutputImageType > FFTComplexToComplexType; + + typename FFTRealToComplexType::Pointer m_FFTRealToComplexFilter; + typename FFTComplexToComplexType::Pointer m_FFTComplexToComplexFilter; + + /** Override to return a splitter that does not split along the direction we + * are performing the transform. */ + virtual const ImageRegionSplitterBase* GetImageRegionSplitter() const ITK_OVERRIDE; + +private: + AnalyticSignalImageFilter( const Self& ); // purposely not implemented + void operator=( const Self& ); // purposely not implemented + + ImageRegionSplitterDirection::Pointer m_ImageRegionSplitter; +}; +} + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkAnalyticSignalImageFilter.hxx" +#endif + +#endif // itkAnalyticSignalImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkAnalyticSignalImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkAnalyticSignalImageFilter.hxx new file mode 100644 index 0000000000..a48bcba4cb --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkAnalyticSignalImageFilter.hxx @@ -0,0 +1,271 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkAnalyticSignalImageFilter_hxx +#define itkAnalyticSignalImageFilter_hxx + +#include "itkAnalyticSignalImageFilter.h" + +#include "itkVnlFFT1DRealToComplexConjugateImageFilter.h" +#include "itkVnlFFT1DComplexToComplexImageFilter.h" + +#if defined(ITK_USE_FFTWD) || defined(ITK_USE_FFTWF) +#include "itkFFTW1DRealToComplexConjugateImageFilter.h" +#include "itkFFTW1DComplexToComplexImageFilter.h" +#endif + +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" +#include "itkMetaDataObject.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::AnalyticSignalImageFilter() +{ + m_FFTRealToComplexFilter = FFTRealToComplexType::New(); + m_FFTComplexToComplexFilter = FFTComplexToComplexType::New(); + + m_FFTComplexToComplexFilter->SetTransformDirection( FFTComplexToComplexType::INVERSE ); + + this->SetDirection( 0 ); + + this->m_ImageRegionSplitter = ImageRegionSplitterDirection::New(); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + typename InputImageType::Pointer inputPtr = + const_cast (this->GetInput()); + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->GetDirection(); + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast< OutputImageType* >( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + const unsigned int direction = this->GetDirection (); + enlargedSize[direction] = outputLargeSize[direction]; + enlargedIndex[direction] = outputLargeIndex[direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + const unsigned int direction = this->GetDirection(); + os << indent << "Direction: " << direction << std::endl; + + os << indent << "FFTRealToComplexFilter: " << std::endl; + m_FFTRealToComplexFilter->Print( os, indent ); + os << indent << "FFTComplexToComplexFilter: " << std::endl; + m_FFTComplexToComplexFilter->Print( os, indent ); +} + + +template< typename TInputImage, typename TOutputImage > +const ImageRegionSplitterBase * +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::GetImageRegionSplitter() const +{ + return this->m_ImageRegionSplitter.GetPointer(); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::BeforeThreadedGenerateData() +{ + this->m_ImageRegionSplitter->SetDirection( this->GetDirection() ); + + m_FFTRealToComplexFilter->SetInput( this->GetInput() ); + m_FFTRealToComplexFilter->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); + m_FFTRealToComplexFilter->GetOutput()->SetLargestPossibleRegion( this->GetOutput()->GetLargestPossibleRegion() ); + m_FFTRealToComplexFilter->SetNumberOfThreads( this->GetNumberOfThreads() ); + m_FFTRealToComplexFilter->Update (); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType itkNotUsed( threadId ) ) +{ + // get pointers to the input and output + const typename FFTRealToComplexType::OutputImageType * inputPtr = m_FFTRealToComplexFilter->GetOutput(); + OutputImageType * outputPtr = this->GetOutput(); + + const typename FFTRealToComplexType::OutputImageType::SizeType & inputSize = inputPtr->GetRequestedRegion().GetSize(); + const unsigned int direction = this->GetDirection (); + const unsigned int size = inputSize[direction]; + unsigned int dub_size; + bool even; + if( size % 2 == 0 ) + { + even = true; + dub_size = size / 2 - 1; + } + else + { + even = false; + dub_size = (size + 1) / 2 - 1; + } + + typedef ImageLinearConstIteratorWithIndex< typename FFTRealToComplexType::OutputImageType > InputIteratorType; + typedef ImageLinearIteratorWithIndex< OutputImageType > OutputIteratorType; + InputIteratorType inputIt( inputPtr, outputRegionForThread ); + OutputIteratorType outputIt( outputPtr, outputRegionForThread ); + inputIt.SetDirection( direction ); + outputIt.SetDirection( direction ); + + unsigned int i; + // for every fft line + for( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); + outputIt.NextLine(), inputIt.NextLine() ) + { + inputIt.GoToBeginOfLine(); + outputIt.GoToBeginOfLine(); + + // DC + outputIt.Set( inputIt.Get() ); + ++inputIt; + ++outputIt; + + for( i = 0; i < dub_size; i++ ) + { + outputIt.Set( inputIt.Get() * static_cast< typename TInputImage::PixelType >( 2 ) ); + ++outputIt; + ++inputIt; + } + if( even ) + { + outputIt.Set( inputIt.Get() ); + ++inputIt; + ++outputIt; + } + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( static_cast< typename TInputImage::PixelType >( 0 ) ); + ++outputIt; + } + } +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::AfterThreadedGenerateData() +{ + // Trippy, eh? + m_FFTComplexToComplexFilter->SetInput( this->GetOutput() ); + m_FFTComplexToComplexFilter->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); + m_FFTComplexToComplexFilter->GetOutput()->SetLargestPossibleRegion( this->GetOutput()->GetLargestPossibleRegion() ); + m_FFTComplexToComplexFilter->SetNumberOfThreads( this->GetNumberOfThreads() ); + m_FFTComplexToComplexFilter->Update (); + this->GraftOutput( m_FFTComplexToComplexFilter->GetOutput() ); +} + +} // end namespace itk + +#endif // itkAnalyticSignalImageFilter_hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.h new file mode 100644 index 0000000000..09b4c08bed --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.h @@ -0,0 +1,156 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkBModeImageFilter_h +#define itkBModeImageFilter_h + +#include "itkAddImageFilter.h" +#include "itkComplexToModulusImageFilter.h" +#include "itkConstantPadImageFilter.h" +#include "itkRegionFromReferenceImageFilter.h" +#include "itkImageToImageFilter.h" +#include "itkImage.h" +#include "itkLog10ImageFilter.h" + +#include "itkAnalyticSignalImageFilter.h" + +namespace itk +{ + +/** + * \class BModeImageFilter + * + * \brief Create an ultrasound B-Mode (Brightness-Mode) image from raw + * "RF" data. The RF's envelope is calculated from the analytic signal and + * logarithmic intensity transform is applied. + * + * Use SetDirection() to define the axis of propagation. + * + * \ingroup Ultrasound + * + * \sa AnalyticSignalImageFilter + * + */ +template < typename TInputImage, typename TOutputImage=TInputImage, typename TComplexImage=Image< std::complex< typename TInputImage::PixelType >, TInputImage::ImageDimension > > +class BModeImageFilter : + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef BModeImageFilter Self; + typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + /** The type of input image. */ + typedef TInputImage InputImageType; + + /** Dimension of the input and output images. */ + itkStaticConstMacro (ImageDimension, unsigned int, + TInputImage::ImageDimension); + + /** Typedef support for the input image scalar value type. */ + typedef typename InputImageType::PixelType InputPixelType; + + /** The type of output image. */ + typedef TOutputImage OutputImageType; + + /** Typedef support for the output image scalar value type. */ + typedef typename OutputImageType::PixelType OutputPixelType; + + /** Typedef of the image used for internal computations that has + * std::complex pixels. */ + typedef TComplexImage ComplexImageType; + + /** Other convenient typedefs */ + typedef typename InputImageType::RegionType InputRegionType; + typedef typename InputImageType::SizeType InputSizeType; + typedef typename InputImageType::IndexType InputIndexType; + + /** Run-time type information (and related methods) */ + itkTypeMacro( BModeImageFilter, ImageToImageFilter ); + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Set the direction in which the envelope is to be calculated. */ + virtual void SetDirection( unsigned int direction ) + { + this->m_AnalyticFilter->SetDirection( direction ); + this->Modified(); + } + + /** Get the direction in which the envelope is to be calculated. */ + virtual unsigned int GetDirection() const + { + return m_AnalyticFilter->GetDirection(); + } + +protected: + BModeImageFilter(); + ~BModeImageFilter() {} + + virtual void PrintSelf( std::ostream& os, Indent indent ) const ITK_OVERRIDE; + + virtual void GenerateData() ITK_OVERRIDE; + + // These behave like their analogs in FFT1DRealToComplexConjugateImageFilter. + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + /** Component filters. */ + typedef AnalyticSignalImageFilter< InputImageType, ComplexImageType > AnalyticType; + typedef ComplexToModulusImageFilter< typename AnalyticType::OutputImageType, OutputImageType > ComplexToModulusType; + typedef ConstantPadImageFilter< InputImageType, InputImageType > PadType; + typedef AddImageFilter< InputImageType, InputImageType > AddConstantType; + typedef Log10ImageFilter< InputImageType, OutputImageType > LogType; + typedef RegionFromReferenceImageFilter< OutputImageType, OutputImageType > ROIType; + +private: + BModeImageFilter( const Self& ); // purposely not implemented + void operator=( const Self& ); // purposely not implemented + + typename AnalyticType::Pointer m_AnalyticFilter; + typename ComplexToModulusType::Pointer m_ComplexToModulusFilter; + typename PadType::Pointer m_PadFilter; + typename AddConstantType::Pointer m_AddConstantFilter; + typename LogType::Pointer m_LogFilter; + typename ROIType::Pointer m_ROIFilter; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkBModeImageFilter.hxx" +#endif + +#endif // itkBModeImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.hxx new file mode 100644 index 0000000000..eff78e6836 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkBModeImageFilter.hxx @@ -0,0 +1,212 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkBModeImageFilter_hxx +#define itkBModeImageFilter_hxx + +#include "itkBModeImageFilter.h" + +#include "itkMetaDataDictionary.h" + +#include +#include +#include + +namespace itk +{ + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::BModeImageFilter() +{ + m_AnalyticFilter = AnalyticType::New(); + m_ComplexToModulusFilter = ComplexToModulusType::New(); + m_PadFilter = PadType::New(); + m_AddConstantFilter = AddConstantType::New(); + m_LogFilter = LogType::New(); + m_ROIFilter = ROIType::New(); + + // Avoid taking the log of zero. Assuming that the original input is coming + // from a digitizer that outputs integer types, so 1 is small. + m_AddConstantFilter->SetConstant2( 1 ); + m_PadFilter->SetConstant( 0. ); + + m_ComplexToModulusFilter->SetInput( m_AnalyticFilter->GetOutput() ); + m_ROIFilter->SetInput( m_ComplexToModulusFilter->GetOutput() ); + m_LogFilter->SetInput( m_AddConstantFilter->GetOutput() ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + InputImageType * inputPtr = const_cast (this->GetInput()); + OutputImageType * outputPtr = this->GetOutput(); + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->GetDirection(); + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast< OutputImageType* >( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + const unsigned int direction = this->GetDirection (); + enlargedSize[direction] = outputLargeSize[direction]; + enlargedIndex[direction] = outputLargeIndex[direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::GenerateData() +{ + this->AllocateOutputs(); + + const InputImageType * inputPtr = this->GetInput(); + OutputImageType * outputPtr = this->GetOutput(); + + const unsigned int direction = m_AnalyticFilter->GetDirection(); + typename InputImageType::SizeType size = inputPtr->GetLargestPossibleRegion().GetSize(); + + // Zero padding. FFT direction should be factorable by 2 for all FFT + // implementations to work. + unsigned int n = size[direction]; + while( n % 2 == 0 ) + { + n /= 2; + } + bool doPadding; + if( n == 1 ) + { + doPadding = false; + } + else + { + doPadding = true; + } + if( doPadding ) + { + n = size[direction]; + unsigned int newSizeDirection = 1; + while( newSizeDirection < n ) + { + newSizeDirection *= 2; + } + typename InputImageType::SizeType padSize; + padSize.Fill( 0 ); + padSize[direction] = newSizeDirection - size[direction]; + size[direction] = newSizeDirection; + m_PadFilter->SetPadUpperBound( padSize ); + m_PadFilter->SetInput( inputPtr ); + m_AnalyticFilter->SetInput( m_PadFilter->GetOutput() ); + m_ROIFilter->SetReferenceImage( inputPtr ); + m_ROIFilter->SetInput( m_ComplexToModulusFilter->GetOutput() ); + m_AddConstantFilter->SetInput( m_ROIFilter->GetOutput() ); + } + else // padding is not required + { + m_AnalyticFilter->SetInput( inputPtr ); + m_AddConstantFilter->SetInput( m_ComplexToModulusFilter->GetOutput() ); + } + m_LogFilter->GraftOutput( outputPtr ); + m_LogFilter->Update(); + this->GraftOutput( m_LogFilter->GetOutput() ); +} + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.h new file mode 100644 index 0000000000..ce29acd93e --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.h @@ -0,0 +1,351 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkCurvilinearArraySpecialCoordinatesImage_h +#define itkCurvilinearArraySpecialCoordinatesImage_h + +#include "itkSpecialCoordinatesImage.h" +#include "itkPoint.h" +#include "vnl/vnl_math.h" +#include "itkNeighborhoodAccessorFunctor.h" + +namespace itk +{ +/** \class CurvilinearArraySpecialCoordinatesImage + * + * \brief Templated 2D nonrectilinear-coordinate image class for + * curvilinear/phased-array "range" images. + * + * \verbatim + * + * +---------------------> x-axis + * |\ + * / | \ + * |-~\ + * / | \ + * | \ + * / | \ + * | lateral + * | + * v y-axis + * + * \endverbatim + * + * The equations form performing the conversion from Cartesian coordinates to + * curvilinear/phased array coordinates are as follows: + * + * lateral = arctan(x/y) + * radius = std::sqrt(x^2 + y^2) + * + * The reversed transforms are: + * + * x = radius * std::sin(lateral) + * y = radius * std::cos(lateral) + * + * CurvilinearArraySpecialCoordinatesImages are templated over a pixel + * type and follow the SpecialCoordinatesImage interface. The data in + * an image is arranged in a 1D array as + * [lateral-index][radius-index] with radius-index + * varying most rapidly. The Index type reverses the order so that + * Index[0] = radius-index, Index[1] = lateral-index. + * + * Lateral is discretized into m_LateralAngularSeparation intervals + * per angular voxel, the most negative lateral interval containing + * data is then mapped to lateral-index=0, and the largest lateral + * interval containing data is then mapped to lateral-index=( number + * of samples along lateral axis - 1 ). Elevation is discretized in + * the same manner. This way, the mapping to Cartesian space is + * symmetric about the x axis such that the line defined by + * lateral/2 = x-axis. Radius is discretized into + * m_RadiusSampleSize units per angular voxel. The smallest range + * interval containing data is then mapped to radius-index=0, such + * that radius = m_FirstSampleDistance + (radius-index * + * m_RadiusSampleSize). + * + * \sa SpecialCoordinatesImage + * \sa PhasedArray3DSpecialCoordinatesImage + * + * \ingroup Ultrasound + * + * \ingroup ImageObjects + * \ingroup ITKCommon + */ +template< typename TPixel, unsigned int VDimension > +class CurvilinearArraySpecialCoordinatesImage: + public SpecialCoordinatesImage< TPixel, VDimension > +{ +public: + /** Standard class typedefs */ + typedef CurvilinearArraySpecialCoordinatesImage Self; + typedef SpecialCoordinatesImage< TPixel, VDimension > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + typedef WeakPointer< const Self > ConstWeakPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(CurvilinearArraySpecialCoordinatesImage, SpecialCoordinatesImage); + + /** Pixel typedef support. Used to declare pixel type in filters + * or other operations. */ + typedef TPixel PixelType; + + /** Typedef alias for PixelType */ + typedef TPixel ValueType; + + /** Internal Pixel representation. Used to maintain a uniform API + * with Image Adaptors and allow to keep a particular internal + * representation of data while showing a different external + * representation. */ + typedef TPixel InternalPixelType; + + typedef typename Superclass::IOPixelType IOPixelType; + + /** Accessor type that convert data between internal and external + * representations. */ + typedef DefaultPixelAccessor< PixelType > AccessorType; + + /** Accessor functor to choose between accessors: DefaultPixelAccessor for + * the Image, and DefaultVectorPixelAccessor for the vector image. The + * functor provides a generic API between the two accessors. */ + typedef DefaultPixelAccessorFunctor< Self > AccessorFunctorType; + + /** Typedef for the functor used to access a neighborhood of pixel + * pointers. */ + typedef NeighborhoodAccessorFunctor< Self > NeighborhoodAccessorFunctorType; + + /** Dimension of the image. This constant is used by functions that are + * templated over image type (as opposed to being templated over pixel type + * and dimension) when they need compile time access to the dimension of + * the image. */ + itkStaticConstMacro(ImageDimension, unsigned int, VDimension); + + /** Index typedef support. An index is used to access pixel values. */ + typedef typename Superclass::IndexType IndexType; + typedef typename Superclass::IndexValueType IndexValueType; + + /** Offset typedef support. An offset is used to access pixel values. */ + typedef typename Superclass::OffsetType OffsetType; + + /** Size typedef support. A size is used to define region bounds. */ + typedef typename Superclass::SizeType SizeType; + typedef typename Superclass::SizeValueType SizeValueType; + + /** Container used to store pixels in the image. */ + typedef ImportImageContainer< SizeValueType, PixelType > PixelContainer; + + /** Region typedef support. A region is used to specify a subset of + * an image. + */ + typedef typename Superclass::RegionType RegionType; + + /** Spacing typedef support. Spacing holds the "fake" size of a + * pixel, making each pixel look like a 1 unit hyper-cube to filters + * that were designed for normal images and that therefore use + * m_Spacing. The spacing is the geometric distance between image + * samples. + */ + typedef typename Superclass::SpacingType SpacingType; + + /** Origin typedef support. The origin is the "fake" geometric + * coordinates of the index (0,0). Also for use w/ filters designed + * for normal images. + */ + typedef typename Superclass::PointType PointType; + + /** A pointer to the pixel container. */ + typedef typename PixelContainer::Pointer PixelContainerPointer; + typedef typename PixelContainer::ConstPointer PixelContainerConstPointer; + + /** Graft the data and information from one image to another. This + * is a convenience method to setup a second image with all the meta + * information of another image and use the same pixel + * container. Note that this method is different than just using two + * SmartPointers to the same image since separate DataObjects are + * still maintained. This method is similar to + * ImageSource::GraftOutput(). The implementation in ImageBase + * simply calls CopyInformation() and copies the region ivars. + * The implementation here refers to the superclass' implementation + * and then copies over the pixel container. */ + virtual void Graft(const DataObject *data) ITK_OVERRIDE; + + /** \brief Get the continuous index from a physical point + * + * Returns true if the resulting index is within the image, false otherwise. + * \sa Transform */ + template< typename TCoordRep > + bool TransformPhysicalPointToContinuousIndex( + const Point< TCoordRep, VDimension > & point, + ContinuousIndex< TCoordRep, VDimension > & index) const + { + const RegionType & region = this->GetLargestPossibleRegion(); + const double maxLateral = region.GetSize(1) - 1; + + // Convert Cartesian coordinates into angular coordinates + const TCoordRep lateral = std::atan(point[0] / point[1]); + const TCoordRep radius = std::sqrt(point[0] * point[0] + point[1] * point[1] ); + + // Convert the "proper" angular coordinates into index format + index[0] = static_cast< TCoordRep >( ( ( radius - m_FirstSampleDistance ) + / m_RadiusSampleSize ) ); + index[1] = static_cast< TCoordRep >( ( lateral / m_LateralAngularSeparation ) + + ( maxLateral / 2.0 ) ); + + // Now, check to see if the index is within allowed bounds + const bool isInside = region.IsInside(index); + + return isInside; + } + + /** Get the index (discrete) from a physical point. + * Floating point index results are truncated to integers. + * Returns true if the resulting index is within the image, false otherwise + * \sa Transform */ + template< typename TCoordRep > + bool TransformPhysicalPointToIndex( + const Point< TCoordRep, VDimension > & point, + IndexType & index) const + { + const RegionType & region = this->GetLargestPossibleRegion(); + const double maxLateral = region.GetSize(1) - 1; + + // Convert Cartesian coordinates into angular coordinates + const TCoordRep lateral = std::atan(point[0] / point[1]); + const TCoordRep radius = std::sqrt(point[0] * point[0] + point[1] * point[1] ); + + // Convert the "proper" angular coordinates into index format + index[0] = static_cast< IndexValueType >( ( ( radius - m_FirstSampleDistance ) + / m_RadiusSampleSize ) ); + index[1] = static_cast< IndexValueType >( ( lateral / m_LateralAngularSeparation ) + + ( maxLateral / 2.0 ) ); + + // Now, check to see if the index is within allowed bounds + const bool isInside = region.IsInside(index); + + return isInside; + } + + /** Get a physical point (in the space which + * the origin and spacing information comes from) + * from a continuous index (in the index space) + * \sa Transform */ + template< typename TCoordRep > + void TransformContinuousIndexToPhysicalPoint( + const ContinuousIndex< TCoordRep, VDimension > & index, + Point< TCoordRep, VDimension > & point) const + { + const RegionType & region = this->GetLargestPossibleRegion(); + const double maxLateral = region.GetSize(1) - 1; + + // Convert the index into proper angular coordinates + const TCoordRep radius = ( index[0] * m_RadiusSampleSize ) + m_FirstSampleDistance; + const TCoordRep lateral = ( index[1] - ( maxLateral / 2.0 ) ) * m_LateralAngularSeparation; + + // Convert the angular coordinates into Cartesian coordinates + point[0] = static_cast< TCoordRep >( radius * std::sin(lateral) ); + point[1] = static_cast< TCoordRep >( radius * std::cos(lateral) ); + } + + /** Get a physical point (in the space which + * the origin and spacing information comes from) + * from a discrete index (in the index space) + * + * \sa Transform */ + template< typename TCoordRep > + void TransformIndexToPhysicalPoint( + const IndexType & index, + Point< TCoordRep, VDimension > & point) const + { + const RegionType & region = this->GetLargestPossibleRegion(); + const double maxLateral = region.GetSize(1) - 1; + + // Convert the index into proper angular coordinates + const TCoordRep radius = ( index[0] * m_RadiusSampleSize ) + m_FirstSampleDistance; + const TCoordRep lateral = ( index[1] - ( maxLateral / 2.0 ) ) * m_LateralAngularSeparation; + + // Convert the angular coordinates into Cartesian coordinates + point[0] = static_cast< TCoordRep >( radius * std::sin(lateral) ); + point[1] = static_cast< TCoordRep >( radius * std::cos(lateral) ); + } + + /** Set/Get the number of radians between each lateral unit. */ + itkSetMacro(LateralAngularSeparation, double); + itkGetConstMacro(LateralAngularSeparation, double); + + /** Set/Get the number of cartesian units between each unit along the R . */ + itkSetMacro(RadiusSampleSize, double); + itkGetConstMacro(RadiusSampleSize, double); + + /** Set the distance to add to the radius. */ + itkSetMacro(FirstSampleDistance, double); + itkGetConstMacro(FirstSampleDistance, double); + + template< typename TCoordRep > + void TransformLocalVectorToPhysicalVector( + FixedArray< TCoordRep, VDimension > & ) const + {} + + template< typename TCoordRep > + void TransformPhysicalVectorToLocalVector( + const FixedArray< TCoordRep, VDimension > & , + FixedArray< TCoordRep, VDimension > & ) const + {} + +protected: + CurvilinearArraySpecialCoordinatesImage() + { + m_RadiusSampleSize = 1; + m_LateralAngularSeparation = 1 * ( 2.0 * vnl_math::pi / 360.0 ); // 1 + // degree + m_FirstSampleDistance = 0; + } + + virtual ~CurvilinearArraySpecialCoordinatesImage() {} + virtual void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; + +private: + CurvilinearArraySpecialCoordinatesImage(const Self &); // purposely not implemented + void operator=(const Self &); // purposely not implemented + + double m_LateralAngularSeparation; // in radians + double m_RadiusSampleSize; + double m_FirstSampleDistance; +}; +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkCurvilinearArraySpecialCoordinatesImage.hxx" +#endif + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.hxx new file mode 100644 index 0000000000..b9a55c6b97 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkCurvilinearArraySpecialCoordinatesImage.hxx @@ -0,0 +1,102 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +/*========================================================================= + * + * Portions of this file are subject to the VTK Toolkit Version 3 copyright. + * + * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + * + * For complete copyright, license and disclaimer of warranty information + * please refer to the NOTICE file at the top of the ITK source tree. + * + *=========================================================================*/ +#ifndef itkCurvilinearArraySpecialCoordinatesImage_hxx +#define itkCurvilinearArraySpecialCoordinatesImage_hxx +#include "itkCurvilinearArraySpecialCoordinatesImage.h" + +namespace itk +{ + +template< typename TPixel, unsigned int VDimension > +void +CurvilinearArraySpecialCoordinatesImage< TPixel, VDimension > +::PrintSelf(std::ostream & os, Indent indent) const +{ + Superclass::PrintSelf(os, indent); + + os << indent + << "RadiusSampleSize = " << m_RadiusSampleSize + << std::endl; + os << indent + << "LateralAngularSeparation = " + << m_LateralAngularSeparation + << std::endl; + os << indent + << "FirstSampleDistance = " + << m_FirstSampleDistance + << std::endl; +} + + +template< typename TPixel, unsigned int VDimension > +void +CurvilinearArraySpecialCoordinatesImage< TPixel, VDimension > +::Graft(const DataObject *data) +{ + // call the superclass' implementation + Superclass::Graft(data); + + if ( data ) + { + // Attempt to cast data to a CurvilinearArraySpecialCoordinatesImage + const Self * const imgData = dynamic_cast< const Self * >( data ); + + if ( imgData ) + { + // Now copy anything remaining that is needed + this->SetPixelContainer( const_cast< PixelContainer * > + ( imgData->GetPixelContainer() ) ); + } + else + { + // pointer could not be cast back down + itkExceptionMacro( << "itk::Image::Graft() cannot cast " + << typeid( data ).name() << " to " + << typeid( const Self * ).name() ); + } + } +} + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h new file mode 100644 index 0000000000..11a3d2ee0d --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h @@ -0,0 +1,121 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DComplexConjugateToRealImageFilter_h +#define itkFFT1DComplexConjugateToRealImageFilter_h + +#include + +#include "itkImageToImageFilter.h" +#include "itkImageRegionSplitterDirection.h" + +namespace itk +{ +/** \class FFT1DComplexConjugateToRealImageFilter + * \brief Perform the Fast Fourier Transform, in the reverse direction, with + * real output, but only along one dimension. + * + * \ingroup FourierTransform + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=Image< typename NumericTraits< typename TInputImage::PixelType >::ValueType, TInputImage::ImageDimension > > +class FFT1DComplexConjugateToRealImageFilter: + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + typedef FFT1DComplexConjugateToRealImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension ); + + itkTypeMacro( FFT1DComplexConjugateToRealImageFilter, ImageToImageFilter ); + + /** Customized object creation methods that support configuration-based + * selection of FFT implementation. + * + * Default implementation is VnlFFT1D. + */ + static Pointer New(void); + + /** Get the direction in which the filter is to be applied. */ + itkGetMacro(Direction, unsigned int); + + /** Set the direction in which the filter is to be applied. */ + itkSetClampMacro(Direction, unsigned int, 0, ImageDimension - 1); + +protected: + FFT1DComplexConjugateToRealImageFilter(); + virtual ~FFT1DComplexConjugateToRealImageFilter() {} + + void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + virtual void BeforeThreadedGenerateData() ITK_OVERRIDE; + + /** Override to return a splitter that does not split along the direction we + * are performing the transform. */ + virtual const ImageRegionSplitterBase* GetImageRegionSplitter() const ITK_OVERRIDE; + + /** Direction in which the filter is to be applied + * this should be in the range [0,ImageDimension-1]. */ + unsigned int m_Direction; + +private: + FFT1DComplexConjugateToRealImageFilter( const Self& ); + void operator=( const Self& ); + + ImageRegionSplitterDirection::Pointer m_ImageRegionSplitter; +}; +} + +#ifndef ITK_MANUAL_INSTANTIATION +#ifndef itkVnlFFT1DComplexConjugateToRealImageFilter_h +#ifndef itkVnlFFT1DComplexConjugateToRealImageFilter_hxx +#ifndef itkFFTW1DComplexConjugateToRealImageFilter_h +#ifndef itkFFTW1DComplexConjugateToRealImageFilter_hxx +#include "itkFFT1DComplexConjugateToRealImageFilter.hxx" +#endif +#endif +#endif +#endif +#endif + +#endif // itkFFT1DComplexConjugateToRealImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.hxx new file mode 100644 index 0000000000..00c523fbd5 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.hxx @@ -0,0 +1,208 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DComplexConjugateToRealImageFilter_hxx +#define itkFFT1DComplexConjugateToRealImageFilter_hxx + +#include "itkFFT1DComplexConjugateToRealImageFilter.h" + +#include "itkVnlFFT1DComplexConjugateToRealImageFilter.h" + +#if defined(ITK_USE_FFTWD) || defined(ITK_USE_FFTWF) +#include "itkFFTW1DComplexConjugateToRealImageFilter.h" +#endif + +#include "itkMetaDataDictionary.h" +#include "itkMetaDataObject.h" + +namespace itk +{ + +template < typename TInputImage, typename TOutputImage > +typename FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage >::Pointer +FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +::New() +{ + Pointer smartPtr = ::itk::ObjectFactory< Self >::Create(); + +#ifdef ITK_USE_FFTWD + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( double ) ) + { + smartPtr = dynamic_cast< Self* >( + FFTW1DComplexConjugateToRealImageFilter< double, VDimension > + ::New().GetPointer() ); + } + } +#endif +#ifdef ITK_USE_FFTWF + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( float ) ) + { + smartPtr = dynamic_cast( + FFTW1DComplexConjugateToRealImageFilter< float, VDimension > + ::New().GetPointer() ); + } + } +#endif + + if( smartPtr.IsNull() ) + { + smartPtr = VnlFFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > + ::New().GetPointer(); + } + + return smartPtr; +} + + +template < typename TInputImage, typename TOutputImage > +FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +::FFT1DComplexConjugateToRealImageFilter(): + m_Direction( 0 ) +{ + this->m_ImageRegionSplitter = ImageRegionSplitterDirection::New(); +} + + +template +const ImageRegionSplitterBase* +FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +::GetImageRegionSplitter() const +{ + return this->m_ImageRegionSplitter.GetPointer(); +} + + +template +void +FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +::BeforeThreadedGenerateData() +{ + this->m_ImageRegionSplitter->SetDirection( this->GetDirection() ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + typename InputImageType::Pointer inputPtr = + const_cast (this->GetInput()); + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->m_Direction; + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + enlargedSize[this->m_Direction] = outputLargeSize[this->m_Direction]; + enlargedIndex[this->m_Direction] = outputLargeIndex[this->m_Direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + os << indent << "Direction: " << m_Direction << std::endl; +} + +} // end namespace itk + +#endif // itkFFT1DComplexConjugateToRealImageFilter_hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h new file mode 100644 index 0000000000..ed9b8b90f6 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h @@ -0,0 +1,142 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DComplexToComplexImageFilter_h +#define itkFFT1DComplexToComplexImageFilter_h + +#include + +#include "itkImage.h" +#include "itkImageToImageFilter.h" +#include "itkImageRegionSplitterDirection.h" + +namespace itk +{ +/** \class FFT1DComplexToComplexImageFilter + * \brief Perform the Fast Fourier Transform, complex input to complex output, + * but only along one dimension. + * + * The direction of the transform, 'Forward' or 'Inverse', can be set with + * SetTransformDirection() and GetTransformDirection(). + * + * The dimension along which to apply to filter can be specified with + * SetDirection() and GetDirection(). + * + * \ingroup FourierTransform + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=TInputImage > +class FFT1DComplexToComplexImageFilter: + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + typedef FFT1DComplexToComplexImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension ); + + itkTypeMacro( FFT1DComplexToComplexImageFilter, ImageToImageFilter ); + + /** Customized object creation methods that support configuration-based + * selection of FFT implementation. + * + * Default implementation is VnlFFT1D. + */ + static Pointer New(); + + /** Transform direction. */ + typedef enum { DIRECT = 1, INVERSE } TransformDirectionType; + + /** Set/Get the direction in which the transform will be applied. + * By selecting DIRECT, this filter will perform a direct (forward) Fourier + * Transform. + * By selecting INVERSE, this filter will perform an inverse Fourier + * Transform. */ + itkSetMacro( TransformDirection, TransformDirectionType ); + itkGetConstMacro( TransformDirection, TransformDirectionType ); + + /** Get the direction in which the filter is to be applied. */ + itkGetMacro(Direction, unsigned int); + + /** Set the direction in which the filter is to be applied. */ + itkSetClampMacro(Direction, unsigned int, 0, ImageDimension - 1); + +protected: + FFT1DComplexToComplexImageFilter(); + virtual ~FFT1DComplexToComplexImageFilter() {} + + void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + virtual void BeforeThreadedGenerateData() ITK_OVERRIDE; + + /** Override to return a splitter that does not split along the direction we + * are performing the transform. */ + virtual const ImageRegionSplitterBase* GetImageRegionSplitter() const ITK_OVERRIDE; + + /** Direction in which the filter is to be applied + * this should be in the range [0,ImageDimension-1]. */ + unsigned int m_Direction; + + /** Direction to apply the transform (forward/inverse). */ + TransformDirectionType m_TransformDirection; + +private: + FFT1DComplexToComplexImageFilter( const Self& ); + void operator=( const Self& ); + + ImageRegionSplitterDirection::Pointer m_ImageRegionSplitter; +}; +} + +#ifndef ITK_MANUAL_INSTANTIATION +#ifndef itkVnlFFT1DComplexToComplexImageFilter_h +#ifndef itkVnlFFT1DComplexToComplexImageFilter_hxx +#ifndef itkFFTW1DComplexToComplexImageFilter_h +#ifndef itkFFTW1DComplexToComplexImageFilter_hxx +#include "itkFFT1DComplexToComplexImageFilter.hxx" +#endif +#endif +#endif +#endif +#endif + +#endif // itkFFT1DComplexToComplexImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx new file mode 100644 index 0000000000..f287799e1c --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx @@ -0,0 +1,210 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DComplexToComplexImageFilter_hxx +#define itkFFT1DComplexToComplexImageFilter_hxx + +#include "itkFFT1DComplexToComplexImageFilter.h" + +#include "itkVnlFFT1DComplexToComplexImageFilter.h" + +#if defined(ITK_USE_FFTWD) || defined(ITK_USE_FFTWF) +#include "itkFFTW1DComplexToComplexImageFilter.h" +#endif + +#include "itkMetaDataDictionary.h" +#include "itkMetaDataObject.h" + +namespace itk +{ + +template < typename TInputImage, typename TOutputImage > +typename FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage >::Pointer +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::New() +{ + Pointer smartPtr = ::itk::ObjectFactory< Self >::Create(); + +#ifdef ITK_USE_FFTWD + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( double ) ) + { + smartPtr = dynamic_cast< Self* >( + FFTW1DComplexToComplexImageFilter< double, VDimension > + ::New().GetPointer() ); + } + } +#endif +#ifdef ITK_USE_FFTWF + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( float ) ) + { + smartPtr = dynamic_cast( + FFTW1DComplexToComplexImageFilter< float, VDimension > + ::New().GetPointer() ); + } + } +#endif + + if( smartPtr.IsNull() ) + { + smartPtr = VnlFFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > + ::New().GetPointer(); + } + + return smartPtr; +} + + +template< typename TInputImage, typename TOutputImage > +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::FFT1DComplexToComplexImageFilter(): + m_Direction(0), m_TransformDirection( DIRECT ) +{ + this->m_ImageRegionSplitter = ImageRegionSplitterDirection::New(); +} + + +template +const ImageRegionSplitterBase* +FFT1DComplexToComplexImageFilter < TInputImage, TOutputImage > +::GetImageRegionSplitter(void) const +{ + return this->m_ImageRegionSplitter.GetPointer(); +} + + +template +void +FFT1DComplexToComplexImageFilter < TInputImage, TOutputImage > +::BeforeThreadedGenerateData() +{ + this->m_ImageRegionSplitter->SetDirection( this->GetDirection() ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + typename InputImageType::Pointer inputPtr = + const_cast (this->GetInput()); + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->m_Direction; + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + enlargedSize[this->m_Direction] = outputLargeSize[this->m_Direction]; + enlargedIndex[this->m_Direction] = outputLargeIndex[this->m_Direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + os << indent << "Direction: " << m_Direction << std::endl; + os << indent << "TransformDirection: " << m_TransformDirection << std::endl; +} + + +} // end namespace itk + +#endif // itkFFT1DComplexToComplexImageFilter_hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h new file mode 100644 index 0000000000..9ff85ad00c --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h @@ -0,0 +1,123 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DRealToComplexConjugateImageFilter_h +#define itkFFT1DRealToComplexConjugateImageFilter_h + +#include + +#include "itkImageToImageFilter.h" +#include "itkImageRegionSplitterDirection.h" + +namespace itk +{ +/** \class FFT1DRealToComplexConjugateImageFilter + * \brief Perform the Fast Fourier Transform, in the forward direction, with + * real inputs, but only along one dimension. + * + * \ingroup FourierTransform + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=Image< std::complex< typename TInputImage::PixelType >, TInputImage::ImageDimension > > +class FFT1DRealToComplexConjugateImageFilter: + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + + /** Standard class typedefs. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + typedef FFT1DRealToComplexConjugateImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkStaticConstMacro( ImageDimension, unsigned int, InputImageType::ImageDimension ); + + itkTypeMacro( FFT1DRealToComplexConjugateImageFilter, ImageToImageFilter ); + + /** Customized object creation methods that support configuration-based + * selection of FFT implementation. + * + * Default implementation is VnlFFT1D. + */ + static Pointer New(); + + /** Get the direction in which the filter is to be applied. */ + itkGetMacro(Direction, unsigned int); + + /** Set the direction in which the filter is to be applied. */ + itkSetClampMacro(Direction, unsigned int, 0, ImageDimension - 1); + +protected: + FFT1DRealToComplexConjugateImageFilter(); + virtual ~FFT1DRealToComplexConjugateImageFilter() {} + + void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + virtual void BeforeThreadedGenerateData() ITK_OVERRIDE; + + /** Override to return a splitter that does not split along the direction we + * are performing the transform. */ + virtual const ImageRegionSplitterBase* GetImageRegionSplitter() const ITK_OVERRIDE; + +private: + FFT1DRealToComplexConjugateImageFilter( const Self& ); + void operator=( const Self& ); + + ImageRegionSplitterDirection::Pointer m_ImageRegionSplitter; + + /** Direction in which the filter is to be applied + * this should be in the range [0,ImageDimension-1]. */ + unsigned int m_Direction; + +}; +} + +#ifndef ITK_MANUAL_INSTANTIATION +#ifndef itkVnlFFT1DRealToComplexConjugateImageFilter_h +#ifndef itkVnlFFT1DRealToComplexConjugateImageFilter_hxx +#ifndef itkFFTW1DRealToComplexConjugateImageFilter_h +#ifndef itkFFTW1DRealToComplexConjugateImageFilter_hxx +#include "itkFFT1DRealToComplexConjugateImageFilter.hxx" +#endif +#endif +#endif +#endif +#endif + +#endif // itkFFT1DRealToComplexConjugateImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx new file mode 100644 index 0000000000..16c10f5477 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx @@ -0,0 +1,207 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DRealToComplexConjugateImageFilter_hxx +#define itkFFT1DRealToComplexConjugateImageFilter_hxx + +#include "itkFFT1DRealToComplexConjugateImageFilter.h" + +#include "itkVnlFFT1DRealToComplexConjugateImageFilter.h" + +#if defined(ITK_USE_FFTWD) || defined(ITK_USE_FFTWF) +#include "itkFFTW1DRealToComplexConjugateImageFilter.h" +#endif + +#include "itkMetaDataObject.h" + +namespace itk +{ + +template < typename TInputImage, typename TOutputImage > +typename FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage >::Pointer +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::New() +{ + Pointer smartPtr = ::itk::ObjectFactory< Self >::Create(); + +#ifdef ITK_USE_FFTWD + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( double ) ) + { + smartPtr = dynamic_cast< Self* >( + FFTW1DRealToComplexConjugateImageFilter< double, VDimension > + ::New().GetPointer() ); + } + } +#endif +#ifdef ITK_USE_FFTWF + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( float ) ) + { + smartPtr = dynamic_cast( + FFTW1DRealToComplexConjugateImageFilter< float, VDimension > + ::New().GetPointer() ); + } + } +#endif + + if( smartPtr.IsNull() ) + { + smartPtr = VnlFFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > + ::New().GetPointer(); + } + + return smartPtr; +} + + +template< typename TInputImage, typename TOutputImage > +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::FFT1DRealToComplexConjugateImageFilter(): + m_Direction( 0 ) +{ + this->m_ImageRegionSplitter = ImageRegionSplitterDirection::New(); +} + + +template< typename TInputImage, typename TOutputImage > +const ImageRegionSplitterBase* +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::GetImageRegionSplitter() const +{ + return this->m_ImageRegionSplitter.GetPointer(); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::BeforeThreadedGenerateData() +{ + this->m_ImageRegionSplitter->SetDirection( this->GetDirection() ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + typename InputImageType::Pointer inputPtr = + const_cast (this->GetInput()); + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->m_Direction; + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DRealToComplexConjugateImageFilter < TInputImage, TOutputImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast< OutputImageType * >( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + enlargedSize[this->m_Direction] = outputLargeSize[this->m_Direction]; + enlargedIndex[this->m_Direction] = outputLargeIndex[this->m_Direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DRealToComplexConjugateImageFilter < TInputImage, TOutputImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + os << indent << "Direction: " << m_Direction << std::endl; +} + +} // end namespace itk + +#endif // itkFFT1DRealToComplexConjugateImageFilter_hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.h new file mode 100644 index 0000000000..5a15e24723 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.h @@ -0,0 +1,143 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkRegionFromReferenceImageFilter_h +#define itkRegionFromReferenceImageFilter_h + +#include "itkExtractImageFilter.h" + +namespace itk +{ + +/** \class RegionFromReferenceImageFilter + * \brief Decrease the image size by cropping the image by an itk::Size at + * both the upper and lower bounds of the largest possible region. + * + * RegionFromReferenceImageFilter changes the image boundary of an image by removing + * pixels outside the target region. The target region is not specified in + * advance, but calculated in BeforeThreadedGenerateData(). + * + * This filter uses ExtractImageFilter to perform the cropping. + * + * \ingroup GeometricTransforms + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=TInputImage > +class RegionFromReferenceImageFilter: + public ExtractImageFilter +{ +public: + /** Standard class typedefs. */ + typedef RegionFromReferenceImageFilter Self; + typedef ExtractImageFilter Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(RegionFromReferenceImageFilter, ExtractImageFilter); + + /** Typedef to describe the output and input image region types. */ + typedef typename Superclass::OutputImageRegionType OutputImageRegionType; + typedef typename Superclass::InputImageRegionType InputImageRegionType; + + /** Typedef to describe the type of pixel. */ + typedef typename Superclass::OutputImagePixelType OutputImagePixelType; + typedef typename Superclass::InputImagePixelType InputImagePixelType; + + /** Typedef to describe the output and input image index and size types. */ + typedef typename Superclass::OutputImageIndexType OutputImageIndexType; + typedef typename Superclass::InputImageIndexType InputImageIndexType; + typedef typename Superclass::OutputImageSizeType OutputImageSizeType; + typedef typename Superclass::InputImageSizeType InputImageSizeType; + typedef InputImageSizeType SizeType; + + /** ImageDimension constants */ + itkStaticConstMacro(InputImageDimension, unsigned int, + Superclass::InputImageDimension); + itkStaticConstMacro(OutputImageDimension, unsigned int, + Superclass::OutputImageDimension); + itkStaticConstMacro(ImageDimension, unsigned int, + Superclass::OutputImageDimension); + + typedef ImageBase< itkGetStaticConstMacro( ImageDimension ) > ReferenceImageType; + + /** Copy the output information from another Image. */ + void SetReferenceImage ( const ReferenceImageType *image ); + + const ReferenceImageType * GetReferenceImage() const; + + /** Set the input image */ + void SetInput1(const TInputImage *input) + { + this->SetInput( input ); + } + + /** Set the reference image */ + void SetInput2(const ReferenceImageType *input) + { + this->SetReferenceImage( input ); + } + + +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(InputConvertibleToOutputCheck, + (Concept::Convertible)); + itkConceptMacro(SameDimensionCheck, + (Concept::SameDimension)); + /** End concept checking */ +#endif + +protected: + RegionFromReferenceImageFilter() + { + this->SetNumberOfRequiredInputs(2); + } + ~RegionFromReferenceImageFilter() {} + + virtual void GenerateOutputInformation() ITK_OVERRIDE; + +private: + RegionFromReferenceImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkRegionFromReferenceImageFilter.hxx" +#endif + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx new file mode 100644 index 0000000000..463ef984eb --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx @@ -0,0 +1,87 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkRegionFromReferenceImageFilter_hxx +#define itkRegionFromReferenceImageFilter_hxx + +#include "itkRegionFromReferenceImageFilter.h" + +namespace itk +{ + +template +void +RegionFromReferenceImageFilter +::GenerateOutputInformation() +{ + if( !this->GetInput() || !this->GetReferenceImage() ) + { + return; + } + + // Superclass::Superclass::GenerateOutputInformation(); + this->SetExtractionRegion( this->GetReferenceImage()->GetLargestPossibleRegion() ); + Superclass::GenerateOutputInformation(); +} + + +template +void +RegionFromReferenceImageFilter +::SetReferenceImage ( const ReferenceImageType *image ) +{ + itkDebugMacro("setting input ReferenceImage to " << image); + if( image != static_cast(this->GetInput( 1 )) ) + { + this->ProcessObject::SetNthInput(1, const_cast< ReferenceImageType *>( image ) ); + this->Modified(); + } +} + + +template +const typename RegionFromReferenceImageFilter::ReferenceImageType * +RegionFromReferenceImageFilter +::GetReferenceImage() const +{ + Self * surrogate = const_cast< Self * >( this ); + + const DataObject * input = surrogate->ProcessObject::GetInput(1); + + const ReferenceImageType * referenceImage = static_cast( input ); + + return referenceImage; +} + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.h new file mode 100644 index 0000000000..5adb49b396 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.h @@ -0,0 +1,139 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkSpectra1DImageFilter_h +#define itkSpectra1DImageFilter_h + +#include "itkImageToImageFilter.h" +#include "itkDefaultConvertPixelTraits.h" +#include "itkImageRegionConstIterator.h" + +#include "vnl/algo/vnl_fft_base.h" +#include "vnl/algo/vnl_fft_1d.h" + +#include +#include + +#include "itkSpectra1DSupportWindowImageFilter.h" + +namespace itk +{ + +/** \class Spectra1DImageFilter + * \brief Generate an image of local spectra. + * + * This image takes in the input image and image that has indexes of the local + * lines used to compute the local spectra. + * + * \ingroup Ultrasound + * + * \sa Spectra1DSupportWindowImageFilter + */ +template< typename TInputImage, typename TSupportWindowImage, typename TOutputImage > +class Spectra1DImageFilter: + public ImageToImageFilter< TInputImage, + TOutputImage > +{ +public: + itkStaticConstMacro( ImageDimension, unsigned int, TInputImage::ImageDimension ); + + typedef TInputImage InputImageType; + typedef TSupportWindowImage SupportWindowImageType; + typedef TOutputImage OutputImageType; + + typedef typename DefaultConvertPixelTraits< typename OutputImageType::PixelType >::ComponentType + ScalarType; + + /** Standard class typedefs. */ + typedef Spectra1DImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkTypeMacro( Spectra1DImageFilter, ImageToImageFilter ); + itkNewMacro( Self ); + + /** Set/get the input image containning the support window for local spectra + * computation. */ + itkSetInputMacro( SupportWindowImage, SupportWindowImageType ); + itkGetInputMacro( SupportWindowImage, SupportWindowImageType ); + +protected: + Spectra1DImageFilter(); + virtual ~Spectra1DImageFilter() {}; + + typedef typename OutputImageType::RegionType OutputImageRegionType; + + virtual void GenerateOutputInformation() ITK_OVERRIDE; + virtual void BeforeThreadedGenerateData() ITK_OVERRIDE; + virtual void ThreadedGenerateData( const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId ) ITK_OVERRIDE; + +private: + Spectra1DImageFilter( const Self & ); // purposely not implemented + void operator=( const Self & ); // purposely not implemented + + typedef vcl_complex< ScalarType > ComplexType; + typedef vnl_vector< ComplexType > ComplexVectorType; + typedef vnl_vector< ScalarType > SpectraVectorType; + typedef typename InputImageType::IndexType IndexType; + typedef std::pair< IndexType, SpectraVectorType > SpectraLineType; + typedef std::deque< SpectraLineType > SpectraLinesContainerType; + typedef typename SupportWindowImageType::PixelType SupportWindowType; + typedef ImageRegionConstIterator< InputImageType > InputImageIteratorType; + typedef vnl_fft_1d< ScalarType > FFT1DType; + + typedef Spectra1DSupportWindowImageFilter< OutputImageType > Spectra1DSupportWindowFilterType; + typedef typename Spectra1DSupportWindowFilterType::FFT1DSizeType FFT1DSizeType; + + typedef std::map< FFT1DSizeType, SpectraVectorType > LineWindowMapType; + + struct PerThreadData + { + ComplexVectorType ComplexVector; + SpectraVectorType SpectraVector; + typename InputImageType::SizeType LineImageRegionSize; + LineWindowMapType LineWindowMap; + }; + typedef std::vector< PerThreadData > PerThreadDataContainerType; + PerThreadDataContainerType m_PerThreadDataContainer; + + SpectraLineType ComputeSpectra( const IndexType & lineIndex, ThreadIdType threadId ); + void AddLineWindow( FFT1DSizeType length, LineWindowMapType & lineWindowMap ); +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkSpectra1DImageFilter.hxx" +#endif + +#endif // itkSpectra1DImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.hxx new file mode 100644 index 0000000000..e2d3e87053 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DImageFilter.hxx @@ -0,0 +1,277 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkSpectra1DImageFilter_hxx +#define itkSpectra1DImageFilter_hxx + +#include "itkSpectra1DImageFilter.h" + +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" +#include "itkImageRegionConstIterator.h" +#include "itkMetaDataObject.h" + +#include "itkSpectra1DSupportWindowImageFilter.h" + +namespace itk +{ + +template< typename TInputImage, typename TSupportWindowImage, typename TOutputImage > +Spectra1DImageFilter< TInputImage, TSupportWindowImage, TOutputImage > +::Spectra1DImageFilter() +{ + this->AddRequiredInputName( "SupportWindowImage" ); +} + + +template< typename TInputImage, typename TSupportWindowImage, typename TOutputImage > +void +Spectra1DImageFilter< TInputImage, TSupportWindowImage, TOutputImage > +::GenerateOutputInformation() +{ + Superclass::GenerateOutputInformation(); + + const SupportWindowImageType * supportWindowImage = this->GetSupportWindowImage(); + const MetaDataDictionary & dict = supportWindowImage->GetMetaDataDictionary(); + FFT1DSizeType fft1DSize = 32; + ExposeMetaData< FFT1DSizeType >( dict, "FFT1DSize", fft1DSize ); + const FFT1DSizeType spectraComponents = fft1DSize / 2 - 1; + + OutputImageType * output = this->GetOutput(); + output->SetVectorLength( spectraComponents ); +} + + +template< typename TInputImage, typename TSupportWindowImage, typename TOutputImage > +void +Spectra1DImageFilter< TInputImage, TSupportWindowImage, TOutputImage > +::BeforeThreadedGenerateData() +{ + const SupportWindowImageType * supportWindowImage = this->GetSupportWindowImage(); + const MetaDataDictionary & dict = supportWindowImage->GetMetaDataDictionary(); + FFT1DSizeType fft1DSize = 32; + ExposeMetaData< FFT1DSizeType >( dict, "FFT1DSize", fft1DSize ); + const FFT1DSizeType spectraComponents = fft1DSize / 2 - 1; + + const ThreadIdType numberOfThreads = this->GetNumberOfThreads(); + this->m_PerThreadDataContainer.resize( numberOfThreads ); + for( ThreadIdType threadId = 0; threadId < numberOfThreads; ++threadId ) + { + PerThreadData & perThreadData = this->m_PerThreadDataContainer[threadId]; + perThreadData.ComplexVector.set_size( fft1DSize ); + perThreadData.SpectraVector.set_size( spectraComponents ); + perThreadData.LineImageRegionSize.Fill( 1 ); + perThreadData.LineImageRegionSize[0] = fft1DSize; + } +} + + +template< typename TInputImage, typename TSupportWindowImage, typename TOutputImage > +void +Spectra1DImageFilter< TInputImage, TSupportWindowImage, TOutputImage > +::AddLineWindow( FFT1DSizeType length, LineWindowMapType & lineWindowMap ) +{ + if( lineWindowMap.count( length ) == 1 ) + { + return; + } + // Currently using a Hamming Window + SpectraVectorType window( length ); + ScalarType sum = NumericTraits< ScalarType >::ZeroValue(); + const ScalarType twopi = 2 * vnl_math::pi; + for( FFT1DSizeType sample = 0; sample < length; ++sample ) + { + window[sample] = 0.54 + 0.46 * std::cos( (twopi * sample) / (length - 1) ); + sum += window[sample]; + } + for( FFT1DSizeType sample = 0; sample < length; ++sample ) + { + window[sample] /= sum; + } + lineWindowMap[length] = window; +} + + +template< typename TInputImage, typename TSupportWindowImage, typename TOutputImage > +typename Spectra1DImageFilter< TInputImage, TSupportWindowImage, TOutputImage >::SpectraLineType +Spectra1DImageFilter< TInputImage, TSupportWindowImage, TOutputImage > +::ComputeSpectra( const IndexType & lineIndex, ThreadIdType threadId ) +{ + const InputImageType * input = this->GetInput(); + PerThreadData & perThreadData = this->m_PerThreadDataContainer[threadId]; + + const FFT1DSizeType fft1DSize = static_cast< FFT1DSizeType >( perThreadData.ComplexVector.size() ); + + const typename InputImageType::RegionType lineRegion( lineIndex, perThreadData.LineImageRegionSize ); + InputImageIteratorType inputIt( input, lineRegion ); + inputIt.GoToBegin(); + perThreadData.ComplexVector.fill( 0 ); + typename ComplexVectorType::iterator complexVectorIt = perThreadData.ComplexVector.begin(); + typename SpectraVectorType::const_iterator windowIt = perThreadData.LineWindowMap[fft1DSize].begin(); + while( !inputIt.IsAtEnd() ) + { + *complexVectorIt = inputIt.Value() * *windowIt; + ++inputIt; + ++complexVectorIt; + ++windowIt; + } + FFT1DType fft1D( fft1DSize ); + fft1D.bwd_transform( perThreadData.ComplexVector ); + typename ComplexVectorType::const_iterator complexVectorConstIt = perThreadData.ComplexVector.begin(); + typename SpectraVectorType::iterator spectraVectorIt = perThreadData.SpectraVector.begin(); + // drop DC component + ++complexVectorConstIt; + const size_t highFreq = perThreadData.SpectraVector.size(); + for( size_t freq = 0; freq < highFreq; ++freq ) + { + spectraVectorIt[freq] = std::real(*complexVectorConstIt * std::conj(*complexVectorConstIt)); + ++complexVectorConstIt; + } + return std::make_pair( lineIndex, perThreadData.SpectraVector ); +} + + +template< typename TInputImage, typename TSupportWindowImage, typename TOutputImage > +void +Spectra1DImageFilter< TInputImage, TSupportWindowImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId ) +{ + OutputImageType * output = this->GetOutput(); + const SupportWindowImageType * supportWindowImage = this->GetSupportWindowImage(); + + typedef ImageLinearIteratorWithIndex< OutputImageType > OutputIteratorType; + OutputIteratorType outputIt( output, outputRegionForThread ); + outputIt.SetDirection( 1 ); + + const MetaDataDictionary & dict = supportWindowImage->GetMetaDataDictionary(); + FFT1DSizeType fft1DSize = 32; + ExposeMetaData< FFT1DSizeType >( dict, "FFT1DSize", fft1DSize ); + PerThreadData & perThreadData = this->m_PerThreadDataContainer[threadId]; + this->AddLineWindow( fft1DSize, perThreadData.LineWindowMap ); + + ComplexVectorType complexVector( fft1DSize ); + SpectraVectorType spectraVector( fft1DSize ); + typename InputImageType::SizeType lineImageRegionSize; + lineImageRegionSize.Fill( 1 ); + lineImageRegionSize[0] = fft1DSize; + vnl_fft_1d< ScalarType > fft1D( fft1DSize ); + SpectraLinesContainerType spectraLines; + + typedef ImageLinearConstIteratorWithIndex< SupportWindowImageType > SupportWindowIteratorType; + SupportWindowIteratorType supportWindowIt( supportWindowImage, outputRegionForThread ); + supportWindowIt.SetDirection( 1 ); + + for( outputIt.GoToBegin(), supportWindowIt.GoToBegin(); + !outputIt.IsAtEnd(); + outputIt.NextLine(), supportWindowIt.NextLine() ) + { + spectraLines.clear(); + while( ! outputIt.IsAtEndOfLine() ) + { + // Compute the per line spectra. + const SupportWindowType & supportWindow = supportWindowIt.Value(); + if( spectraLines.size() == 0 ) // first window in this lateral direction + { + const typename SupportWindowType::const_iterator windowLineEnd = supportWindow.end(); + for( typename SupportWindowType::const_iterator windowLine = supportWindow.begin(); + windowLine != windowLineEnd; + ++windowLine ) + { + const IndexType & lineIndex = *windowLine; + const SpectraLineType & spectraLine = this->ComputeSpectra( lineIndex, threadId ); + spectraLines.push_back( spectraLine ); + } + } + else // subsequent window along a line + { + const IndexValueType desiredFirstLine = supportWindow[0][1]; + while( spectraLines[0].first[1] < desiredFirstLine ) + { + spectraLines.pop_front(); + } + const typename SupportWindowType::const_iterator windowLineEnd = supportWindow.end(); + typename SpectraLinesContainerType::iterator spectraLinesIt = spectraLines.begin(); + const typename SpectraLinesContainerType::iterator spectraLinesEnd = spectraLines.end(); + for( typename SupportWindowType::const_iterator windowLine = supportWindow.begin(); + windowLine != windowLineEnd; + ++windowLine ) + { + const IndexType & lineIndex = *windowLine; + if( spectraLinesIt == spectraLinesEnd ) // past the end of the previously processed lines + { + const SpectraLineType & spectraLine = this->ComputeSpectra( lineIndex, threadId ); + spectraLines.push_back( spectraLine ); + } + else if( lineIndex[1] == (spectraLinesIt->first)[1] ) // one of the same lines that was previously computed + { + if( lineIndex[0] != (spectraLinesIt->first)[0] ) + { + const SpectraLineType & spectraLine = this->ComputeSpectra( lineIndex, threadId ); + *spectraLinesIt = spectraLine; + } + ++spectraLinesIt; + } + else + { + itkExceptionMacro( "Unexpected line" ); + } + } + } + + const size_t spectraLinesCount = spectraLines.size(); + this->AddLineWindow( spectraLinesCount, perThreadData.LineWindowMap ); + typename OutputImageType::PixelType outputPixel; + outputPixel.SetSize( fft1DSize ); + outputPixel.Fill( NumericTraits< ScalarType >::ZeroValue() ); + typename SpectraVectorType::const_iterator windowIt = perThreadData.LineWindowMap[spectraLinesCount].begin(); + for( size_t line = 0; line < spectraLinesCount; ++line ) + { + typename SpectraVectorType::const_iterator spectraIt = spectraLines[line].second.begin(); + for( FFT1DSizeType sample = 0; sample < fft1DSize; ++sample ) + { + outputPixel[sample] += *windowIt * *spectraIt; + ++spectraIt; + } + ++windowIt; + } + outputIt.Set( outputPixel ); + + ++outputIt; + ++supportWindowIt; + } + } +} + + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.h new file mode 100644 index 0000000000..e1b2b7b9fc --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.h @@ -0,0 +1,117 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkSpectra1DSupportWindowImageFilter_h +#define itkSpectra1DSupportWindowImageFilter_h + +#include + +#include "itkImageToImageFilter.h" + +namespace itk +{ + +/** \class Spectra1DSupportWindowImageFilter + * \brief Generate an image of local spectra computation support windows. + * + * The information from the input image is used to determine the output image + * information. The pixel value of the input image is used to specify the + * nominal number of lines on either side of the central FFT line to add to + * the window. The nominal size of the 1D FFT is specified with SetFFTSize() + * + * The overlap between windows is specified with SetStep(). By default, the + * Step is only one sample. + * + * \ingroup Ultrasound + */ +template< typename TInputImage > +class Spectra1DSupportWindowImageFilter: + public ImageToImageFilter< TInputImage, + Image< std::deque< typename TInputImage::IndexType >, TInputImage::ImageDimension > > +{ +public: + itkStaticConstMacro( ImageDimension, unsigned int, TInputImage::ImageDimension ); + + typedef TInputImage InputImageType; + typedef typename InputImageType::IndexType IndexType; + + typedef std::deque< IndexType > OutputPixelType; + typedef Image< OutputPixelType, ImageDimension > OutputImageType; + + typedef unsigned int FFT1DSizeType; + + /** Standard class typedefs. */ + typedef Spectra1DSupportWindowImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkTypeMacro( Spectra1DSupportWindowImageFilter, ImageToImageFilter ); + itkNewMacro( Self ); + + /** Set/Get the nominal size of the FFT. This will be truncated at the + * boundary of image. */ + itkGetConstMacro( FFT1DSize, FFT1DSizeType ); + itkSetMacro( FFT1DSize, FFT1DSizeType ); + + /** Set/Get the number of samples between windows -- defaults to 1. */ + itkGetConstMacro( Step, SizeValueType ); + itkSetMacro( Step, SizeValueType ); + +protected: + Spectra1DSupportWindowImageFilter(); + virtual ~Spectra1DSupportWindowImageFilter() {}; + + typedef typename OutputImageType::RegionType OutputImageRegionType; + + virtual void GenerateOutputInformation() ITK_OVERRIDE; + + virtual void ThreadedGenerateData( const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId ) ITK_OVERRIDE; + virtual void AfterThreadedGenerateData() ITK_OVERRIDE; + + virtual void PrintSelf( std::ostream & os, Indent indent ) const ITK_OVERRIDE; + +private: + Spectra1DSupportWindowImageFilter( const Self & ); // purposely not implemented + void operator=( const Self & ); // purposely not implemented + + FFT1DSizeType m_FFT1DSize; + SizeValueType m_Step; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkSpectra1DSupportWindowImageFilter.hxx" +#endif + +#endif // itkSpectra1DSupportWindowImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.hxx new file mode 100644 index 0000000000..af009fd784 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowImageFilter.hxx @@ -0,0 +1,172 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkSpectra1DSupportWindowImageFilter_hxx +#define itkSpectra1DSupportWindowImageFilter_hxx + +#include "itkSpectra1DSupportWindowImageFilter.h" +#include "itkImageRegionIterator.h" +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkMetaDataObject.h" +#include "itkImageScanlineIterator.h" + +namespace itk +{ + +template< typename TInputImage > +Spectra1DSupportWindowImageFilter< TInputImage > +::Spectra1DSupportWindowImageFilter(): + m_FFT1DSize( 32 ), + m_Step( 1 ) +{ +} + + +template< typename TInputImage > +void +Spectra1DSupportWindowImageFilter< TInputImage > +::GenerateOutputInformation() +{ + Superclass::GenerateOutputInformation(); + + OutputImageType * output = this->GetOutput(); + const InputImageType * input = this->GetInput(); + + OutputImageRegionType outputRegion = input->GetLargestPossibleRegion(); + typename OutputImageType::SizeType outputSize = outputRegion.GetSize(); + outputSize[0] /= this->GetStep(); + outputRegion.SetSize( outputSize ); + output->SetLargestPossibleRegion( outputRegion ); + + typename OutputImageType::SpacingType outputSpacing = input->GetSpacing(); + outputSpacing[0] *= this->GetStep(); + output->SetSpacing( outputSpacing ); +} + + +template< typename TInputImage > +void +Spectra1DSupportWindowImageFilter< TInputImage > +::ThreadedGenerateData( const OutputImageRegionType & outputRegionForThread, ThreadIdType itkNotUsed( threadId ) ) +{ + OutputImageType * output = this->GetOutput(); + const InputImageType * input = this->GetInput(); + + const OutputImageRegionType outputLargestRegion = output->GetLargestPossibleRegion(); + typedef typename OutputImageType::IndexType IndexType; + const IndexType largestIndexStart = outputLargestRegion.GetIndex(); + IndexType largestIndexStop = largestIndexStart + outputLargestRegion.GetSize(); + for( unsigned int dim = 0; dim < ImageDimension; ++dim ) + { + largestIndexStop[dim] -= 1; + } + + typedef ImageLinearConstIteratorWithIndex< InputImageType > InputIteratorType; + InputIteratorType inputIt( input, outputRegionForThread ); + typedef ImageScanlineIterator< OutputImageType > OutputIteratorType; + OutputIteratorType outputIt( output, outputRegionForThread ); + const FFT1DSizeType fftSize = this->GetFFT1DSize(); + const SizeValueType sampleStep = this->GetStep(); + if( outputLargestRegion.GetSize()[0] < fftSize ) + { + itkExceptionMacro( "Insufficient size in the FFT direction." ); + } + for( inputIt.GoToBegin(), outputIt.GoToBegin(); !outputIt.IsAtEnd(); ) + { + while( !outputIt.IsAtEndOfLine() ) + { + OutputPixelType & supportWindow = outputIt.Value(); + supportWindow.clear(); + + const IndexType inputIndex = inputIt.GetIndex(); + + IndexType lineIndex; + lineIndex[0] = inputIndex[0] - fftSize / 2; + if( lineIndex[0] < largestIndexStart[0] ) + { + lineIndex[0] = largestIndexStart[0]; + } + + if( lineIndex[0] + fftSize > largestIndexStop[0] ) + { + lineIndex[0] = largestIndexStop[0] - fftSize; + } + + const IndexValueType sideLines = static_cast< IndexValueType >( inputIt.Get() ); + for( IndexValueType line = inputIndex[1] - sideLines; + line < inputIndex[1] + sideLines; + ++line ) + { + if( line < largestIndexStart[1] || line > largestIndexStop[1] ) + { + continue; + } + lineIndex[1] = line; + supportWindow.push_back( lineIndex ); + } + for( SizeValueType ii = 0; ii < sampleStep; ++ii ) + { + ++inputIt; + } + ++outputIt; + } + inputIt.NextLine(); + outputIt.NextLine(); + } +} + + +template< typename TInputImage > +void +Spectra1DSupportWindowImageFilter< TInputImage > +::AfterThreadedGenerateData() +{ + OutputImageType * output = this->GetOutput(); + MetaDataDictionary & dict = output->GetMetaDataDictionary(); + EncapsulateMetaData< FFT1DSizeType >( dict, "FFT1DSize", this->GetFFT1DSize() ); +} + + +template< typename TInputImage > +void +Spectra1DSupportWindowImageFilter< TInputImage > +::PrintSelf( std::ostream & os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + os << indent << "FFT1DSize: " << this->GetFFT1DSize() << std::endl; + os << indent << "Step: " << this->GetStep() << std::endl; +} + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.h new file mode 100644 index 0000000000..bb12313671 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.h @@ -0,0 +1,105 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkSpectra1DSupportWindowToMaskImageFilter_h +#define itkSpectra1DSupportWindowToMaskImageFilter_h + +#include "itkImageToImageFilter.h" + +namespace itk +{ + +/** \class Spectra1DSupportWindowToMaskImageFilter + * \brief Generate a mask image from the support window at a given index. + * + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage > +class Spectra1DSupportWindowToMaskImageFilter: + public ImageToImageFilter< TInputImage, + TOutputImage > +{ +public: + itkStaticConstMacro( ImageDimension, unsigned int, TInputImage::ImageDimension ); + + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + + typedef typename InputImageType::IndexType IndexType; + typedef typename OutputImageType::PixelType OutputPixelType; + + /** Standard class typedefs. */ + typedef Spectra1DSupportWindowToMaskImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkTypeMacro( Spectra1DSupportWindowToMaskImageFilter, ImageToImageFilter ); + itkNewMacro( Self ); + + /** Set/Get the index of the support window to create the mask for. */ + itkGetConstReferenceMacro( MaskIndex, IndexType ); + itkSetMacro( MaskIndex, IndexType ); + + /** Set/Get the value to consider as "background". Defaults to zero. */ + itkSetMacro( BackgroundValue, OutputPixelType ); + itkGetConstMacro( BackgroundValue, OutputPixelType ); + + /** Set/Get the value in the image to consider as "foreground". Defaults to + * maximum value of the OutputPixelType. */ + itkSetMacro( ForegroundValue, OutputPixelType ); + itkGetConstMacro( ForegroundValue, OutputPixelType ); + + +protected: + Spectra1DSupportWindowToMaskImageFilter(); + virtual ~Spectra1DSupportWindowToMaskImageFilter() {}; + + virtual void GenerateData() ITK_OVERRIDE; + +private: + Spectra1DSupportWindowToMaskImageFilter( const Self & ); // purposely not implemented + void operator=( const Self & ); // purposely not implemented + + IndexType m_MaskIndex; + + OutputPixelType m_BackgroundValue; + OutputPixelType m_ForegroundValue; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkSpectra1DSupportWindowToMaskImageFilter.hxx" +#endif + +#endif // itkSpectra1DSupportWindowToMaskImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.hxx new file mode 100644 index 0000000000..61c4efdaea --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkSpectra1DSupportWindowToMaskImageFilter.hxx @@ -0,0 +1,90 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkSpectra1DSupportWindowToMaskImageFilter_hxx +#define itkSpectra1DSupportWindowToMaskImageFilter_hxx + +#include "itkSpectra1DSupportWindowToMaskImageFilter.h" +#include "itkSpectra1DSupportWindowImageFilter.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIteratorWithIndex.h" +#include "itkMetaDataObject.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +Spectra1DSupportWindowToMaskImageFilter< TInputImage, TOutputImage > +::Spectra1DSupportWindowToMaskImageFilter(): + m_BackgroundValue( NumericTraits< OutputPixelType >::ZeroValue() ), + m_ForegroundValue( NumericTraits< OutputPixelType >::max() ) +{ + m_MaskIndex.Fill( 0 ); +} + + +template< typename TInputImage, typename TOutputImage > +void +Spectra1DSupportWindowToMaskImageFilter< TInputImage, TOutputImage > +::GenerateData() +{ + this->AllocateOutputs(); + + const InputImageType * input = this->GetInput(); + typedef typename InputImageType::PixelType InputPixelType; + const InputPixelType & inputPixel = input->GetPixel( this->GetMaskIndex() ); + + typedef Spectra1DSupportWindowImageFilter< OutputImageType > Spectra1DSupportWindowFilterType; + typedef typename Spectra1DSupportWindowFilterType::FFT1DSizeType FFT1DSizeType; + + const MetaDataDictionary & dict = input->GetMetaDataDictionary(); + FFT1DSizeType fft1DSize = 32; + ExposeMetaData< FFT1DSizeType >( dict, "FFT1DSize", fft1DSize ); + + OutputImageType * output = this->GetOutput(); + output->FillBuffer( this->GetBackgroundValue() ); + + for( typename InputPixelType::const_iterator lineIt = inputPixel.begin(); lineIt != inputPixel.end(); ++lineIt ) + { + const IndexType startIndex = *lineIt; + IndexType index = startIndex; + for( FFT1DSizeType sampleIndex = 0; sampleIndex < fft1DSize; ++sampleIndex ) + { + index[0] = startIndex[0] + sampleIndex; + output->SetPixel( index, this->GetForegroundValue() ); + } + } +} + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.h new file mode 100644 index 0000000000..c910f2a103 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.h @@ -0,0 +1,101 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkTimeGainCompensationImageFilter_h +#define itkTimeGainCompensationImageFilter_h + +#include "itkImageToImageFilter.h" + +#include "itkArray2D.h" + +namespace itk +{ + +/** + * \class TimeGainCompensationImageFilter + * \brief Applies a linear piecewise time gain compensation. + * + * This filter applies a linear piecewise gain with depth. The depth + * direction is assumed to be the first direction (0th direction). + * + * \ingroup Ultrasound + * */ +template< typename TInputImage, typename TOutputImage = TInputImage > +class TimeGainCompensationImageFilter: + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + + typedef TimeGainCompensationImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkTypeMacro( TimeGainCompensationImageFilter, ImageToImageFilter ); + itkNewMacro( Self ); + + typedef Array2D< double > GainType; + + /** Set/Get the gain. The first column specifies the depth. The second + * column specifies the gain. */ + itkSetMacro( Gain, GainType ); + itkGetConstReferenceMacro( Gain, GainType ); + +protected: + typedef typename OutputImageType::RegionType OutputImageRegionType; + + TimeGainCompensationImageFilter(); + virtual ~TimeGainCompensationImageFilter() {} + + void PrintSelf( std::ostream & os, Indent indent ) const ITK_OVERRIDE; + + virtual void BeforeThreadedGenerateData() ITK_OVERRIDE; + virtual void ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId ) ITK_OVERRIDE; + +private: + TimeGainCompensationImageFilter( const Self& ); // purposely not implemented + void operator=( const Self& ); // purposely not implemented + + GainType m_Gain; +}; + +} + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkTimeGainCompensationImageFilter.hxx" +#endif + +#endif // itkTimeGainCompensationImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.hxx new file mode 100644 index 0000000000..ff80d32820 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkTimeGainCompensationImageFilter.hxx @@ -0,0 +1,180 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkTimeGainCompensationImageFilter_hxx +#define itkTimeGainCompensationImageFilter_hxx + +#include "itkTimeGainCompensationImageFilter.h" + +#include "itkImageScanlineIterator.h" +#include "itkImageScanlineConstIterator.h" +#include "itkArray.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +TimeGainCompensationImageFilter< TInputImage, TOutputImage > +::TimeGainCompensationImageFilter(): + m_Gain( 2, 2 ) +{ + m_Gain(0, 0) = NumericTraits< double >::min(); + m_Gain(0, 1) = NumericTraits< double >::OneValue(); + m_Gain(1, 0) = NumericTraits< double >::max(); + m_Gain(1, 1) = NumericTraits< double >::OneValue(); +} + + +template< typename TInputImage, typename TOutputImage > +void +TimeGainCompensationImageFilter< TInputImage, TOutputImage > +::PrintSelf( std::ostream & os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + os << indent << "Gain:" << std::endl; + for( unsigned int ii = 0; ii < m_Gain.rows(); ++ii ) + { + os << indent.GetNextIndent() << "[" << m_Gain( ii, 0 ) << ", " << m_Gain( ii, 1 ) << "]" << std::endl; + } +} + + +template< typename TInputImage, typename TOutputImage > +void +TimeGainCompensationImageFilter< TInputImage, TOutputImage > +::BeforeThreadedGenerateData() +{ + const GainType & gain = this->GetGain(); + if( gain.cols() != 2 ) + { + itkExceptionMacro( "Gain should have two columns." ); + } + if( gain.rows() < 2 ) + { + itkExceptionMacro( "Insufficient depths specified in Gain." ); + } + double depth = gain( 0, 0 ); + for( unsigned int ii = 1; ii < gain.rows(); ++ii ) + { + if( gain( ii, 0 ) <= depth ) + { + itkExceptionMacro( "Gain depths must be strictly increasing." ); + } + depth = gain( ii, 0 ); + } +} + + +template< typename TInputImage, typename TOutputImage > +void +TimeGainCompensationImageFilter< TInputImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType & outputRegionForThread, ThreadIdType itkNotUsed( threadId ) ) +{ + const InputImageType * inputImage = this->GetInput(); + OutputImageType * outputImage = this->GetOutput(); + + // Compute the line gain once. + const GainType & gain = this->GetGain(); + double pieceStart = gain( 0, 0 ); + double pieceEnd = gain( 1, 0 ); + double gainStart = gain( 0, 1 ); + double gainEnd = gain( 1, 1 ); + SizeValueType gainSegment = 1; + + typedef Array< double > LineGainType; + const SizeValueType lineGainSize = outputRegionForThread.GetSize()[0]; + const typename InputImageType::RegionType & inputRegion = inputImage->GetLargestPossibleRegion(); + const IndexValueType imageStartIndex = inputRegion.GetIndex()[0]; + const typename InputImageType::PointType origin = inputImage->GetOrigin(); + const SpacePrecisionType pixelSpacing = inputImage->GetSpacing()[0]; + IndexValueType indexOffset = outputRegionForThread.GetIndex()[0] - imageStartIndex; + LineGainType lineGain( lineGainSize ); + for( SizeValueType lineGainIndex = 0; lineGainIndex < lineGainSize; ++lineGainIndex ) + { + const SpacePrecisionType pixelLocation = origin[0] + pixelSpacing * indexOffset; + if( pixelLocation <= pieceStart ) + { + lineGain[lineGainIndex] = gainStart; + } + else if( pixelLocation > pieceEnd ) + { + if( gainSegment >= gain.rows() - 1 ) + { + lineGain[lineGainIndex] = gainEnd; + } + else + { + ++gainSegment; + pieceStart = gain( gainSegment - 1, 0 ); + pieceEnd = gain( gainSegment, 0 ); + gainStart = gain( gainSegment - 1, 1 ); + gainEnd = gain( gainSegment, 1 ); + + const SpacePrecisionType offset = static_cast< SpacePrecisionType >( pixelLocation - pieceStart ); + lineGain[lineGainIndex] = offset * ( gainEnd - gainStart ) / ( pieceEnd - pieceStart ) + gainStart; + } + } + else + { + const SpacePrecisionType offset = static_cast< SpacePrecisionType >( pixelLocation - pieceStart ); + lineGain[lineGainIndex] = offset * ( gainEnd - gainStart ) / ( pieceEnd - pieceStart ) + gainStart; + } + ++indexOffset; + } + + typedef ImageScanlineConstIterator< InputImageType > InputIteratorType; + InputIteratorType inputIt( inputImage, outputRegionForThread ); + + typedef ImageScanlineIterator< OutputImageType > OutputIteratorType; + OutputIteratorType outputIt( outputImage, outputRegionForThread ); + + for( inputIt.GoToBegin(), outputIt.GoToBegin(); + !outputIt.IsAtEnd(); + inputIt.NextLine(), outputIt.NextLine() ) + { + inputIt.GoToBeginOfLine(); + outputIt.GoToBeginOfLine(); + SizeValueType lineGainIndex = 0; + while( ! outputIt.IsAtEndOfLine() ) + { + outputIt.Set( inputIt.Value() * lineGain[lineGainIndex] ); + ++inputIt; + ++outputIt; + ++lineGainIndex; + } + } +} + +} // end namespace itk + +#endif // itkTimeGainCompensationImageFilter_hxx diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h new file mode 100644 index 0000000000..91b2db0240 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h @@ -0,0 +1,87 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DComplexConjugateToRealImageFilter_h +#define itkVnlFFT1DComplexConjugateToRealImageFilter_h + +#include "itkFFT1DComplexConjugateToRealImageFilter.h" +#include + +namespace itk +{ + +/** \class VnlFFT1DComplexConjugateToRealImageFilter + * + * \brief Perform the FFT along one dimension of an image using Vnl as a + * backend. + * + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=Image< typename NumericTraits< typename TInputImage::PixelType >::ValueType, TInputImage::ImageDimension > > +class VnlFFT1DComplexConjugateToRealImageFilter: + public FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef VnlFFT1DComplexConjugateToRealImageFilter Self; + typedef FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( VnlFFT1DComplexConjugateToRealImageFilter, FFT1DComplexConjugateToRealImageFilter ); + +protected: + virtual void ThreadedGenerateData( const OutputImageRegionType&, ThreadIdType threadID ); // generates output from input + + VnlFFT1DComplexConjugateToRealImageFilter() { } + virtual ~VnlFFT1DComplexConjugateToRealImageFilter() { } + +private: + VnlFFT1DComplexConjugateToRealImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkVnlFFT1DComplexConjugateToRealImageFilter.hxx" +#endif + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx new file mode 100644 index 0000000000..6a628451d3 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx @@ -0,0 +1,114 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DComplexConjugateToRealImageFilter_hxx +#define itkVnlFFT1DComplexConjugateToRealImageFilter_hxx + +#include "itkVnlFFT1DComplexConjugateToRealImageFilter.h" + +#include "itkFFT1DComplexConjugateToRealImageFilter.hxx" +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" +#include "itkIndent.h" +#include "itkMetaDataObject.h" +#include "itkExceptionObject.h" +#include "vnl/algo/vnl_fft_base.h" +#include "vnl/algo/vnl_fft_1d.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +void +VnlFFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType& outputRegion, ThreadIdType itkNotUsed( threadID ) ) +{ + // get pointers to the input and output + const typename Superclass::InputImageType * inputPtr = this->GetInput(); + typename Superclass::OutputImageType * outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + const typename Superclass::InputImageType::SizeType & inputSize = inputPtr->GetRequestedRegion().GetSize(); + + unsigned int vec_size = inputSize[this->m_Direction]; + + typedef itk::ImageLinearConstIteratorWithIndex< InputImageType > InputIteratorType; + typedef itk::ImageLinearIteratorWithIndex< OutputImageType > OutputIteratorType; + InputIteratorType inputIt( inputPtr, outputRegion ); + OutputIteratorType outputIt( outputPtr, outputRegion ); + + inputIt.SetDirection(this->m_Direction); + outputIt.SetDirection(this->m_Direction); + + typedef typename TOutputImage::PixelType OutputPixelType; + vnl_vector< vcl_complex< OutputPixelType > > inputBuffer( vec_size ); + typename vnl_vector< vcl_complex< OutputPixelType > >::iterator inputBufferIt = inputBuffer.begin(); + // fft is done in-place + typename vnl_vector< vcl_complex< OutputPixelType > >::iterator outputBufferIt = inputBuffer.begin(); + vnl_fft_1d< OutputPixelType > v1d(vec_size); + + // for every fft line + for( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); + outputIt.NextLine(), inputIt.NextLine() ) + { + // copy the input line into our buffer + inputIt.GoToBeginOfLine(); + inputBufferIt = inputBuffer.begin(); + while( !inputIt.IsAtEndOfLine() ) + { + *inputBufferIt = inputIt.Get(); + ++inputIt; + ++inputBufferIt; + } + + // do the transform + v1d.fwd_transform(inputBuffer); + + // copy the output from the buffer into our line + outputBufferIt = inputBuffer.begin(); + outputIt.GoToBeginOfLine(); + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( (*outputBufferIt).real() / vec_size ); + ++outputIt; + ++outputBufferIt; + } + } +} + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h new file mode 100644 index 0000000000..f2a80377ca --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h @@ -0,0 +1,89 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DComplexToComplexImageFilter_h +#define itkVnlFFT1DComplexToComplexImageFilter_h + +#include "itkFFT1DComplexToComplexImageFilter.h" +#include + +namespace itk +{ + +/** \class VnlFFT1DComplexToComplexImageFilter + * + * \brief Perform the FFT along one dimension of an image using Vnl as a + * backend. + * + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage > +class VnlFFT1DComplexToComplexImageFilter: + public FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef VnlFFT1DComplexToComplexImageFilter Self; + typedef FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + typedef typename Superclass::TransformDirectionType TransformDirectionType; + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( VnlFFT1DComplexToComplexImageFilter, FFT1DComplexToComplexImageFilter ); + +protected: + VnlFFT1DComplexToComplexImageFilter() {} + virtual ~VnlFFT1DComplexToComplexImageFilter() {} + + virtual void ThreadedGenerateData( const OutputImageRegionType&, ThreadIdType threadID ) ITK_OVERRIDE; + +private: + VnlFFT1DComplexToComplexImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkVnlFFT1DComplexToComplexImageFilter.hxx" +#endif + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx new file mode 100644 index 0000000000..31639f9780 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx @@ -0,0 +1,131 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DComplexToComplexImageFilter_hxx +#define itkVnlFFT1DComplexToComplexImageFilter_hxx + +#include "itkVnlFFT1DComplexToComplexImageFilter.h" + +#include "itkFFT1DComplexToComplexImageFilter.hxx" +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" +#include "itkIndent.h" +#include "itkMetaDataObject.h" +#include "itkExceptionObject.h" +#include "vnl/algo/vnl_fft_base.h" +#include "vnl/algo/vnl_fft_1d.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +void +VnlFFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType& outputRegion, ThreadIdType itkNotUsed( threadID ) ) +{ + // get pointers to the input and output + const typename Superclass::InputImageType * inputPtr = this->GetInput(); + typename Superclass::OutputImageType * outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + const typename Superclass::InputImageType::SizeType & inputSize = inputPtr->GetRequestedRegion().GetSize(); + + const unsigned int direction = this->GetDirection(); + const unsigned int vectorSize = inputSize[direction]; + + typedef itk::ImageLinearConstIteratorWithIndex< InputImageType > InputIteratorType; + typedef itk::ImageLinearIteratorWithIndex< OutputImageType > OutputIteratorType; + InputIteratorType inputIt( inputPtr, outputRegion ); + OutputIteratorType outputIt( outputPtr, outputRegion ); + + inputIt.SetDirection( direction ); + outputIt.SetDirection( direction ); + + typedef typename TInputImage::PixelType PixelType; + typedef vnl_vector< PixelType > VNLVectorType; + VNLVectorType inputBuffer( vectorSize ); + typename VNLVectorType::iterator inputBufferIt = inputBuffer.begin(); + // fft is done in-place + typename VNLVectorType::iterator outputBufferIt = inputBuffer.begin(); + vnl_fft_1d< typename NumericTraits< PixelType >::ValueType > v1d(vectorSize); + + // for every fft line + for( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); + outputIt.NextLine(), inputIt.NextLine() ) + { + // copy the input line into our buffer + inputIt.GoToBeginOfLine(); + inputBufferIt = inputBuffer.begin(); + while( !inputIt.IsAtEndOfLine() ) + { + *inputBufferIt = inputIt.Get(); + ++inputIt; + ++inputBufferIt; + } + + // do the transform + if( this->m_TransformDirection == Superclass::DIRECT ) + { + v1d.bwd_transform(inputBuffer); + // copy the output from the buffer into our line + outputBufferIt = inputBuffer.begin(); + outputIt.GoToBeginOfLine(); + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( *outputBufferIt ); + ++outputIt; + ++outputBufferIt; + } + } + else // m_TransformDirection == INVERSE + { + v1d.fwd_transform(inputBuffer); + // copy the output from the buffer into our line + outputBufferIt = inputBuffer.begin(); + outputIt.GoToBeginOfLine(); + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( (*outputBufferIt) / static_cast< PixelType >( vectorSize )); + ++outputIt; + ++outputBufferIt; + } + } + } +} + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h new file mode 100644 index 0000000000..e0e99f70f8 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h @@ -0,0 +1,87 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DRealToComplexConjugateImageFilter_h +#define itkVnlFFT1DRealToComplexConjugateImageFilter_h + +#include "itkFFT1DRealToComplexConjugateImageFilter.h" +#include + +namespace itk +{ + +/** \class VnlFFT1DRealToComplexConjugateImageFilter + * + * \brief Perform the FFT along one dimension of an image using Vnl as a + * backend. + * + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=Image< std::complex< typename TInputImage::PixelType >, TInputImage::ImageDimension > > +class VnlFFT1DRealToComplexConjugateImageFilter : + public FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef VnlFFT1DRealToComplexConjugateImageFilter Self; + typedef FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( VnlFFT1DRealToComplexConjugateImageFilter, FFT1DRealToComplexConjugateImageFilter ); + +protected: + virtual void ThreadedGenerateData( const OutputImageRegionType&, ThreadIdType threadID ) ITK_OVERRIDE; + + VnlFFT1DRealToComplexConjugateImageFilter() { } + ~VnlFFT1DRealToComplexConjugateImageFilter() { } + +private: + VnlFFT1DRealToComplexConjugateImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkVnlFFT1DRealToComplexConjugateImageFilter.hxx" +#endif + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx new file mode 100644 index 0000000000..57d3532734 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx @@ -0,0 +1,119 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DRealToComplexConjugateImageFilter_hxx +#define itkVnlFFT1DRealToComplexConjugateImageFilter_hxx + +#include "itkVnlFFT1DRealToComplexConjugateImageFilter.h" + +#include "itkFFT1DRealToComplexConjugateImageFilter.hxx" +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" +#include "itkIndent.h" +#include "itkMetaDataObject.h" +#include "itkExceptionObject.h" +#include "itkVnlFFTCommon.h" +#include "vnl/algo/vnl_fft_base.h" +#include "vnl/algo/vnl_fft_1d.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +void +VnlFFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType& outputRegion, ThreadIdType itkNotUsed( threadID ) ) +{ + // get pointers to the input and output + const typename Superclass::InputImageType * inputPtr = this->GetInput(); + typename Superclass::OutputImageType * outputPtr = this->GetOutput(); + + const typename Superclass::InputImageType::SizeType & inputSize = inputPtr->GetRequestedRegion().GetSize(); + + const unsigned int direction = this->GetDirection(); + unsigned int vectorSize = inputSize[direction]; + if( ! VnlFFTCommon::IsDimensionSizeLegal(vectorSize) ) + { + itkExceptionMacro("Illegal Array DIM for FFT"); + } + + + typedef ImageLinearConstIteratorWithIndex< InputImageType > InputIteratorType; + typedef ImageLinearIteratorWithIndex< OutputImageType > OutputIteratorType; + InputIteratorType inputIt( inputPtr, outputRegion ); + OutputIteratorType outputIt( outputPtr, outputRegion ); + + inputIt.SetDirection( direction ); + outputIt.SetDirection( direction ); + + typedef typename TInputImage::PixelType PixelType; + typedef vcl_complex< PixelType > ComplexType; + typedef vnl_vector< ComplexType > ComplexVectorType; + ComplexVectorType inputBuffer( vectorSize ); + typename ComplexVectorType::iterator inputBufferIt = inputBuffer.begin(); + // fft is done in-place + typename ComplexVectorType::iterator outputBufferIt = inputBuffer.begin(); + vnl_fft_1d< PixelType > v1d( vectorSize ); + + // for every fft line + for( inputIt.GoToBegin(), outputIt.GoToBegin(); + !inputIt.IsAtEnd(); + outputIt.NextLine(), inputIt.NextLine() ) + { + // copy the input line into our buffer + inputIt.GoToBeginOfLine(); + inputBufferIt = inputBuffer.begin(); + while( !inputIt.IsAtEndOfLine() ) + { + *inputBufferIt = inputIt.Value(); + ++inputIt; + ++inputBufferIt; + } + + // do the transform + v1d.bwd_transform( inputBuffer ); + + // copy the output from the buffer into our line + outputBufferIt = inputBuffer.begin(); + outputIt.GoToBeginOfLine(); + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( *outputBufferIt ); + ++outputIt; + ++outputBufferIt; + } + } +} + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.cpp b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.cpp new file mode 100644 index 0000000000..891839b80a --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.cpp @@ -0,0 +1,103 @@ +/*=================================================================== + +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 "mitkPhotoacousticBModeFilter.h" +#include "usServiceReference.h" + +mitk::PhotoacousticBModeFilter::PhotoacousticBModeFilter() + : m_PixelCalculation(NULL) +{ + this->AddSourceFile("BModeAbs.cl"); + this->AddSourceFile("BModeAbsLog.cl"); + + this->m_FilterID = "PixelCalculation"; +} + +mitk::PhotoacousticBModeFilter::~PhotoacousticBModeFilter() +{ + if (this->m_PixelCalculation) + { + clReleaseKernel(m_PixelCalculation); + } +} + +void mitk::PhotoacousticBModeFilter::Update() +{ + //Check if context & program available + if (!this->Initialize()) + { + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + // clean-up also the resources + resources->InvalidateStorage(); + mitkThrow() << "Filter is not initialized. Cannot update."; + } + else { + // Execute + this->Execute(); + } +} + +void mitk::PhotoacousticBModeFilter::Execute() +{ + try + { + this->InitExec(this->m_PixelCalculation); + } + catch (const mitk::Exception& e) + { + MITK_ERROR << "Catched exception while initializing filter: " << e.what(); + return; + } + + // execute the filter on a 3D NDRange + this->ExecuteKernel(m_PixelCalculation, 3); + + // signalize the GPU-side data changed + m_Output->Modified(GPU_DATA); +} + +us::Module *mitk::PhotoacousticBModeFilter::GetModule() +{ + return us::GetModuleContext()->GetModule(); +} + +bool mitk::PhotoacousticBModeFilter::Initialize() +{ + bool buildErr = true; + cl_int clErr = 0; + + if (OclFilter::Initialize()) + { + if(m_UseLogFilter) + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckBmodeAbsLog", &clErr); + else + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckBmodeAbs", &clErr); + buildErr |= CHECK_OCL_ERR(clErr); + } + return (OclFilter::IsInitialized() && buildErr); +} + +void mitk::PhotoacousticBModeFilter::SetInput(mitk::Image::Pointer image) +{ + if (image->GetDimension() != 3) + { + mitkThrowException(mitk::Exception) << "Input for " << this->GetNameOfClass() << + " is not 3D. The filter only supports 3D. Please change your input."; + } + OclImageToImageFilter::SetInput(image); +} diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.h new file mode 100644 index 0000000000..adc24614df --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticBModeFilter.h @@ -0,0 +1,91 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ +#define _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ + +#include "mitkOclImageToImageFilter.h" +#include + +namespace mitk +{ + class OclImageToImageFilter; + + /** Documentation + * + * \brief The OclBinaryThresholdImageFilter computes a binary segmentation based on given + threshold values. + + * + * The filter requires two threshold values ( the upper and the lower threshold ) and two image values ( inside and outside ). The resulting voxel of the segmentation image is assigned the inside value 1 if the image value is between the given thresholds and the outside value otherwise. + */ + + + class PhotoacousticBModeFilter : public OclImageToImageFilter, public itk::Object + { + + public: + mitkClassMacroItkParent(PhotoacousticBModeFilter, itk::Object); + itkNewMacro(Self); + + /** + * @brief SetInput Set the input image. Only 3D images are supported for now. + * @param image a 3D image. + * @throw mitk::Exception if the dimesion is not 3. + */ + void SetInput(Image::Pointer image); + + /** Update the filter */ + void Update(); + + void SetParameters(bool useLogFilter) + { + m_UseLogFilter = useLogFilter; + } + + protected: + + /** Constructor */ + PhotoacousticBModeFilter(); + + /** Destructor */ + virtual ~PhotoacousticBModeFilter(); + + /** Initialize the filter */ + bool Initialize(); + + void Execute(); + + mitk::PixelType GetOutputType() + { + return mitk::MakeScalarPixelType(); + } + + int GetBytesPerElem() + { + return sizeof(float); + } + + virtual us::Module* GetModule(); + + + private: + /** The OpenCL kernel for the filter */ + cl_kernel m_PixelCalculation; + bool m_UseLogFilter; + }; +} +#endif \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.cpp b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.cpp new file mode 100644 index 0000000000..114810ddc9 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.cpp @@ -0,0 +1,177 @@ +/*=================================================================== + +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 "mitkPhotoacousticOCLBeamformer.h" +#include "usServiceReference.h" + +mitk::PhotoacousticOCLBeamformer::PhotoacousticOCLBeamformer() +: m_PixelCalculation( NULL ) +{ + this->AddSourceFile("DASQuadratic.cl"); + this->AddSourceFile("DMASQuadratic.cl"); + this->AddSourceFile("DASspherical.cl"); + this->AddSourceFile("DMASspherical.cl"); + + this->m_FilterID = "PixelCalculation"; +} + +mitk::PhotoacousticOCLBeamformer::~PhotoacousticOCLBeamformer() +{ + if ( this->m_PixelCalculation ) + { + clReleaseKernel( m_PixelCalculation ); + } +} + +void mitk::PhotoacousticOCLBeamformer::Update() +{ + //Check if context & program available + if (!this->Initialize()) + { + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + // clean-up also the resources + resources->InvalidateStorage(); + mitkThrow() <<"Filter is not initialized. Cannot update."; + } + else{ + // Execute + this->Execute(); + } +} + +void mitk::PhotoacousticOCLBeamformer::Execute() +{ + cl_int clErr = 0; + + try + { + this->InitExec(this->m_PixelCalculation, m_OutputDim); + } + catch (const mitk::Exception& e) + { + MITK_ERROR << "Caught exception while initializing filter: " << e.what(); + return; + } + + if (m_Apodisation == nullptr) + { + MITK_INFO << "No apodisation function set; Beamforming will be done without any apodisation."; + m_Apodisation = new float[1]; + m_Apodisation[0] = 1; + m_ApodArraySize = 1; + } + + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + cl_context gpuContext = resources->GetContext(); + + cl_mem cl_input = clCreateBuffer(gpuContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * m_ApodArraySize, m_Apodisation, &clErr); + CHECK_OCL_ERR(clErr); + + // set kernel arguments + clErr = clSetKernelArg( this->m_PixelCalculation, 2, sizeof(cl_mem), &cl_input); + clErr |= clSetKernelArg( this->m_PixelCalculation, 3, sizeof(cl_ushort), &(this->m_ApodArraySize) ); + clErr |= clSetKernelArg( this->m_PixelCalculation, 4, sizeof(cl_float), &(this->m_SpeedOfSound) ); + clErr |= clSetKernelArg( this->m_PixelCalculation, 5, sizeof(cl_float), &(this->m_TimeSpacing) ); + clErr |= clSetKernelArg( this->m_PixelCalculation, 6, sizeof(cl_float), &(this->m_Pitch) ); + clErr |= clSetKernelArg( this->m_PixelCalculation, 7, sizeof(cl_float), &(this->m_Angle) ); + clErr |= clSetKernelArg( this->m_PixelCalculation, 8, sizeof(cl_ushort), &(this->m_PAImage)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 9, sizeof(cl_ushort), &(this->m_TransducerElements)); + + CHECK_OCL_ERR( clErr ); + + // execute the filter on a 3D NDRange + this->ExecuteKernel( m_PixelCalculation, 3); + + // signalize the GPU-side data changed + m_Output->Modified( GPU_DATA ); +} + +us::Module *mitk::PhotoacousticOCLBeamformer::GetModule() +{ + return us::GetModuleContext()->GetModule(); +} + +bool mitk::PhotoacousticOCLBeamformer::Initialize() +{ + bool buildErr = true; + cl_int clErr = 0; + + if ( OclFilter::Initialize() ) + { + switch (m_Algorithm) + { + case BeamformingAlgorithm::DASQuad: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDASQuad", &clErr); + break; + } + case BeamformingAlgorithm::DMASQuad: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDMASQuad", &clErr); + break; + } + case BeamformingAlgorithm::DASSphe: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDASSphe", &clErr); + break; + } + case BeamformingAlgorithm::DMASSphe: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDMASSphe", &clErr); + break; + } + } + buildErr |= CHECK_OCL_ERR( clErr ); + } + return (OclFilter::IsInitialized() && buildErr ); +} + +void mitk::PhotoacousticOCLBeamformer::SetInput(mitk::Image::Pointer image) +{ + if(image->GetDimension() != 3) + { + mitkThrowException(mitk::Exception) << "Input for " << this->GetNameOfClass() << + " is not 3D. The filter only supports 3D. Please change your input."; + } + OclImageToImageFilter::SetInput(image); +} + +mitk::Image::Pointer mitk::PhotoacousticOCLBeamformer::GetOutput() +{ + if (m_Output->IsModified(GPU_DATA)) + { + void* pData = m_Output->TransferDataToCPU(m_CommandQue); + + const unsigned int dimension = 3; + unsigned int* dimensions = m_OutputDim; + + const mitk::SlicedGeometry3D::Pointer p_slg = m_Input->GetMITKImage()->GetSlicedGeometry(); + + MITK_DEBUG << "Creating new MITK Image."; + + m_Output->GetMITKImage()->Initialize(this->GetOutputType(), dimension, dimensions); + m_Output->GetMITKImage()->SetSpacing(p_slg->GetSpacing()); + m_Output->GetMITKImage()->SetGeometry(m_Input->GetMITKImage()->GetGeometry()); + m_Output->GetMITKImage()->SetImportVolume(pData, 0, 0, mitk::Image::ReferenceMemory); + } + + MITK_DEBUG << "Image Initialized."; + + return m_Output->GetMITKImage(); +} diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.h b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.h new file mode 100644 index 0000000000..9a7c90e0de --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/OCL/mitkPhotoacousticOCLBeamformer.h @@ -0,0 +1,129 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ +#define _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ + +#include "mitkOclImageToImageFilter.h" +#include + +namespace mitk +{ +class OclImageToImageFilter; + +/** Documentation + * + * \brief The OclBinaryThresholdImageFilter computes a binary segmentation based on given + threshold values. + + * + * The filter requires two threshold values ( the upper and the lower threshold ) and two image values ( inside and outside ). The resulting voxel of the segmentation image is assigned the inside value 1 if the image value is between the given thresholds and the outside value otherwise. + */ + + +class PhotoacousticOCLBeamformer : public OclImageToImageFilter, public itk::Object +{ + +public: + mitkClassMacroItkParent(PhotoacousticOCLBeamformer, itk::Object); + itkNewMacro(Self); + + /** + * @brief SetInput Set the input image. Only 3D images are supported for now. + * @param image a 3D image. + * @throw mitk::Exception if the dimesion is not 3. + */ + void SetInput(Image::Pointer image); + + mitk::Image::Pointer GetOutput(); + + /** Update the filter */ + void Update(); + + void SetOutputDim( unsigned int outputDim[3]) + { + m_OutputDim[0] = outputDim[0]; + m_OutputDim[1] = outputDim[1]; + m_OutputDim[2] = outputDim[2]; + } + + void SetApodisation(float* apodisation, unsigned short apodArraySize) + { + m_ApodArraySize = apodArraySize; + m_Apodisation = apodisation; + } + + enum BeamformingAlgorithm { DASQuad, DMASQuad, DASSphe, DMASSphe }; + + void SetAlgorithm(BeamformingAlgorithm algorithm, bool PA) + { + m_Algorithm = algorithm; + m_PAImage = PA; + } + + void SetBeamformingParameters(float SpeedOfSound, float timeSpacing, float Pitch, float Angle, bool PAImage, unsigned short transducerElements) + { + m_SpeedOfSound = SpeedOfSound; + m_TimeSpacing = timeSpacing; + m_Pitch = Pitch; + m_Angle = Angle; + m_PAImage = PAImage; + m_TransducerElements = transducerElements; + } + +protected: + + /** Constructor */ + PhotoacousticOCLBeamformer(); + + /** Destructor */ + virtual ~PhotoacousticOCLBeamformer(); + + /** Initialize the filter */ + bool Initialize(); + + void Execute(); + + mitk::PixelType GetOutputType() + { + return mitk::MakeScalarPixelType(); + } + + int GetBytesPerElem() + { + return sizeof(float); + } + + virtual us::Module* GetModule(); + + +private: + /** The OpenCL kernel for the filter */ + cl_kernel m_PixelCalculation; + + unsigned int m_OutputDim[3]; + float* m_Apodisation; + unsigned short m_ApodArraySize; + BeamformingAlgorithm m_Algorithm; + unsigned short m_PAImage; + float m_SpeedOfSound; + float m_TimeSpacing; + float m_Pitch; + float m_Angle; + unsigned short m_TransducerElements; +}; +} +#endif \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.h new file mode 100644 index 0000000000..3bb1bda69d --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.h @@ -0,0 +1,147 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkPhotoacousticBModeImageFilter_h +#define itkPhotoacousticBModeImageFilter_h + +#include "itkComplexToModulusImageFilter.h" +#include "itkConstantPadImageFilter.h" +#include "itkImageToImageFilter.h" +#include "itkImage.h" + +#include "ITKUltrasound/itkRegionFromReferenceImageFilter.h" +#include "ITKUltrasound/itkAnalyticSignalImageFilter.h" + +namespace itk +{ + +/** + * \class PhotoacousticBModeImageFilter + * + * \brief Create an Photoacoustic B-Mode (Brightness-Mode) image from raw + * "RF" data. The RF's envelope is calculated from the analytic signal and + * logarithmic intensity transform is NOT applied. This is for now the only + * difference to the "normal" BModeImageFilter. + * + * Use SetDirection() to define the axis of propagation. + * + */ +template < typename TInputImage, typename TOutputImage=TInputImage, typename TComplexImage=Image< std::complex< typename TInputImage::PixelType >, TInputImage::ImageDimension > > +class PhotoacousticBModeImageFilter : + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef PhotoacousticBModeImageFilter Self; + typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + /** The type of input image. */ + typedef TInputImage InputImageType; + + /** Dimension of the input and output images. */ + itkStaticConstMacro (ImageDimension, unsigned int, + TInputImage::ImageDimension); + + /** Typedef support for the input image scalar value type. */ + typedef typename InputImageType::PixelType InputPixelType; + + /** The type of output image. */ + typedef TOutputImage OutputImageType; + + /** Typedef support for the output image scalar value type. */ + typedef typename OutputImageType::PixelType OutputPixelType; + + /** Typedef of the image used for internal computations that has + * std::complex pixels. */ + typedef TComplexImage ComplexImageType; + + /** Other convenient typedefs */ + typedef typename InputImageType::RegionType InputRegionType; + typedef typename InputImageType::SizeType InputSizeType; + typedef typename InputImageType::IndexType InputIndexType; + + /** Run-time type information (and related methods) */ + itkTypeMacro( PhotoacousticBModeImageFilter, ImageToImageFilter ); + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Set the direction in which the envelope is to be calculated. */ + virtual void SetDirection( unsigned int direction ) + { + this->m_AnalyticFilter->SetDirection( direction ); + this->Modified(); + } + + /** Get the direction in which the envelope is to be calculated. */ + virtual unsigned int GetDirection() const + { + return m_AnalyticFilter->GetDirection(); + } + +protected: + PhotoacousticBModeImageFilter(); + ~PhotoacousticBModeImageFilter() {} + + virtual void PrintSelf( std::ostream& os, Indent indent ) const ITK_OVERRIDE; + + virtual void GenerateData() ITK_OVERRIDE; + + // These behave like their analogs in FFT1DRealToComplexConjugateImageFilter. + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + /** Component filters. */ + typedef AnalyticSignalImageFilter< InputImageType, ComplexImageType > AnalyticType; + typedef ComplexToModulusImageFilter< typename AnalyticType::OutputImageType, OutputImageType > ComplexToModulusType; + typedef ConstantPadImageFilter< InputImageType, InputImageType > PadType; + typedef RegionFromReferenceImageFilter< OutputImageType, OutputImageType > ROIType; + +private: + PhotoacousticBModeImageFilter( const Self& ); // purposely not implemented + void operator=( const Self& ); // purposely not implemented + + typename AnalyticType::Pointer m_AnalyticFilter; + typename ComplexToModulusType::Pointer m_ComplexToModulusFilter; + typename PadType::Pointer m_PadFilter; + typename ROIType::Pointer m_ROIFilter; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkPhotoacousticBModeImageFilter.hxx" +#endif + +#endif // itkPhotoacousticBModeImageFilter_h diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.hxx b/Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.hxx new file mode 100644 index 0000000000..dace5c1cfc --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/itkPhotoacousticBModeImageFilter.hxx @@ -0,0 +1,207 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkPhotoacousticBModeImageFilter_hxx +#define itkPhotoacousticBModeImageFilter_hxx + +#include "itkPhotoacousticBModeImageFilter.h" + +#include "itkMetaDataDictionary.h" + +#include +#include +#include + +namespace itk +{ + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::PhotoacousticBModeImageFilter() +{ + m_AnalyticFilter = AnalyticType::New(); + m_ComplexToModulusFilter = ComplexToModulusType::New(); + m_PadFilter = PadType::New(); + m_ROIFilter = ROIType::New(); + + m_PadFilter->SetConstant( 0. ); + m_ComplexToModulusFilter->SetInput( m_AnalyticFilter->GetOutput() ); + m_ROIFilter->SetInput( m_ComplexToModulusFilter->GetOutput() ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + InputImageType * inputPtr = const_cast (this->GetInput()); + OutputImageType * outputPtr = this->GetOutput(); + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->GetDirection(); + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast< OutputImageType* >( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + const unsigned int direction = this->GetDirection (); + enlargedSize[direction] = outputLargeSize[direction]; + enlargedIndex[direction] = outputLargeIndex[direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::GenerateData() +{ + this->AllocateOutputs(); + + const InputImageType * inputPtr = this->GetInput(); + OutputImageType * outputPtr = this->GetOutput(); + + const unsigned int direction = m_AnalyticFilter->GetDirection(); + typename InputImageType::SizeType size = inputPtr->GetLargestPossibleRegion().GetSize(); + + // Zero padding. FFT direction should be factorable by 2 for all FFT + // implementations to work. + unsigned int n = size[direction]; + while( n % 2 == 0 ) + { + n /= 2; + } + bool doPadding; + if( n == 1 ) + { + doPadding = false; + } + else + { + doPadding = true; + } + if( doPadding ) + { + n = size[direction]; + unsigned int newSizeDirection = 1; + while( newSizeDirection < n ) + { + newSizeDirection *= 2; + } + typename InputImageType::SizeType padSize; + padSize.Fill( 0 ); + padSize[direction] = newSizeDirection - size[direction]; + size[direction] = newSizeDirection; + m_PadFilter->SetPadUpperBound( padSize ); + m_PadFilter->SetInput( inputPtr ); + m_AnalyticFilter->SetInput( m_PadFilter->GetOutput() ); + m_ROIFilter->SetReferenceImage( inputPtr ); + m_ROIFilter->SetInput( m_ComplexToModulusFilter->GetOutput() ); + m_ROIFilter->GraftOutput( outputPtr ); + m_ROIFilter->Update(); + this->GraftOutput( m_ROIFilter->GetOutput() ); + } + else // padding is not required + { + m_AnalyticFilter->SetInput( inputPtr ); + m_ComplexToModulusFilter->GraftOutput( outputPtr ); + m_ComplexToModulusFilter->Update(); + this->GraftOutput( m_ComplexToModulusFilter->GetOutput() ); + } + +} + +} // end namespace itk + +#endif diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.cpp b/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.cpp new file mode 100644 index 0000000000..47587fb719 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.cpp @@ -0,0 +1,607 @@ +/*=================================================================== +mitkPhotoacousticBeamformingFilter +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. + +===================================================================*/ + +#define _USE_MATH_DEFINES + +#include "mitkPhotoacousticBeamformingFilter.h" +#include "mitkProperties.h" +#include "mitkImageReadAccessor.h" +#include +#include +#include +#include +#include +#include +#include "mitkImageCast.h" +#include + + +mitk::BeamformingFilter::BeamformingFilter() : m_OutputData(nullptr), m_InputData(nullptr) +{ + this->SetNumberOfIndexedInputs(1); + this->SetNumberOfRequiredInputs(1); + + m_ProgressHandle = [](int, std::string) {}; +} + +void mitk::BeamformingFilter::SetProgressHandle(std::function progressHandle) +{ + m_ProgressHandle = progressHandle; +} + +mitk::BeamformingFilter::~BeamformingFilter() +{ +} + +void mitk::BeamformingFilter::GenerateInputRequestedRegion() +{ + Superclass::GenerateInputRequestedRegion(); + + mitk::Image* output = this->GetOutput(); + mitk::Image* input = const_cast (this->GetInput()); + if (!output->IsInitialized()) + { + return; + } + + input->SetRequestedRegionToLargestPossibleRegion(); + + //GenerateTimeInInputRegion(output, input); +} + +void mitk::BeamformingFilter::GenerateOutputInformation() +{ + mitk::Image::ConstPointer input = this->GetInput(); + mitk::Image::Pointer output = this->GetOutput(); + + if ((output->IsInitialized()) && (this->GetMTime() <= m_TimeOfHeaderInitialization.GetMTime())) + return; + + itkDebugMacro(<< "GenerateOutputInformation()"); + + unsigned int dim[] = { m_Conf.ReconstructionLines, m_Conf.SamplesPerLine, input->GetDimension(2) }; + output->Initialize(mitk::MakeScalarPixelType(), 3, dim); + + mitk::Vector3D spacing; + spacing[0] = m_Conf.Pitch * m_Conf.TransducerElements * 1000 / m_Conf.ReconstructionLines; + spacing[1] = m_Conf.RecordTime / 2 * m_Conf.SpeedOfSound * 1000 / m_Conf.SamplesPerLine; + spacing[2] = 1; + + output->GetGeometry()->SetSpacing(spacing); + output->GetGeometry()->Modified(); + output->SetPropertyList(input->GetPropertyList()->Clone()); + + m_TimeOfHeaderInitialization.Modified(); +} + +void mitk::BeamformingFilter::GenerateData() +{ + GenerateOutputInformation(); + mitk::Image::Pointer input = this->GetInput(); + mitk::Image::Pointer output = this->GetOutput(); + + if (!output->IsInitialized()) + return; + + float inputDim[2] = { (float)input->GetDimension(0), (float)input->GetDimension(1) }; + float outputDim[2] = { (float)output->GetDimension(0), (float)output->GetDimension(1) }; + + unsigned short chunkSize = 2; // TODO: make this slightly less arbitrary + + unsigned int oclOutputDim[3] = { output->GetDimension(0), output->GetDimension(1), output->GetDimension(2) }; + + unsigned int oclOutputDimChunk[3] = { output->GetDimension(0), output->GetDimension(1), chunkSize}; + unsigned int oclInputDimChunk[3] = { input->GetDimension(0), input->GetDimension(1), chunkSize}; + + unsigned int oclOutputDimLastChunk[3] = { output->GetDimension(0), output->GetDimension(1), input->GetDimension(2) % chunkSize }; + unsigned int oclInputDimLastChunk[3] = { input->GetDimension(0), input->GetDimension(1), input->GetDimension(2) % chunkSize }; + + const int apodArraySize = m_Conf.TransducerElements * 4; // set the resolution of the apodization array + float* ApodWindow; + + // calculate the appropiate apodization window + switch (m_Conf.Apod) + { + case beamformingSettings::Apodization::Hann: + ApodWindow = VonHannFunction(apodArraySize); + break; + case beamformingSettings::Apodization::Hamm: + ApodWindow = HammFunction(apodArraySize); + break; + case beamformingSettings::Apodization::Box: + ApodWindow = BoxFunction(apodArraySize); + break; + default: + ApodWindow = BoxFunction(apodArraySize); + break; + } + + int progInterval = output->GetDimension(2) / 20 > 1 ? output->GetDimension(2) / 20 : 1; + // the interval at which we update the gui progress bar + + auto begin = std::chrono::high_resolution_clock::now(); // debbuging the performance... + if (!m_Conf.UseGPU) + { + for (unsigned int i = 0; i < output->GetDimension(2); ++i) // seperate Slices should get Beamforming seperately applied + { + mitk::ImageReadAccessor inputReadAccessor(input, input->GetSliceData(i)); + + m_OutputData = new float[m_Conf.ReconstructionLines*m_Conf.SamplesPerLine]; + m_InputDataPuffer = new float[input->GetDimension(0)*input->GetDimension(1)]; + + // first, we convert any data to float, which we use by default + if (input->GetPixelType().GetTypeAsString() == "scalar (float)" || input->GetPixelType().GetTypeAsString() == " (float)") + { + m_InputData = (float*)inputReadAccessor.GetData(); + } + else + { + MITK_INFO << "Pixel type is not float, abort"; + return; + } + + // fill the image with zeros + for (int l = 0; l < outputDim[0]; ++l) + { + for (int s = 0; s < outputDim[1]; ++s) + { + m_OutputData[l*(short)outputDim[1] + s] = 0; + } + } + + std::thread *threads = new std::thread[(short)outputDim[0]]; + + // every line will be beamformed in a seperate thread + if (m_Conf.Algorithm == beamformingSettings::BeamformingAlgorithm::DAS) + { + if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::QuadApprox) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::DASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, apodArraySize); + } + } + else if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::Spherical) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::DASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, apodArraySize); + } + } + } + else if (m_Conf.Algorithm == beamformingSettings::BeamformingAlgorithm::DMAS) + { + if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::QuadApprox) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::DMASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, apodArraySize); + } + } + else if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::Spherical) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingFilter::DMASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, apodArraySize); + } + } + } + // wait for all lines to finish + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line].join(); + } + + output->SetSlice(m_OutputData, i); + + if (i % progInterval == 0) + m_ProgressHandle((int)((i + 1) / (float)output->GetDimension(2) * 100), "performing reconstruction"); + + delete[] m_OutputData; + delete[] m_InputDataPuffer; + m_OutputData = nullptr; + m_InputData = nullptr; + } + } + else + { + mitk::PhotoacousticOCLBeamformer::Pointer m_oclFilter = mitk::PhotoacousticOCLBeamformer::New(); + + try + { + if (m_Conf.Algorithm == beamformingSettings::BeamformingAlgorithm::DAS) + { + if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::QuadApprox) + m_oclFilter->SetAlgorithm(PhotoacousticOCLBeamformer::BeamformingAlgorithm::DASQuad, true); + else if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::Spherical) + m_oclFilter->SetAlgorithm(PhotoacousticOCLBeamformer::BeamformingAlgorithm::DASSphe, true); + } + else if (m_Conf.Algorithm == beamformingSettings::BeamformingAlgorithm::DMAS) + { + if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::QuadApprox) + m_oclFilter->SetAlgorithm(PhotoacousticOCLBeamformer::BeamformingAlgorithm::DMASQuad, true); + else if (m_Conf.DelayCalculationMethod == beamformingSettings::DelayCalc::Spherical) + m_oclFilter->SetAlgorithm(PhotoacousticOCLBeamformer::BeamformingAlgorithm::DMASSphe, true); + } + m_oclFilter->SetApodisation(ApodWindow, apodArraySize); + m_oclFilter->SetOutputDim(oclOutputDimChunk); + m_oclFilter->SetBeamformingParameters(m_Conf.SpeedOfSound, m_Conf.TimeSpacing, m_Conf.Pitch, m_Conf.Angle, m_Conf.Photoacoustic, m_Conf.TransducerElements); + + if (chunkSize < oclOutputDim[2]) + { + bool skip = false; + for (unsigned int i = 0; !skip && i < ceil((float)oclOutputDim[2] / (float)chunkSize); ++i) + { + m_ProgressHandle(100 * ((float)(i * chunkSize) / (float)oclOutputDim[2]), "performing reconstruction"); + mitk::Image::Pointer chunk = mitk::Image::New(); + if ((int)((oclOutputDim[2]) - (i * chunkSize)) == (int)(1 + chunkSize)) + { + // A 3d image of 3rd dimension == 1 can not be processed by openCL, make sure that this case never arises + oclInputDimLastChunk[2] = input->GetDimension(2) % chunkSize + chunkSize; + oclOutputDimLastChunk[2] = input->GetDimension(2) % chunkSize + chunkSize; + + chunk->Initialize(input->GetPixelType(), 3, oclInputDimLastChunk); + m_oclFilter->SetOutputDim(oclOutputDimLastChunk); + skip = true; //skip the last chunk + } + else if ((oclOutputDim[2]) - (i * chunkSize) >= chunkSize) + chunk->Initialize(input->GetPixelType(), 3, oclInputDimChunk); + else + { + chunk->Initialize(input->GetPixelType(), 3, oclInputDimLastChunk); + m_oclFilter->SetOutputDim(oclOutputDimLastChunk); + } + + chunk->SetSpacing(input->GetGeometry()->GetSpacing()); + + mitk::ImageReadAccessor ChunkMove(input); + chunk->SetImportVolume((void*)&(((float*)const_cast(ChunkMove.GetData()))[i * chunkSize * input->GetDimension(0) * input->GetDimension(1)]), 0, 0, mitk::Image::ReferenceMemory); + + m_oclFilter->SetInput(chunk); + m_oclFilter->Update(); + auto out = m_oclFilter->GetOutput(); + + for (unsigned int s = i * chunkSize; s < oclOutputDim[2]; ++s) // TODO: make the bounds here smaller... + { + mitk::ImageReadAccessor copy(out, out->GetSliceData(s - i * chunkSize)); + output->SetImportSlice(const_cast(copy.GetData()), s, 0, 0, mitk::Image::ReferenceMemory); + } + } + } + else + { + m_ProgressHandle(50, "performing reconstruction"); + + m_oclFilter->SetOutputDim(oclOutputDim); + m_oclFilter->SetInput(input); + m_oclFilter->Update(); + + auto out = m_oclFilter->GetOutput(); + mitk::ImageReadAccessor copy(out); + output->SetImportVolume(const_cast(copy.GetData()), 0, 0, mitk::Image::ReferenceMemory); + } + } + catch (mitk::Exception &e) + { + std::string errorMessage = "Caught unexpected exception "; + errorMessage.append(e.what()); + MITK_ERROR << errorMessage; + } + } + + m_TimeOfHeaderInitialization.Modified(); + + auto end = std::chrono::high_resolution_clock::now(); + MITK_INFO << "Beamforming of " << output->GetDimension(2) << " Images completed in " << ((float)std::chrono::duration_cast(end - begin).count()) / 1000000 << "ms" << std::endl; +} + +void mitk::BeamformingFilter::Configure(beamformingSettings settings) +{ + m_Conf = settings; +} + +float* mitk::BeamformingFilter::VonHannFunction(int samples) +{ + float* ApodWindow = new float[samples]; + + for (int n = 0; n < samples; ++n) + { + ApodWindow[n] = (1 - cos(2 * M_PI * n / (samples - 1))) / 2; + } + + return ApodWindow; +} + +float* mitk::BeamformingFilter::HammFunction(int samples) +{ + float* ApodWindow = new float[samples]; + + for (int n = 0; n < samples; ++n) + { + ApodWindow[n] = 0.54 - 0.46*cos(2 * M_PI*n / (samples - 1)); + } + + return ApodWindow; +} + +float* mitk::BeamformingFilter::BoxFunction(int samples) +{ + float* ApodWindow = new float[samples]; + + for (int n = 0; n < samples; ++n) + { + ApodWindow[n] = 1; + } + + return ApodWindow; +} + +void mitk::BeamformingFilter::DASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short AddSample = 0; + short maxLine = 0; + short minLine = 0; + float delayMultiplicator = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * m_Conf.ReconstructionLines / m_Conf.TransducerElements; + float apod_mult = 1; + + short usedLines = (maxLine - minLine); + + //quadratic delay + l_i = line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = apodArraySize / (maxLine - minLine); + + delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; + + for (short l_s = minLine; l_s < maxLine; ++l_s) + { + AddSample = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1 - m_Conf.Photoacoustic)*s_i; + if (AddSample < inputS && AddSample >= 0) + output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; + else + --usedLines; + } + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; + } +} + +void mitk::BeamformingFilter::DASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short AddSample = 0; + short maxLine = 0; + short minLine = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * m_Conf.ReconstructionLines / m_Conf.TransducerElements; + float apod_mult = 1; + + short usedLines = (maxLine - minLine); + + //exact delay + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = apodArraySize / (maxLine - minLine); + + for (short l_s = minLine; l_s < maxLine; ++l_s) + { + AddSample = (int)sqrt( + pow(s_i, 2) + + + pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * ((l_s - l_i)*m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) + ) + (1 - m_Conf.Photoacoustic)*s_i; + if (AddSample < inputS && AddSample >= 0) + output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; + else + --usedLines; + } + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; + } +} + +void mitk::BeamformingFilter::DMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float delayMultiplicator = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * m_Conf.ReconstructionLines / m_Conf.TransducerElements; + float apod_mult = 1; + + float mult = 0; + short usedLines = (maxLine - minLine); + + //quadratic delay + l_i = line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = apodArraySize / (maxLine - minLine); + + delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + (1 - m_Conf.Photoacoustic)*s_i; + } + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < (short)inputS && AddSample[l_s1 - minLine] >= 0) + { + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + mult = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL] * apodisation[(short)((l_s2 - minLine)*apod_mult)] * input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL] * apodisation[(short)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(abs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = 10 * output[sample*(short)outputL + line] / (pow(usedLines, 2) - (usedLines - 1)); + + delete[] AddSample; + } +} + +void mitk::BeamformingFilter::DMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) +{ + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * M_PI); + float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * m_Conf.ReconstructionLines / m_Conf.TransducerElements; + float apod_mult = 1; + + float mult = 0; + + short usedLines = (maxLine - minLine); + + //exact delay + + l_i = line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = sample / outputS * inputS / 2; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = apodArraySize / (maxLine - minLine); + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)sqrt( + pow(s_i, 2) + + + pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * ((minLine + l_s - l_i)*m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) + ) + (1 - m_Conf.Photoacoustic)*s_i; + } + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) + { + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + mult = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL] * apodisation[(int)((l_s2 - minLine)*apod_mult)] * input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL] * apodisation[(int)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(abs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = 10 * output[sample*(short)outputL + line] / (pow(usedLines, 2) - (usedLines - 1)); + + delete[] AddSample; + } +} diff --git a/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.h b/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.h new file mode 100644 index 0000000000..e2654fc7fd --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Algorithms/mitkPhotoacousticBeamformingFilter.h @@ -0,0 +1,108 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +#ifndef MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER +#define MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER + +#include "mitkImageToImageFilter.h" +#include + +namespace mitk { + + //##Documentation + //## @brief + //## @ingroup Process + class BeamformingFilter : public ImageToImageFilter + { + public: + mitkClassMacro(BeamformingFilter, ImageToImageFilter); + + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + struct beamformingSettings + { + float Pitch = 0.0003; // [m] + float SpeedOfSound = 1540; // [m/s] + unsigned int SamplesPerLine = 2048; + unsigned int ReconstructionLines = 128; + float RecordTime = 0.00006; // [s] + float TimeSpacing = 0.0000000000001; // [s] + unsigned int TransducerElements = 128; + bool partial = false; + unsigned int CropBounds[2] = { 0,0 }; + + bool UseGPU = true; + + enum DelayCalc {QuadApprox, Spherical}; + DelayCalc DelayCalculationMethod = QuadApprox; + + enum Apodization {Hamm, Hann, Box}; + Apodization Apod = Hann; + + enum BeamformingAlgorithm {DMAS, DAS}; + BeamformingAlgorithm Algorithm = DAS; + + float Angle = 10; + bool Photoacoustic = true; + float BPHighPass = 50; + float BPLowPass = 50; + bool UseBP = false; + }; + + void Configure(beamformingSettings settings); + + void SetProgressHandle(std::function progressHandle); + + protected: + + BeamformingFilter(); + + ~BeamformingFilter(); + + virtual void GenerateInputRequestedRegion() override; + + virtual void GenerateOutputInformation() override; + + virtual void GenerateData() override; + + //##Description + //## @brief Time when Header was last initialized + itk::TimeStamp m_TimeOfHeaderInitialization; + + std::function m_ProgressHandle; + + float* VonHannFunction(int samples); + float* HammFunction(int samples); + float* BoxFunction(int samples); + + void DASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + void DASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + + void DMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + void DMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); + + float* m_OutputData; + float* m_InputData; + float* m_InputDataPuffer; + + beamformingSettings m_Conf; + }; + +} // namespace mitk + +#endif //MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER diff --git a/Modules/PhotoacousticsAlgorithms/CMakeLists.txt b/Modules/PhotoacousticsAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000..a1bd2a69cf --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/CMakeLists.txt @@ -0,0 +1,8 @@ +MITK_CREATE_MODULE( + SUBPROJECTS + DEPENDS MitkCore MitkAlgorithmsExt MitkOpenCL + #AUTOLOAD_WITH MitkCore + INCLUDE_DIRS PUBLIC Algorithms/ITKUltrasound Algorithms Algorithms/OCL + INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} + PACKAGE_DEPENDS ITK|ITKFFT+ITKImageCompose+ITKImageIntensity +) diff --git a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl new file mode 100644 index 0000000000..ce692acbb6 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl @@ -0,0 +1,41 @@ +/*=================================================================== + +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. + +===================================================================*/ + +__kernel void ckBmodeAbs( + __read_only image3d_t dSource, // input image + __global float* dDest // output buffer +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + unsigned int globalPosZ = get_global_id(2); + + // get image width and weight + const unsigned int inputL = get_image_width( dSource ); + const unsigned int inputS = get_image_height( dSource ); + const unsigned int Slices = get_image_depth( dSource ); + + // create an image sampler + const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; + + // terminate non-valid threads + if ( globalPosX < inputL && globalPosY < inputS && globalPosZ < Slices ) + { + + dDest[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ] = fabs(read_imagef( dSource, defaultSampler, (int4)(globalPosX, globalPosY, globalPosZ, 0 )).x); + } +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl new file mode 100644 index 0000000000..1daa1709e1 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl @@ -0,0 +1,40 @@ +/*=================================================================== + +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. + +===================================================================*/ + +__kernel void ckBmodeAbsLog( + __read_only image3d_t dSource, // input image + __global float* dDest // output buffer +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + unsigned int globalPosZ = get_global_id(2); + + // get image width and weight + const unsigned int inputL = get_image_width( dSource ); + const unsigned int inputS = get_image_height( dSource ); + const unsigned int Slices = get_image_depth( dSource ); + + // create an image sampler + const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; + + // terminate non-valid threads + if ( globalPosX < inputL && globalPosY < inputS && globalPosZ < Slices ) + { + dDest[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ] = log(fabs((float)read_imagef( dSource, defaultSampler, (int4)(globalPosX, globalPosY, globalPosZ, 0 )).x)); + } +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DASQuadratic.cl b/Modules/PhotoacousticsAlgorithms/Resources/DASQuadratic.cl new file mode 100644 index 0000000000..8afda8ff42 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/DASQuadratic.cl @@ -0,0 +1,76 @@ +/*=================================================================== + +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. + +===================================================================*/ + +__kernel void ckDASQuad( + __read_only image3d_t dSource, // input image + __global float* dDest, // output buffer + __global float* apodArray, + unsigned short apodArraySize, + float SpeedOfSound, + float TimeSpacing, + float Pitch, + float Angle, + unsigned short PAImage, + unsigned short TransducerElements // parameters +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + unsigned int globalPosZ = get_global_id(2); + + unsigned short outputS = get_global_size(1); + unsigned short outputL = get_global_size(0); + + // get image width and weight + const unsigned int inputL = get_image_width( dSource ); + const unsigned int inputS = get_image_height( dSource ); + const unsigned int Slices = get_image_depth( dSource ); + + // create an image sampler + const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; + + // terminate non-valid threads + if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) + { + float l_i = (float)globalPosX / outputL * inputL; + float s_i = (float)globalPosY / outputS * inputS / 2; + + float part = (tan(Angle / 360 * 2 * M_PI) * TimeSpacing * SpeedOfSound / Pitch * outputL / TransducerElements) * s_i; + if (part < 1) + part = 1; + + short maxLine = min((l_i + part) + 1, (float)inputL); + short minLine = max((l_i - part), 0.0f); + short usedLines = (maxLine - minLine); + float apod_mult = apodArraySize / (maxLine - minLine); + + short AddSample = 0; + float output = 0; + float delayMultiplicator = pow(1 / (TimeSpacing*SpeedOfSound) * Pitch * TransducerElements / inputL, 2) / s_i / 2; + + for (short l_s = minLine; l_s < maxLine; ++l_s) + { + AddSample = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1-PAImage)*s_i; + if (AddSample < inputS && AddSample >= 0) + output += apodArray[(short)((l_s - minLine)*apod_mult)] * read_imagef( dSource, defaultSampler, (int4)(l_s, AddSample, globalPosZ, 0 )).x; + else + --usedLines; + } + + dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / usedLines; + } +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DASspherical.cl b/Modules/PhotoacousticsAlgorithms/Resources/DASspherical.cl new file mode 100644 index 0000000000..f9a11f7504 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/DASspherical.cl @@ -0,0 +1,79 @@ +/*=================================================================== + +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. + +===================================================================*/ + +__kernel void ckDASSphe( + __read_only image3d_t dSource, // input image + __global float* dDest, // output buffer + __global float* apodArray, + unsigned short apodArraySize, + float SpeedOfSound, + float TimeSpacing, + float Pitch, + float Angle, + unsigned short PAImage, + unsigned short TransducerElements // parameters +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + unsigned int globalPosZ = get_global_id(2); + + unsigned short outputS = get_global_size(1); + unsigned short outputL = get_global_size(0); + + // get image width and weight + const unsigned int inputL = get_image_width( dSource ); + const unsigned int inputS = get_image_height( dSource ); + const unsigned int Slices = get_image_depth( dSource ); + + // create an image sampler + const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; + + // terminate non-valid threads + if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) + { + float l_i = (float)globalPosX / outputL * inputL; + float s_i = (float)globalPosY / outputS * inputS / 2; + + float part = (tan(Angle / 360 * 2 * M_PI) * TimeSpacing * SpeedOfSound / Pitch * outputL / TransducerElements) * s_i; + if (part < 1) + part = 1; + + short maxLine = min((l_i + part) + 1, (float)inputL); + short minLine = max((l_i - part), 0.0f); + short usedLines = (maxLine - minLine); + float apod_mult = apodArraySize / (maxLine - minLine); + + short AddSample = 0; + float output = 0; + + for (short l_s = minLine; l_s < maxLine; ++l_s) + { + AddSample = sqrt( + pow(s_i, 2) + + + pow((1 / (TimeSpacing*SpeedOfSound) * ((l_s - l_i)*Pitch*TransducerElements) / inputL), 2) + ) + (1-PAImage)*s_i; + if (AddSample < inputS && AddSample >= 0) + output += apodArray[(short)((l_s - minLine)*apod_mult)] * read_imagef( dSource, defaultSampler, (int4)(l_s, AddSample, globalPosZ, 0 )).x; + else + --usedLines; + } + + dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / usedLines; + } +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DMASQuadratic.cl b/Modules/PhotoacousticsAlgorithms/Resources/DMASQuadratic.cl new file mode 100644 index 0000000000..857b988746 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/DMASQuadratic.cl @@ -0,0 +1,92 @@ +/*=================================================================== + +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. + +===================================================================*/ + +__kernel void ckDMASQuad( + __read_only image3d_t dSource, // input image + __global float* dDest, // output buffer + __global float* apodArray, + unsigned short apodArraySize, + float SpeedOfSound, + float TimeSpacing, + float Pitch, + float Angle, + unsigned short PAImage, + unsigned short TransducerElements // parameters +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + unsigned int globalPosZ = get_global_id(2); + + unsigned short outputS = get_global_size(1); + unsigned short outputL = get_global_size(0); + + // get image width and weight + const unsigned int inputL = get_image_width( dSource ); + const unsigned int inputS = get_image_height( dSource ); + const unsigned int Slices = get_image_depth( dSource ); + + // create an image sampler + const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; + + // terminate non-valid threads + if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) + { + float l_i = (float)globalPosX / outputL * inputL; + float s_i = (float)globalPosY / outputS * inputS / 2; + + float part = (tan(Angle / 360 * 2 * M_PI) * TimeSpacing * SpeedOfSound / Pitch * outputL / TransducerElements) * s_i; + if (part < 1) + part = 1; + + short maxLine = min((l_i + part) + 1, (float)inputL); + short minLine = max((l_i - part), 0.0f); + short usedLines = (maxLine - minLine); + float apod_mult = apodArraySize / (maxLine - minLine); + + float delayMultiplicator = pow((1 / (TimeSpacing*SpeedOfSound) * Pitch * TransducerElements / inputL), 2) / s_i / 2; + + float mult = 0; + float output = 0; + float AddSample1 = 0; + float AddSample2 = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + AddSample1 = delayMultiplicator * pow((l_s1 - l_i), 2) + s_i + (1-PAImage)*s_i; + if (AddSample1 < inputS && AddSample1 >= 0) + { + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + AddSample2 = delayMultiplicator * pow((l_s2 - l_i), 2) + s_i + (1-PAImage)*s_i; + if (AddSample2 < inputS && AddSample2 >= 0) + { + mult = read_imagef( dSource, defaultSampler, (int4)(l_s2, AddSample2, globalPosZ, 0 )).x + * apodArray[(short)((l_s2 - minLine)*apod_mult)] + * read_imagef( dSource, defaultSampler, (int4)(l_s1, AddSample1, globalPosZ, 0 )).x + * apodArray[(short)((l_s1 - minLine)*apod_mult)]; + output += sqrt(mult * ((float)(mult>0)-(float)(mult<0))) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = 10 * output / (pow((float)usedLines, 2.0f) - (usedLines - 1)); + } +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DMASspherical.cl b/Modules/PhotoacousticsAlgorithms/Resources/DMASspherical.cl new file mode 100644 index 0000000000..fc480b0820 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/Resources/DMASspherical.cl @@ -0,0 +1,98 @@ +/*=================================================================== + +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. + +===================================================================*/ + +__kernel void ckDMASSphe( + __read_only image3d_t dSource, // input image + __global float* dDest, // output buffer + __global float* apodArray, + unsigned short apodArraySize, + float SpeedOfSound, + float TimeSpacing, + float Pitch, + float Angle, + unsigned short PAImage, + unsigned short TransducerElements // parameters +) +{ + // get thread identifier + unsigned int globalPosX = get_global_id(0); + unsigned int globalPosY = get_global_id(1); + unsigned int globalPosZ = get_global_id(2); + + unsigned short outputS = get_global_size(1); + unsigned short outputL = get_global_size(0); + + // get image width and weight + const unsigned int inputL = get_image_width( dSource ); + const unsigned int inputS = get_image_height( dSource ); + const unsigned int Slices = get_image_depth( dSource ); + + // create an image sampler + const sampler_t defaultSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST ; + + // terminate non-valid threads + if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices ) + { + float l_i = (float)globalPosX / outputL * inputL; + float s_i = (float)globalPosY / outputS * inputS / 2; + + float part = (tan(Angle / 360 * 2 * M_PI) * TimeSpacing * SpeedOfSound / Pitch * outputL / TransducerElements) * s_i; + if (part < 1) + part = 1; + + short maxLine = min((l_i + part) + 1, (float)inputL); + short minLine = max((l_i - part), 0.0f); + short usedLines = (maxLine - minLine); + float apod_mult = apodArraySize / (maxLine - minLine); + + float mult = 0; + float output = 0; + float AddSample1 = 0; + float AddSample2 = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + AddSample1 = sqrt( + pow(s_i, 2) + + + pow((1 / (TimeSpacing*SpeedOfSound) * ((l_s1 - l_i)*Pitch*TransducerElements)/inputL), 2) + ) + (1-PAImage)*s_i; + if (AddSample1 < inputS && AddSample1 >= 0) + { + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + AddSample2 = sqrt( + pow(s_i, 2) + + + pow((1 / (TimeSpacing*SpeedOfSound) * ((l_s2 - l_i)*Pitch*TransducerElements)/inputL), 2) + ) + (1-PAImage)*s_i; + if (AddSample2 < inputS && AddSample2 >= 0) + { + mult = read_imagef( dSource, defaultSampler, (int4)(l_s2, AddSample2, globalPosZ, 0 )).x + * apodArray[(short)((l_s2 - minLine)*apod_mult)] + * read_imagef( dSource, defaultSampler, (int4)(l_s1, AddSample1, globalPosZ, 0 )).x + * apodArray[(short)((l_s1 - minLine)*apod_mult)]; + output += sqrt(mult * ((float)(mult>0)-(float)(mult<0))) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = 10 * output / (pow((float)usedLines, 2.0f) - (usedLines - 1)); + } +} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/files.cmake b/Modules/PhotoacousticsAlgorithms/files.cmake new file mode 100644 index 0000000000..08f72362af --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/files.cmake @@ -0,0 +1,18 @@ +set(CPP_FILES + mitkPhotoacousticImage.cpp + + Algorithms/mitkPhotoacousticBeamformingFilter.cpp + + Algorithms/OCL/mitkPhotoacousticOCLBeamformer.cpp + + Algorithms/OCL/mitkPhotoacousticBModeFilter.cpp +) + +set(RESOURCE_FILES + DASQuadratic.cl + DMASQuadratic.cl + DASspherical.cl + DMASspherical.cl + BModeAbs.cl + BModeAbsLog.cl +) \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp new file mode 100644 index 0000000000..9ba451e9cd --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp @@ -0,0 +1,641 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#define _USE_MATH_DEFINES +#include +#include "mitkPhotoacousticImage.h" +#include "itkBModeImageFilter.h" +#include "itkPhotoacousticBModeImageFilter.h" +#include "mitkImageCast.h" +#include "mitkITKImageImport.h" +#include "mitkPhotoacousticBeamformingFilter.h" +#include +#include +#include + + +// itk dependencies +#include "itkImage.h" +#include "itkResampleImageFilter.h" +#include "itkCastImageFilter.h" +#include "itkCropImageFilter.h" +#include "itkRescaleIntensityImageFilter.h" +#include "itkIntensityWindowingImageFilter.h" +#include +#include "itkMultiplyImageFilter.h" +#include "itkBSplineInterpolateImageFunction.h" +#include + +// needed itk image filters +#include "mitkITKImageImport.h" +#include "itkFFTShiftImageFilter.h" +#include "itkMultiplyImageFilter.h" +#include "itkComplexToModulusImageFilter.h" +#include +#include "itkFFT1DComplexConjugateToRealImageFilter.h" +#include "itkFFT1DRealToComplexConjugateImageFilter.h" + +mitk::PhotoacousticImage::PhotoacousticImage() +{ + MITK_INFO << "[PhotoacousticImage Debug] created that image"; +} + +mitk::PhotoacousticImage::~PhotoacousticImage() +{ + MITK_INFO << "[PhotoacousticImage Debug] destroyed that image"; +} + +mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method, bool UseLogFilter, float resampleSpacing) +{ + // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage + typedef itk::Image< float, 3 > itkFloatImageType; + typedef itk::IdentityTransform TransformType; + + if (method == BModeMethod::Abs) + { + auto input = ApplyCropping(inputImage, 0, 0, 0, 0, 0, inputImage->GetDimension(2) - 1); + PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); + filter->SetParameters(UseLogFilter); + filter->SetInput(input); + filter->Update(); + + auto out = filter->GetOutput(); + + if(resampleSpacing == 0) + return out; + + typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; + ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); + + itkFloatImageType::Pointer itkImage; + mitk::CastToItkImage(out, itkImage); + itkFloatImageType::SpacingType outputSpacing; + itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); + itkFloatImageType::SizeType outputSize = inputSize; + + outputSpacing[0] = itkImage->GetSpacing()[0]; + outputSpacing[1] = resampleSpacing; + outputSpacing[2] = itkImage->GetSpacing()[2]; + + outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; + + typedef itk::IdentityTransform TransformType; + resampleImageFilter->SetInput(itkImage); + resampleImageFilter->SetSize(outputSize); + resampleImageFilter->SetOutputSpacing(outputSpacing); + resampleImageFilter->SetTransform(TransformType::New()); + + resampleImageFilter->UpdateLargestPossibleRegion(); + return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); + } + else if (method == BModeMethod::ShapeDetection) + { + typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; + BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter + + typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; + PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter + + typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; + ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); + + itkFloatImageType::Pointer itkImage; + + mitk::CastToItkImage(inputImage, itkImage); + + itkFloatImageType::Pointer bmode; + + if (UseLogFilter) + { + bModeFilter->SetInput(itkImage); + bModeFilter->SetDirection(1); + bmode = bModeFilter->GetOutput(); + } + else + { + photoacousticBModeFilter->SetInput(itkImage); + photoacousticBModeFilter->SetDirection(1); + bmode = photoacousticBModeFilter->GetOutput(); + } + + // resampleSpacing == 0 means: do no resampling + if (resampleSpacing == 0) + { + return mitk::GrabItkImageMemory(bmode); + } + + itkFloatImageType::SpacingType outputSpacing; + itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); + itkFloatImageType::SizeType outputSize = inputSize; + + outputSpacing[0] = itkImage->GetSpacing()[0]; + outputSpacing[1] = resampleSpacing; + outputSpacing[2] = itkImage->GetSpacing()[2]; + + outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; + + resampleImageFilter->SetInput(bmode); + resampleImageFilter->SetSize(outputSize); + resampleImageFilter->SetOutputSpacing(outputSpacing); + resampleImageFilter->SetTransform(TransformType::New()); + + resampleImageFilter->UpdateLargestPossibleRegion(); + return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); + } + return nullptr; +} + +/*mitk::Image::Pointer mitk::PhotoacousticImage::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scattering) +{ + typedef itk::Image< float, 3 > itkFloatImageType; + typedef itk::MultiplyImageFilter MultiplyImageFilterType; + + itkFloatImageType::Pointer itkImage; + mitk::CastToItkImage(inputImage, itkImage); + + MultiplyImageFilterType::Pointer multiplyFilter = MultiplyImageFilterType::New(); + multiplyFilter->SetInput1(itkImage); + multiplyFilter->SetInput2(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); + + return mitk::GrabItkImageMemory(multiplyFilter->GetOutput()); +}*/ + +mitk::Image::Pointer mitk::PhotoacousticImage::ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]) +{ + typedef itk::Image< float, 3 > itkFloatImageType; + + typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; + ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); + typedef itk::LinearInterpolateImageFunction T_Interpolator; + itkFloatImageType::Pointer itkImage; + + mitk::CastToItkImage(inputImage, itkImage); + + itkFloatImageType::SpacingType outputSpacingItk; + itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); + itkFloatImageType::SizeType outputSizeItk = inputSizeItk; + + outputSizeItk[0] = outputSize[0]; + outputSizeItk[1] = outputSize[1]; + outputSizeItk[2] = inputSizeItk[2]; + + outputSpacingItk[0] = itkImage->GetSpacing()[0] * (static_cast(inputSizeItk[0]) / static_cast(outputSizeItk[0])); + outputSpacingItk[1] = itkImage->GetSpacing()[1] * (static_cast(inputSizeItk[1]) / static_cast(outputSizeItk[1])); + outputSpacingItk[2] = itkImage->GetSpacing()[2]; + + typedef itk::IdentityTransform TransformType; + T_Interpolator::Pointer _pInterpolator = T_Interpolator::New(); + resampleImageFilter->SetInput(itkImage); + resampleImageFilter->SetSize(outputSizeItk); + resampleImageFilter->SetOutputSpacing(outputSpacingItk); + resampleImageFilter->SetTransform(TransformType::New()); + resampleImageFilter->SetInterpolator(_pInterpolator); + + resampleImageFilter->UpdateLargestPossibleRegion(); + return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); +} + +mitk::Image::Pointer mitk::PhotoacousticImage::ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice) +{ + + unsigned int inputDim[3] = { inputImage->GetDimension(0), inputImage->GetDimension(1), inputImage->GetDimension(2) }; + unsigned int outputDim[3] = { inputImage->GetDimension(0) - left - right, inputImage->GetDimension(1) - (unsigned int)above - (unsigned int)below, (unsigned int)maxSlice - (unsigned int)minSlice + 1 }; + + void* inputData; + float* outputData = new float[outputDim[0] * outputDim[1] * outputDim[2]]; + + ImageReadAccessor acc(inputImage); + inputData = const_cast(acc.GetData()); + + // convert the data to float by default + // as of now only those float, short, float are used at all... though it's easy to add other ones + if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") + { + // copy the data into the cropped image + for (unsigned short sl = 0; sl < outputDim[2]; ++sl) + { + for (unsigned short l = 0; l < outputDim[0]; ++l) + { + for (unsigned short s = 0; s < outputDim[1]; ++s) + { + outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((float*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; + } + } + } + } + else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (short)" || inputImage->GetPixelType().GetTypeAsString() == " (short)") + { + // copy the data unsigned shorto the cropped image + for (unsigned short sl = 0; sl < outputDim[2]; ++sl) + { + for (unsigned short l = 0; l < outputDim[0]; ++l) + { + for (unsigned short s = 0; s < outputDim[1]; ++s) + { + outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((short*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; + } + } + } + } + else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (double)" || inputImage->GetPixelType().GetTypeAsString() == " (double)") + { + // copy the data unsigned shorto the cropped image + for (unsigned short sl = 0; sl < outputDim[2]; ++sl) + { + for (unsigned short l = 0; l < outputDim[0]; ++l) + { + for (unsigned short s = 0; s < outputDim[1]; ++s) + { + outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((double*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; + } + } + } + } + else + { + MITK_INFO << "Could not determine pixel type"; + } + + mitk::Image::Pointer output = mitk::Image::New(); + output->Initialize(mitk::MakeScalarPixelType(), 3, outputDim); + output->SetSpacing(inputImage->GetGeometry()->GetSpacing()); + output->SetImportVolume(outputData, 0, 0, mitk::Image::ReferenceMemory); + + return output; +} + +mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingFilter::beamformingSettings config, int cutoff, std::function progressHandle) +{ + // crop the image + // set the Maximum Size of the image to 4096 + unsigned short lowerCutoff = 0; + if (((unsigned int)(4096 + cutoff)) < inputImage->GetDimension(1)) + { + lowerCutoff = (unsigned short)(inputImage->GetDimension(1) - 4096); + } + + config.RecordTime = config.RecordTime - (cutoff + lowerCutoff) / inputImage->GetDimension(1) * config.RecordTime; // adjust the recorded time lost by cropping + progressHandle(0, "cropping image"); + if (!config.partial) + { + config.CropBounds[0] = 0; + config.CropBounds[1] = inputImage->GetDimension(2) - 1; + } + + Image::Pointer processedImage = ApplyCropping(inputImage, cutoff, lowerCutoff, 0, 0, config.CropBounds[0], config.CropBounds[1]); + + // resample the image in horizontal direction + if (inputImage->GetDimension(0) != config.ReconstructionLines) + { + progressHandle(0, "resampling image"); + auto begin = std::chrono::high_resolution_clock::now(); + unsigned int dim[2] = { config.ReconstructionLines, processedImage->GetDimension(1) }; + processedImage = ApplyResampling(processedImage, dim); + auto end = std::chrono::high_resolution_clock::now(); + MITK_DEBUG << "Upsampling from " << inputImage->GetDimension(0) << " to " << config.ReconstructionLines << " lines completed in " << ((double)std::chrono::duration_cast(end - begin).count()) / 1000000 << "ms" << std::endl; + } + + // perform the beamforming + BeamformingFilter::Pointer Beamformer = BeamformingFilter::New(); + Beamformer->SetInput(processedImage); + Beamformer->Configure(config); + Beamformer->SetProgressHandle(progressHandle); + Beamformer->UpdateLargestPossibleRegion(); + + processedImage = Beamformer->GetOutput(); + + return processedImage; +} + +mitk::Image::Pointer mitk::PhotoacousticImage::BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha) +{ + bool powerOfTwo = false; + int finalPower = 0; + for (int i = 1; pow(2, i) <= data->GetDimension(1); ++i) + { + finalPower = i; + if (pow(2, i) == data->GetDimension(1)) + { + powerOfTwo = true; + } + } + if (!powerOfTwo) + { + unsigned int dim[2] = { data->GetDimension(0), (unsigned int)pow(2,finalPower+1)}; + data = ApplyResampling(data, dim); + } + + MITK_INFO << data->GetDimension(0); + + // do a fourier transform, multiply with an appropriate window for the filter, and transform back + typedef float PixelType; + typedef itk::Image< PixelType, 3 > RealImageType; + RealImageType::Pointer image; + + mitk::CastToItkImage(data, image); + + typedef itk::FFT1DRealToComplexConjugateImageFilter ForwardFFTFilterType; + typedef ForwardFFTFilterType::OutputImageType ComplexImageType; + ForwardFFTFilterType::Pointer forwardFFTFilter = ForwardFFTFilterType::New(); + forwardFFTFilter->SetInput(image); + forwardFFTFilter->SetDirection(1); + try + { + forwardFFTFilter->UpdateOutputInformation(); + } + catch (itk::ExceptionObject & error) + { + std::cerr << "Error: " << error << std::endl; + MITK_WARN << "Bandpass could not be applied"; + return data; + } + + float singleVoxel = 1 / (recordTime / data->GetDimension(1)) / 2 / 1000; + float cutoffPixelHighPass = std::min(BPHighPass / singleVoxel, (float)data->GetDimension(1) / 2); + float cutoffPixelLowPass = std::min(BPLowPass / singleVoxel, (float)data->GetDimension(1) / 2 - cutoffPixelHighPass); + + RealImageType::Pointer fftMultiplicator = BPFunction(data, cutoffPixelHighPass, cutoffPixelLowPass, alpha); + + typedef itk::MultiplyImageFilter< ComplexImageType, + RealImageType, + ComplexImageType > + MultiplyFilterType; + MultiplyFilterType::Pointer multiplyFilter = MultiplyFilterType::New(); + multiplyFilter->SetInput1(forwardFFTFilter->GetOutput()); + multiplyFilter->SetInput2(fftMultiplicator); + + /*itk::ComplexToModulusImageFilter::Pointer toReal = itk::ComplexToModulusImageFilter::New(); + toReal->SetInput(forwardFFTFilter->GetOutput()); + return GrabItkImageMemory(toReal->GetOutput()); + return GrabItkImageMemory(fftMultiplicator); *///DEBUG + + typedef itk::FFT1DComplexConjugateToRealImageFilter< ComplexImageType, RealImageType > InverseFilterType; + InverseFilterType::Pointer inverseFFTFilter = InverseFilterType::New(); + inverseFFTFilter->SetInput(multiplyFilter->GetOutput()); + inverseFFTFilter->SetDirection(1); + + return GrabItkImageMemory(inverseFFTFilter->GetOutput()); +} + +itk::Image::Pointer mitk::PhotoacousticImage::BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha) +{ + float* imageData = new float[reference->GetDimension(0)*reference->GetDimension(1)]; + + // tukey window + float width = reference->GetDimension(1) / 2 - (float)cutoffFrequencyPixelHighPass - (float)cutoffFrequencyPixelLowPass; + float center = (float)cutoffFrequencyPixelHighPass / 2 + width / 2; + + + MITK_INFO << width << "width " << center << "center " << alpha; + + for (unsigned int n = 0; n < reference->GetDimension(1); ++n) + { + imageData[reference->GetDimension(0)*n] = 0; + } + + for (int n = 0; n < width; ++n) + { + if (n <= (alpha*(width - 1)) / 2) + { + imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(M_PI*(2 * n / (alpha*(width - 1)) - 1))) / 2; + } + else if (n >= (width - 1)*(1 - alpha / 2) && n <= (width - 1)) + { + imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(M_PI*(2 * n / (alpha*(width - 1)) + 1 - 2 / alpha))) / 2; + } + else + { + imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; + } + } + + // Butterworth-Filter + /* + // first, write the HighPass + if (cutoffFrequencyPixelHighPass != reference->GetDimension(1) / 2) + { + for (int n = 0; n < reference->GetDimension(1) / 2; ++n) + { + imageData[reference->GetDimension(0)*n] = 1 / (1 + pow( + (float)n / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelHighPass) + , 2 * butterworthOrder)); + } + } + else + { + for (int n = 0; n < reference->GetDimension(1) / 2; ++n) + { + imageData[reference->GetDimension(0)*n] = 1; + } + } + + // now, the LowPass + for (int n = 0; n < reference->GetDimension(1) / 2; ++n) + { + imageData[reference->GetDimension(0)*n] *= 1 / (1 + pow( + (float)(reference->GetDimension(1) / 2 - 1 - n) / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelLowPass) + , 2 * butterworthOrder)); + } + */ + + // mirror the first half of the image + for (unsigned int n = reference->GetDimension(1) / 2; n < reference->GetDimension(1); ++n) + { + imageData[reference->GetDimension(0)*n] = imageData[(reference->GetDimension(1) - (n + 1)) * reference->GetDimension(0)]; + } + + + // copy and paste to all lines + for (unsigned int line = 1; line < reference->GetDimension(0); ++line) + { + for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) + { + imageData[reference->GetDimension(0)*sample + line] = imageData[reference->GetDimension(0)*sample]; + } + } + + typedef itk::Image< float, 3U > ImageType; + ImageType::RegionType region; + ImageType::IndexType start; + start.Fill(0); + + region.SetIndex(start); + + ImageType::SizeType size; + size[0] = reference->GetDimension(0); + size[1] = reference->GetDimension(1); + size[2] = reference->GetDimension(2); + + region.SetSize(size); + + ImageType::SpacingType SpacingItk; + SpacingItk[0] = reference->GetGeometry()->GetSpacing()[0]; + SpacingItk[1] = reference->GetGeometry()->GetSpacing()[1]; + SpacingItk[2] = reference->GetGeometry()->GetSpacing()[2]; + + ImageType::Pointer image = ImageType::New(); + image->SetRegions(region); + image->Allocate(); + image->FillBuffer(itk::NumericTraits::Zero); + image->SetSpacing(SpacingItk); + + ImageType::IndexType pixelIndex; + + for (ImageType::IndexValueType slice = 0; slice < reference->GetDimension(2); ++slice) + { + for (ImageType::IndexValueType line = 0; line < reference->GetDimension(0); ++line) + { + for (ImageType::IndexValueType sample = 0; sample < reference->GetDimension(1); ++sample) + { + pixelIndex[0] = line; + pixelIndex[1] = sample; + pixelIndex[2] = slice; + + image->SetPixel(pixelIndex, imageData[line + sample*reference->GetDimension(0)]); + } + } + } + + delete[] imageData; + + return image; +} + + +/* +mitk::CropFilter::CropFilter() + : m_PixelCalculation(NULL) +{ + this->AddSourceFile("CropFilter.cl"); + + this->m_FilterID = "CropFilter"; +} + +mitk::CropFilter::~CropFilter() +{ + if (this->m_PixelCalculation) + { + clReleaseKernel(m_PixelCalculation); + } +} + +void mitk::CropFilter::Update() +{ + //Check if context & program available + if (!this->Initialize()) + { + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + // clean-up also the resources + resources->InvalidateStorage(); + mitkThrow() << "Filter is not initialized. Cannot update."; + } + else { + // Execute + this->Execute(); + } +} + +void mitk::CropFilter::Execute() +{ + cl_int clErr = 0; + + try + { + this->InitExec(this->m_PixelCalculation); + } + catch (const mitk::Exception& e) + { + MITK_ERROR << "Catched exception while initializing filter: " << e.what(); + return; + } + + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + cl_context gpuContext = resources->GetContext(); + + unsigned int size = m_OutputDim[0] * m_OutputDim[1] * m_OutputDim[2] * m_Images; + + cl_mem cl_input = clCreateBuffer(gpuContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * size, m_Data, &clErr); + CHECK_OCL_ERR(clErr); + + // set kernel arguments + clErr = clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_mem), &cl_input); + clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_ushort), &(this->m_Images)); + + CHECK_OCL_ERR(clErr); + + // execute the filter on a 3D NDRange + this->ExecuteKernel(m_PixelCalculation, 3); + + // signalize the GPU-side data changed + m_Output->Modified(GPU_DATA); +} + +us::Module *mitk::CropFilter::GetModule() +{ + return us::GetModuleContext()->GetModule(); +} + +bool mitk::CropFilter::Initialize() +{ + bool buildErr = true; + cl_int clErr = 0; + + if (OclFilter::Initialize()) + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckCrop", &clErr); + buildErr |= CHECK_OCL_ERR(clErr); + } + return (OclFilter::IsInitialized() && buildErr); +} + +void mitk::CropFilter::SetInput(mitk::Image::Pointer image) +{ + if (image->GetDimension() != 3) + { + mitkThrowException(mitk::Exception) << "Input for " << this->GetNameOfClass() << + " is not 3D. The filter only supports 3D. Please change your input."; + } + OclImageToImageFilter::SetInput(image); +} + +mitk::Image::Pointer mitk::CropFilter::GetOutput() +{ + if (m_Output->IsModified(GPU_DATA)) + { + void* pData = m_Output->TransferDataToCPU(m_CommandQue); + + const unsigned int dimension = 3; + unsigned int* dimensions = m_OutputDim; + + const mitk::SlicedGeometry3D::Pointer p_slg = m_Input->GetMITKImage()->GetSlicedGeometry(); + + MITK_DEBUG << "Creating new MITK Image."; + + m_Output->GetMITKImage()->Initialize(this->GetOutputType(), dimension, dimensions); + m_Output->GetMITKImage()->SetSpacing(p_slg->GetSpacing()); + m_Output->GetMITKImage()->SetGeometry(m_Input->GetMITKImage()->GetGeometry()); + m_Output->GetMITKImage()->SetImportVolume(pData, 0, 0, mitk::Image::ReferenceMemory); + } + + MITK_DEBUG << "Image Initialized."; + + return m_Output->GetMITKImage(); +} + +*/ diff --git a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h new file mode 100644 index 0000000000..daab4a43cf --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h @@ -0,0 +1,53 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +#ifndef mitkPhotoacousticImage_H_HEADER_INCLUDED +#define mitkPhotoacousticImage_H_HEADER_INCLUDED + +#include "itkObject.h" +#include "mitkCommon.h" +#include "mitkImage.h" +#include +#include "mitkOclImageToImageFilter.h" + +#include "mitkPhotoacousticBeamformingFilter.h" + +#include "MitkPhotoacousticsAlgorithmsExports.h" + +namespace mitk { + + class MITKPHOTOACOUSTICSALGORITHMS_EXPORT PhotoacousticImage : public itk::Object + { + public: + mitkClassMacroItkParent(mitk::PhotoacousticImage, itk::Object); + itkFactorylessNewMacro(Self); + enum BModeMethod { ShapeDetection, Abs }; + mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method = BModeMethod::Abs, bool UseLogFilter = false, float resampleSpacing = 0.15); +// mitk::Image::Pointer ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scatteringCoefficient); + mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]); + mitk::Image::Pointer ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingFilter::beamformingSettings config, int cutoff, std::function progressHandle = [](int, std::string) {}); + mitk::Image::Pointer ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice); + mitk::Image::Pointer BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha); + protected: + PhotoacousticImage(); + virtual ~PhotoacousticImage(); + + itk::Image::Pointer BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha); + }; +} // namespace mitk + +#endif /* mitkPhotoacousticImage_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsHardware/CMakeLists.txt b/Modules/PhotoacousticsHardware/CMakeLists.txt new file mode 100644 index 0000000000..e8a74022ed --- /dev/null +++ b/Modules/PhotoacousticsHardware/CMakeLists.txt @@ -0,0 +1,24 @@ +IF(WIN32) + +OPTION(MITK_USE_OPOTEK_HARDWARE "Enable support for OPOTEK Lasers" OFF) +OPTION(MITK_USE_OPHIR_PRYO_HARDWARE "Enable support for Ophir Pyroelectrical Sensors" OFF) + +IF(MITK_USE_OPHIR_PRYO_HARDWARE) +SET(MITK_OPHIR_API_PATH "" CACHE PATH "Path to Ophir API lib.") +ENDIF(MITK_USE_OPHIR_PRYO_HARDWARE) + +IF(MITK_USE_OPOTEK_HARDWARE) +SET(MITK_GALIL_API_PATH "" CACHE PATH "Path to Galil API header files.") + +MITK_CREATE_MODULE( + SUBPROJECTS + DEPENDS MitkIGT + INCLUDE_DIRS PUBLIC "${MITK_GALIL_API_PATH}/include" "${MITK_OPHIR_API_PATH}" + INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} + ADDITIONAL_LIBS "${MITK_GALIL_API_PATH}/lib/dynamic/x64/gclib.lib" "${MITK_GALIL_API_PATH}/lib/dynamic/x64/gclibo.lib" tinyxml "${MITK_OPHIR_API_PATH}/OphirPyroWrapper.lib" + PACKAGE_DEPENDS tinyxml +) + +ENDIF(MITK_USE_OPOTEK_HARDWARE) + +ENDIF(WIN32) \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/OphirCppWrapper/ConsoleExample.cpp b/Modules/PhotoacousticsHardware/OphirCppWrapper/ConsoleExample.cpp new file mode 100644 index 0000000000..8571245a98 --- /dev/null +++ b/Modules/PhotoacousticsHardware/OphirCppWrapper/ConsoleExample.cpp @@ -0,0 +1,87 @@ +/*=================================================================== + +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 "OphirPyroWrapper.h" +#include + +int main() +{ + OphirPyroWrapper pyro; + + char* sn = pyro.ScanUSB(); + if (sn != 0) + std::cout << "sn: " << sn << std::endl; + else + std::cout << "sn: NULL" << std::endl; + + int handle = pyro.OpenDevice(sn); + std::cout << "handle: " << handle << std::endl; + + char* wl = pyro.GetWavelengths(handle); + std::cout << "wl: " << wl << std::endl; + char* gr = pyro.GetRanges(handle); + std::cout << "gr: " << gr << std::endl; + + bool start = pyro.StartStream(handle); + std::cout << "start: " << start << std::endl; + + std::vector data; + std::vector timestamp; + std::vector status; + Sleep(100); + unsigned int gd = pyro.GetData(handle, &data, ×tamp, &status); + std::cout << "gd: " << gd << std::endl; + std::cout << "length: " << data.size() << std::endl; + for(int i = 0; i +#include +#include "OphirPyroWrapper.h" + +using namespace System::Runtime::InteropServices; // Marshal + +class OphirPyroWrapperPrivate +{ + public: msclr::auto_gcroot ophirAPI; +}; + +OphirPyroWrapper::OphirPyroWrapper() +{ + _private = new OphirPyroWrapperPrivate(); + _private->ophirAPI = gcnew OphirLMMeasurementLib::CoLMMeasurement(); +} + +OphirPyroWrapper::~OphirPyroWrapper() +{ + delete _private; +} + +char* OphirPyroWrapper::ScanUSB() +{ + char* foo; + System::Object^ managedObject; + _private->ophirAPI->ScanUSB(managedObject); + array^ managedCapi = dynamic_cast^>(managedObject); + if (managedCapi->Length != 0) + return (char*)Marshal::StringToHGlobalAnsi(managedCapi[0]).ToPointer(); + else + return 0; +} + +int OphirPyroWrapper::OpenDevice(char* serialNumber) +{ + int deviceHandle; + _private->ophirAPI->OpenUSBDevice(gcnew System::String(serialNumber), deviceHandle); + + return deviceHandle; +} + +char* OphirPyroWrapper::GetWavelengths(int deviceHandle) +{ + int index; + System::Object^ options; + // Show wavelengths of channel 0 + _private->ophirAPI->GetWavelengths(deviceHandle, 0, index, options); + array^ managedCapi = dynamic_cast^>(options); + if (managedCapi->Length != 0) + return (char*)Marshal::StringToHGlobalAnsi(managedCapi[index]).ToPointer(); + else + return 0; +} + +char* OphirPyroWrapper::GetRanges(int deviceHandle) +{ + int index; + System::Object^ options; + // Show ranges of channel 0 + _private->ophirAPI->GetRanges(deviceHandle, 0, index, options); + array^ managedCapi = dynamic_cast^>(options); + if (managedCapi->Length != 0) + return (char*)Marshal::StringToHGlobalAnsi(managedCapi[index]).ToPointer(); + else + return 0; +} + +bool OphirPyroWrapper::StartStream(int deviceHandle) +{ + _private->ophirAPI->StartStream(deviceHandle, 0); + return true; +} + +bool OphirPyroWrapper::StopStream(int deviceHandle) +{ + _private->ophirAPI->StopStream(deviceHandle, 0); + return true; +} + +bool OphirPyroWrapper::CloseDevice(int deviceHandle) +{ + _private->ophirAPI->Close(deviceHandle); + return true; +} + +unsigned int OphirPyroWrapper::GetData(int deviceHandle, std::vector* data, std::vector* timestamp, std::vector* status) +{ + System::Object^ dataArray; + System::Object^ timeStampArray; + System::Object^ statusArray; + array^ managedDataArray; + array^ managedTimeStampArray; + array^ managedStatusArray; + _private->ophirAPI->GetData(deviceHandle, 0, dataArray, timeStampArray, statusArray); + managedDataArray = (array^)dataArray; + managedTimeStampArray = (array^)timeStampArray; + managedStatusArray = (array^)statusArray; + if (managedDataArray->Length > 0) + { + data->resize(managedDataArray->Length); + timestamp->resize(managedDataArray->Length); + status->resize(managedDataArray->Length); + for(int i = 0; iLength; i++) + { + (*data)[i] = managedDataArray[i]; + (*timestamp)[i] = managedTimeStampArray[i]; + (*status)[i] = managedStatusArray[i]; + // DEBUG: std::cout << "managedDataArray " << i << ": " << managedDataArray[i] << " ts: " << managedTimeStampArray[i] << " status: " << managedStatusArray[i] << std::endl; + } + return managedDataArray->Length; + } + else + { + data->resize(1); + timestamp->resize(1); + status->resize(1); + (*data)[0] = -1; + (*timestamp)[0] = -1; + (*status)[0] = -1; + } + + return 0; +} \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/OphirCppWrapper/OphirPyroWrapper.h b/Modules/PhotoacousticsHardware/OphirCppWrapper/OphirPyroWrapper.h new file mode 100644 index 0000000000..1420071c1a --- /dev/null +++ b/Modules/PhotoacousticsHardware/OphirCppWrapper/OphirPyroWrapper.h @@ -0,0 +1,44 @@ +/*=================================================================== + +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 + +class OphirPyroWrapperPrivate; + +class __declspec(dllexport) OphirPyroWrapper +{ + private: OphirPyroWrapperPrivate* _private; + + public: OphirPyroWrapper(); + + public: ~OphirPyroWrapper(); + + public: char* ScanUSB(); + + public: int OpenDevice(char* serialNumber); + + public: char* GetWavelengths(int deviceHandle); + + public: char* GetRanges(int deviceHandle); + + public: bool StartStream(int deviceHandle); + + public: bool StopStream(int deviceHandle); + + public: bool CloseDevice(int deviceHandle); + + public: unsigned int GetData(int deviceHandle, std::vector* data, std::vector* timestamp, std::vector* status); +}; \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/OphirCppWrapper/readme.txt b/Modules/PhotoacousticsHardware/OphirCppWrapper/readme.txt new file mode 100644 index 0000000000..312e900b17 --- /dev/null +++ b/Modules/PhotoacousticsHardware/OphirCppWrapper/readme.txt @@ -0,0 +1,16 @@ +A C++/CLI Wrapper for Ophir Pyroelectrical Sensors + +compile release version of wapper via: cl /clr /LD OphirPyroWrapper.cpp +compile debug version of wapper via: cl /clr /LDd OphirPyroWrapper.cpp +you'll need: Interop.OphirLMMeasurementLib.dll + +compile shitty console example via: cl ConsoleExample.cpp OphirPyroWrapper.lib + +tested with: +VS2015, Windows 10 + 8, Starlab 3.20 + +todo: +- write documentation + +thanks to: +pragmateek for http://pragmateek.com/using-c-from-native-c-with-the-help-of-ccli-v2/ \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/FTUNE.dmc b/Modules/PhotoacousticsHardware/Resources/FTUNE.dmc new file mode 100644 index 0000000000..454e5dacab --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/FTUNE.dmc @@ -0,0 +1,57 @@ +#AUTO +#MAIN +WT 1 +'AMP SETTINGS +AU 0 +BR 1 +AG 0 +TM 1000 +TL 3 +TK 9.998 +' +'GENERAL SETTINGS +ER 10000 +OE 1 +MT -1 +CE 0 +CN-1 +'PID PARAMETERS +KD 17.5 +KP 15 +KI 0 +' +SHX +WT 10 +JS#HOME +WT 10 +JS#RESETP +WT 10 +' +SP 3000000 +AC 60000000 +DC 60000000 +count=0 +idx=0 +#MOVE +II 1 +WT 5 +JP #MOVE +EN +#HOME +OE 0 +JG -10000;BG +#JOG;JP#JOG,@ABS[_TEX]<1000 +ST;AM +OE 1 +WT 10 +EN +#RESETP +PR 32561;BG;AM +DP*=0 +EN +#ININT +idx = count % points +PA pos[idx];BG;AM; +WT 10 +count = count + 1 +RI 1; diff --git a/Modules/PhotoacousticsHardware/Resources/GHOME.dmc b/Modules/PhotoacousticsHardware/Resources/GHOME.dmc new file mode 100644 index 0000000000..7900469823 --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/GHOME.dmc @@ -0,0 +1,44 @@ +#AUTO +#MAIN +#GHOME +suc=99 +'AMP SETTINGS +AU 0 +BR 1 +AG 0 +TM 1000 +TL 3 +TK 9.998 +suc=98 +' +'GENERAL SETTINGS +ER 10000 +OE 1 +MT -1 +CE 0 +CN-1 +suc=97 +'PID PARAMETERS +KD 17.5 +KP 15 +KI 0 +suc=96 +SHX +WT 10 +SP 3000000 +AC 60000000 +DC 60000000 +' +suc=95 +OE 0 +JG -10000;BG +#JOG;JP#JOG,@ABS[_TEX]<1000 +ST;AM +suc=94 +OE 1 +WT10 +PR 32561;BG;AM +suc=93 +DP*=0 +suc=1 +EN diff --git a/Modules/PhotoacousticsHardware/Resources/OpotekPhocusMobile.xml b/Modules/PhotoacousticsHardware/Resources/OpotekPhocusMobile.xml new file mode 100644 index 0000000000..37242e3275 --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/OpotekPhocusMobile.xml @@ -0,0 +1,42 @@ + + + + -3.26731848e+07 + 2.35443306e+05 + -7.04376397e+02 + 1.12232174e+00 + -1.00519593e-03 + 4.79945765e-07 + -9.54424480e-11 + 32561 + + + 690.000 + 750.000 + 950.000 + + + 5 + 115200 + 8 + 0 + 10 + + + 690.0|695.2|700.4|705.6|710.8|716.0|721.2|726.4|731.6|736.8|742.0|747.2|752.4|757.6|762.8|768.0|773.2|778.4|783.6|788.8|794.0|799.2|804.4|809.6|814.8|820.0|825.2|830.4|835.6|840.8|846.0|851.2|856.4|861.6|866.8|872.0|877.2|882.4|887.6|892.8|898.0|903.2|908.4|913.6|918.8|924.0|929.2|934.4|939.6|944.8 + + 0.000727|0.000726|0.000764|0.000795|0.000824|0.000817|0.000832|0.000893|0.000898|0.000881|0.000870|0.000834|0.000849|0.000793|0.000778|0.000753|0.000755|0.000812|0.000843|0.000818|0.000843|0.000824|0.000829|0.000837|0.000832|0.000796|0.000808|0.000796|0.000774|0.000778|0.000760|0.000741|0.000724|0.000725|0.000703|0.000703|0.000695|0.000697|0.000671|0.000702|0.000679|0.000671|0.000676|0.000647|0.000660|0.000674|0.000686|0.000664|0.000658|0.000643 + + 0.042647|0.043251|0.045291|0.047462|0.048515|0.049305|0.049513|0.050434|0.049656|0.050895|0.048269|0.049129|0.050182|0.049334|0.046761|0.045675|0.045061|0.049129|0.050357|0.049206|0.050050|0.048745|0.048822|0.049041|0.048976|0.047813|0.047082|0.046980|0.046980|0.046442|0.045445|0.044063|0.043909|0.042451|0.041058|0.041760|0.042374|0.041683|0.040269|0.042374|0.041299|0.038996|0.041069|0.040736|0.039994|0.040839|0.040225|0.039994|0.038613|0.037692 + + + + + + 4 + 115200 + 8 + N + 1 + + \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/STUNE.dmc b/Modules/PhotoacousticsHardware/Resources/STUNE.dmc new file mode 100644 index 0000000000..edc14db0ae --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/STUNE.dmc @@ -0,0 +1,34 @@ +#AUTO +#STUNE +suc=-1 +'***************** +'AMP SETTINGS +AU 0 +BR 1 +AG 0 +TM 1000 +TL 3 +TK 9.998 +' +'GENERAL SETTINGS +ER 10000 +OE 1 +MT -1 +CE 0 +CN-1 +'PID PARAMETERS +KD 17.5 +KP 15 +KI 0 +' +SHX +WT 10 +SP 3000000 +AC 60000000 +DC 60000000 +' +suc=-102 +WT 10 +PA pos;BG;AM +suc=1 +EN diff --git a/Modules/PhotoacousticsHardware/Resources/configFastTuneOPO.dmc b/Modules/PhotoacousticsHardware/Resources/configFastTuneOPO.dmc new file mode 100644 index 0000000000..e60875bc93 --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/configFastTuneOPO.dmc @@ -0,0 +1,28 @@ +#AUTO +#MAIN +rt=-1 +II1 +'AMP SETTINGS +AU 0 +BR 1 +'AG 0 +TM 1000 +TL 3 +TK 9.998 +' +'GENERAL SETTINGS +ER 10000 +OE 1 +'MT -1 +'CE 0 +CN-1 +'PID PARAMETERS +KD 17.5 +KP 15 +KI 0 +' +SHX +WT 250 +SP 3000000 +AC 120000000 +DC 120000000 \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/configSlowTuneOPO.dmc b/Modules/PhotoacousticsHardware/Resources/configSlowTuneOPO.dmc new file mode 100644 index 0000000000..91b36d58b1 --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/configSlowTuneOPO.dmc @@ -0,0 +1,7 @@ +#AUTO +#MAIN +rt=0 +' +SP 150000 +AC 12000000 +DC 12000000 \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/executeFastTuneOPO.dmc b/Modules/PhotoacousticsHardware/Resources/executeFastTuneOPO.dmc new file mode 100644 index 0000000000..e616d85969 --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/executeFastTuneOPO.dmc @@ -0,0 +1,14 @@ +points=pos[-1] +#MOVE +II 1 +WT 5 +rt=1 +JP #MOVE +EN +#ININT +idx = count % points +PA pos[idx];BG;AM; +BG;AM; +count = count + 1 +WT 1 +RI 1; \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/executeSlowTuneOPO.dmc b/Modules/PhotoacousticsHardware/Resources/executeSlowTuneOPO.dmc new file mode 100644 index 0000000000..741d78c64d --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/executeSlowTuneOPO.dmc @@ -0,0 +1,5 @@ +PA pos;BG;AM; +BG;AM; +WT 100 +rt = 1 +EN \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/fastTuneOPO.dmc b/Modules/PhotoacousticsHardware/Resources/fastTuneOPO.dmc new file mode 100644 index 0000000000..e2d7463d93 --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/fastTuneOPO.dmc @@ -0,0 +1,55 @@ +#AUTO +#FTUNE +rt=-1 +II1 +'AMP SETTINGS +AU 0 +BR 1 +'AG 0 +TM 1000 +TL 3 +TK 9.998 +' +'GENERAL SETTINGS +ER 10000 +OE 1 +'MT -1 +'CE 0 +CN-1 +'PID PARAMETERS +KD 17.5 +KP 15 +KI 0 +' +SHX +WT 250 +SP 3000000 +AC 120000000 +DC 120000000 +rt=-2 +count=0;idx=0;DM pos[2] +rt=-3 +pos[0]=36459 +pos[1]=24577 +rt=-4 +points=pos[-1] +rt=-5 +#MOVE +rt=-6 +II 1 +WT 5 +rt=1 +JP #MOVE +EN +#ININT +'MG "INSIDE INTERUPPT ROUTINE" +rt=-7 +idx = count % points +MG "idx = ", idx {F2.2} +PA pos[idx];BG;AM; +BG;AM; +rt=-8 +count = count + 1 +WT 1 +RI 1; 'Return to the main program +'and restore trip point \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/fastTuneOPO700to900.dmc b/Modules/PhotoacousticsHardware/Resources/fastTuneOPO700to900.dmc new file mode 100644 index 0000000000..10c65430d7 --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/fastTuneOPO700to900.dmc @@ -0,0 +1,48 @@ +#AUTO +#MAIN +rt=-1 +II1 +'AMP SETTINGS +AU 0 +BR 1 +'AG 0 +TM 1000 +TL 3 +TK 9.998 +' +'GENERAL SETTINGS +ER 10000 +OE 1 +'MT -1 +'CE 0 +CN-1 +'PID PARAMETERS +KD 17.5 +KP 15 +KI 0 +' +SHX +WT 250 +SP 3000000 +AC 120000000 +DC 120000000 +count=0;idx=0;DM pos[2] +pos[0]=36459 +pos[1]=24577 +points=pos[-1] +#MOVE +II 1 +WT 5 +rt=1 +JP #MOVE +EN +#ININT +'MG "INSIDE INTERUPPT ROUTINE" +idx = count % points +MG "idx = ", idx {F2.2} +PA pos[idx];BG;AM; +BG;AM; +count = count + 1 +WT 1 +RI 1; 'Return to the main program +'and restore trip point \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/homeOPO.dmc b/Modules/PhotoacousticsHardware/Resources/homeOPO.dmc new file mode 100644 index 0000000000..80ef2aaaba --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/homeOPO.dmc @@ -0,0 +1,35 @@ +#AUTO +#MAIN +rh=-1 +'***************** +'AMP SETTINGS +AU 0 +BR 1 +'AG 0 +TM 1000 +TL 3 +TK 9.998 +' +'GENERAL SETTINGS +ER 10000 +OE 1 +'MT -1 +'CE 0 +CN-1 +'PID PARAMETERS +KD 17.5 +KP 15 +KI 0 +' +SHX +WT 250 +' +OE 0 +JG -10000;BG +#JOG;JP#JOG,@ABS[_TEX]<1000 +ST;AM +OE 1 +WT 100 +DP*=0 +rh=1 +EN diff --git a/Modules/PhotoacousticsHardware/Resources/opotekPhocusMobileDkfz160907.ini b/Modules/PhotoacousticsHardware/Resources/opotekPhocusMobileDkfz160907.ini new file mode 100644 index 0000000000..d2d84f4cfd --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/opotekPhocusMobileDkfz160907.ini @@ -0,0 +1,747 @@ +[Index] +Motor Config Size=6 +Current Config=0 +Show Spectrometer=FALSE + +[Software Version] +Software Version="1.3.2" + +[Motor Config 0] +Double BL=1 +Name="SIGNAL" +Default Wavelength=750.000000 +Motor 0 Equation=1 +Motor 0 Coeff="-10034351.9962601084000000000|66823.5712450537248000000|-182.2028426992165750000|0.2617740803347156640|-0.0002092387122824080|0.0000000881876090298|-0.0000000000152863918|146.4419507104903460000" +Motor 0 Speed=150.000000 +Motor 0 Acceleration=10.000000 +Motor 0 Current=0.600000 +Motor 0 Home=0 +Motor 0 BL Size=0 +Motor 0 BL Dir=1 +Motor 0 Max Step=50000 +Motor 0 Min Step=0 +Motor 0 Mix WL=1064.000000 +Motor 0 Name="OPO" +Motor 0 Park=0 +Motor 0 Ramp=150.000000 +Motor 0 Slope=10.000000 +Motor 0 First=0.600000 +Motor 1 Equation=0 +Motor 1 Coeff="" +Motor 1 Speed=150.000000 +Motor 1 Acceleration=10.000000 +Motor 1 Current=0.600000 +Motor 1 Home=0 +Motor 1 BL Size=650 +Motor 1 BL Dir=1 +Motor 1 Max Step=69000 +Motor 1 Min Step=-200 +Motor 1 Mix WL=1064.000000 +Motor 1 Name="UV" +Motor 1 Park=0 +Motor 1 Ramp=150.000000 +Motor 1 Slope=10.000000 +Motor 1 First=0.600000 +Motor 2 Equation=0 +Motor 2 Coeff="" +Motor 2 Speed=150.000000 +Motor 2 Acceleration=10.000000 +Motor 2 Current=0.600000 +Motor 2 Home=0 +Motor 2 BL Size=650 +Motor 2 BL Dir=1 +Motor 2 Max Step=200000 +Motor 2 Min Step=-20000 +Motor 2 Mix WL=1064.000000 +Motor 2 Name="Beamguide" +Motor 2 Park=0 +Motor 2 Ramp=150.000000 +Motor 2 Slope=10.000000 +Motor 2 First=0.600000 +Motor 3 Equation=0 +Motor 3 Coeff="" +Motor 3 Speed=150.000000 +Motor 3 Acceleration=10.000000 +Motor 3 Current=0.600000 +Motor 3 Home=0 +Motor 3 BL Size=650 +Motor 3 BL Dir=1 +Motor 3 Max Step=69000 +Motor 3 Min Step=-200 +Motor 3 Mix WL=1064.000000 +Motor 3 Name="UV L2" +Motor 3 Park=0 +Motor 3 Ramp=150.000000 +Motor 3 Slope=10.000000 +Motor 3 First=0.600000 + +[Motor Config 1] +Double BL=1 +Name="IDLER" +Default Wavelength=1200.000000 +Motor 0 Equation=2 +Motor 0 Coeff="-10034351.9962601084000000000|66823.5712450537248000000|-182.2028426992165750000|0.2617740803347156640|-0.0002092387122824080|0.0000000881876090298|-0.0000000000152863918|146.4419507104903460000" +Motor 0 Speed=150.000000 +Motor 0 Acceleration=10.000000 +Motor 0 Current=0.600000 +Motor 0 Home=0 +Motor 0 BL Size=0 +Motor 0 BL Dir=1 +Motor 0 Max Step=50000 +Motor 0 Min Step=0 +Motor 0 Mix WL=1064.000000 +Motor 0 Name="OPO" +Motor 0 Park=0 +Motor 0 Ramp=150.000000 +Motor 0 Slope=10.000000 +Motor 0 First=0.600000 +Motor 1 Equation=0 +Motor 1 Coeff="" +Motor 1 Speed=150.000000 +Motor 1 Acceleration=10.000000 +Motor 1 Current=0.600000 +Motor 1 Home=0 +Motor 1 BL Size=650 +Motor 1 BL Dir=1 +Motor 1 Max Step=69000 +Motor 1 Min Step=-200 +Motor 1 Mix WL=1064.000000 +Motor 1 Name="UV" +Motor 1 Park=0 +Motor 1 Ramp=150.000000 +Motor 1 Slope=10.000000 +Motor 1 First=0.600000 +Motor 2 Equation=0 +Motor 2 Coeff="" +Motor 2 Speed=150.000000 +Motor 2 Acceleration=10.000000 +Motor 2 Current=0.600000 +Motor 2 Home=0 +Motor 2 BL Size=650 +Motor 2 BL Dir=1 +Motor 2 Max Step=200000 +Motor 2 Min Step=-20000 +Motor 2 Mix WL=1064.000000 +Motor 2 Name="Beamguide" +Motor 2 Park=0 +Motor 2 Ramp=150.000000 +Motor 2 Slope=10.000000 +Motor 2 First=0.600000 +Motor 3 Equation=0 +Motor 3 Coeff="" +Motor 3 Speed=150.000000 +Motor 3 Acceleration=10.000000 +Motor 3 Current=0.600000 +Motor 3 Home=0 +Motor 3 BL Size=650 +Motor 3 BL Dir=1 +Motor 3 Max Step=69000 +Motor 3 Min Step=-200 +Motor 3 Mix WL=1064.000000 +Motor 3 Name="UV L2" +Motor 3 Park=0 +Motor 3 Ramp=150.000000 +Motor 3 Slope=10.000000 +Motor 3 First=0.600000 + +[Motor Config 2] +Double BL=1 +Name="UV-1" +Default Wavelength=230.000000 +Motor 0 Equation=4 +Motor 0 Coeff="-10034351.9962601084000000000|66823.5712450537248000000|-182.2028426992165750000|0.2617740803347156640|-0.0002092387122824080|0.0000000881876090298|-0.0000000000152863918|146.4419507104903460000" +Motor 0 Speed=150.000000 +Motor 0 Acceleration=10.000000 +Motor 0 Current=0.600000 +Motor 0 Home=0 +Motor 0 BL Size=0 +Motor 0 BL Dir=1 +Motor 0 Max Step=50000 +Motor 0 Min Step=0 +Motor 0 Mix WL=1064.000000 +Motor 0 Name="OPO" +Motor 0 Park=0 +Motor 0 Ramp=150.000000 +Motor 0 Slope=10.000000 +Motor 0 First=0.600000 +Motor 1 Equation=3 +Motor 1 Coeff="" +Motor 1 Speed=150.000000 +Motor 1 Acceleration=10.000000 +Motor 1 Current=0.600000 +Motor 1 Home=0 +Motor 1 BL Size=650 +Motor 1 BL Dir=1 +Motor 1 Max Step=69000 +Motor 1 Min Step=-200 +Motor 1 Mix WL=1064.000000 +Motor 1 Name="UV" +Motor 1 Park=0 +Motor 1 Ramp=150.000000 +Motor 1 Slope=10.000000 +Motor 1 First=0.600000 +Motor 2 Equation=0 +Motor 2 Coeff="" +Motor 2 Speed=150.000000 +Motor 2 Acceleration=10.000000 +Motor 2 Current=0.600000 +Motor 2 Home=0 +Motor 2 BL Size=650 +Motor 2 BL Dir=1 +Motor 2 Max Step=200000 +Motor 2 Min Step=-20000 +Motor 2 Mix WL=1064.000000 +Motor 2 Name="Beamguide" +Motor 2 Park=0 +Motor 2 Ramp=150.000000 +Motor 2 Slope=10.000000 +Motor 2 First=0.600000 +Motor 3 Equation=0 +Motor 3 Coeff="" +Motor 3 Speed=150.000000 +Motor 3 Acceleration=10.000000 +Motor 3 Current=0.600000 +Motor 3 Home=0 +Motor 3 BL Size=650 +Motor 3 BL Dir=1 +Motor 3 Max Step=69000 +Motor 3 Min Step=-200 +Motor 3 Mix WL=1064.000000 +Motor 3 Name="UV L2" +Motor 3 Park=0 +Motor 3 Ramp=150.000000 +Motor 3 Slope=10.000000 +Motor 3 First=0.600000 + +[Motor Config 3] +Double BL=1 +Name="UV-2" +Default Wavelength=400.000000 +Motor 0 Equation=4 +Motor 0 Coeff="-10034351.9962601084000000000|66823.5712450537248000000|-182.2028426992165750000|0.2617740803347156640|-0.0002092387122824080|0.0000000881876090298|-0.0000000000152863918|146.4419507104903460000" +Motor 0 Speed=150.000000 +Motor 0 Acceleration=10.000000 +Motor 0 Current=0.600000 +Motor 0 Home=0 +Motor 0 BL Size=0 +Motor 0 BL Dir=1 +Motor 0 Max Step=50000 +Motor 0 Min Step=0 +Motor 0 Mix WL=1064.000000 +Motor 0 Name="OPO" +Motor 0 Park=0 +Motor 0 Ramp=150.000000 +Motor 0 Slope=10.000000 +Motor 0 First=0.600000 +Motor 1 Equation=3 +Motor 1 Coeff="" +Motor 1 Speed=150.000000 +Motor 1 Acceleration=10.000000 +Motor 1 Current=0.600000 +Motor 1 Home=0 +Motor 1 BL Size=650 +Motor 1 BL Dir=1 +Motor 1 Max Step=69000 +Motor 1 Min Step=-200 +Motor 1 Mix WL=1064.000000 +Motor 1 Name="UV" +Motor 1 Park=0 +Motor 1 Ramp=150.000000 +Motor 1 Slope=10.000000 +Motor 1 First=0.600000 +Motor 2 Equation=0 +Motor 2 Coeff="" +Motor 2 Speed=150.000000 +Motor 2 Acceleration=10.000000 +Motor 2 Current=0.600000 +Motor 2 Home=0 +Motor 2 BL Size=650 +Motor 2 BL Dir=1 +Motor 2 Max Step=200000 +Motor 2 Min Step=-20000 +Motor 2 Mix WL=1064.000000 +Motor 2 Name="Beamguide" +Motor 2 Park=0 +Motor 2 Ramp=150.000000 +Motor 2 Slope=10.000000 +Motor 2 First=0.600000 +Motor 3 Equation=0 +Motor 3 Coeff="" +Motor 3 Speed=150.000000 +Motor 3 Acceleration=10.000000 +Motor 3 Current=0.600000 +Motor 3 Home=0 +Motor 3 BL Size=650 +Motor 3 BL Dir=1 +Motor 3 Max Step=69000 +Motor 3 Min Step=-200 +Motor 3 Mix WL=1064.000000 +Motor 3 Name="UV L2" +Motor 3 Park=0 +Motor 3 Ramp=150.000000 +Motor 3 Slope=10.000000 +Motor 3 First=0.600000 + +[Motor Config 4] +Double BL=1 +Name="UV-3" +Default Wavelength=365.000000 +Motor 0 Equation=5 +Motor 0 Coeff="-10034351.9962601084000000000|66823.5712450537248000000|-182.2028426992165750000|0.2617740803347156640|-0.0002092387122824080|0.0000000881876090298|-0.0000000000152863918|146.4419507104903460000" +Motor 0 Speed=150.000000 +Motor 0 Acceleration=10.000000 +Motor 0 Current=0.600000 +Motor 0 Home=0 +Motor 0 BL Size=0 +Motor 0 BL Dir=1 +Motor 0 Max Step=50000 +Motor 0 Min Step=0 +Motor 0 Mix WL=1064.000000 +Motor 0 Name="OPO" +Motor 0 Park=0 +Motor 0 Ramp=150.000000 +Motor 0 Slope=10.000000 +Motor 0 First=0.600000 +Motor 1 Equation=3 +Motor 1 Coeff="" +Motor 1 Speed=150.000000 +Motor 1 Acceleration=10.000000 +Motor 1 Current=0.600000 +Motor 1 Home=0 +Motor 1 BL Size=650 +Motor 1 BL Dir=1 +Motor 1 Max Step=69000 +Motor 1 Min Step=-200 +Motor 1 Mix WL=1064.000000 +Motor 1 Name="UV" +Motor 1 Park=0 +Motor 1 Ramp=150.000000 +Motor 1 Slope=10.000000 +Motor 1 First=0.600000 +Motor 2 Equation=0 +Motor 2 Coeff="" +Motor 2 Speed=150.000000 +Motor 2 Acceleration=10.000000 +Motor 2 Current=0.600000 +Motor 2 Home=0 +Motor 2 BL Size=650 +Motor 2 BL Dir=1 +Motor 2 Max Step=200000 +Motor 2 Min Step=-20000 +Motor 2 Mix WL=1064.000000 +Motor 2 Name="Beamguide" +Motor 2 Park=0 +Motor 2 Ramp=150.000000 +Motor 2 Slope=10.000000 +Motor 2 First=0.600000 +Motor 3 Equation=0 +Motor 3 Coeff="" +Motor 3 Speed=150.000000 +Motor 3 Acceleration=10.000000 +Motor 3 Current=0.600000 +Motor 3 Home=0 +Motor 3 BL Size=650 +Motor 3 BL Dir=1 +Motor 3 Max Step=69000 +Motor 3 Min Step=-200 +Motor 3 Mix WL=1064.000000 +Motor 3 Name="UV L2" +Motor 3 Park=0 +Motor 3 Ramp=150.000000 +Motor 3 Slope=10.000000 +Motor 3 First=0.600000 + +[Motor Config 5] +Double BL=1 +Name="UV-X" +Default Wavelength=450.000000 +Motor 0 Equation=6 +Motor 0 Coeff="-10034351.9962601084000000000|66823.5712450537248000000|-182.2028426992165750000|0.2617740803347156640|-0.0002092387122824080|0.0000000881876090298|-0.0000000000152863918|146.4419507104903460000" +Motor 0 Speed=150.000000 +Motor 0 Acceleration=10.000000 +Motor 0 Current=0.600000 +Motor 0 Home=0 +Motor 0 BL Size=0 +Motor 0 BL Dir=1 +Motor 0 Max Step=50000 +Motor 0 Min Step=0 +Motor 0 Mix WL=1064.000000 +Motor 0 Name="OPO" +Motor 0 Park=0 +Motor 0 Ramp=150.000000 +Motor 0 Slope=10.000000 +Motor 0 First=0.600000 +Motor 1 Equation=3 +Motor 1 Coeff="" +Motor 1 Speed=150.000000 +Motor 1 Acceleration=10.000000 +Motor 1 Current=0.600000 +Motor 1 Home=0 +Motor 1 BL Size=650 +Motor 1 BL Dir=1 +Motor 1 Max Step=69000 +Motor 1 Min Step=-200 +Motor 1 Mix WL=1064.000000 +Motor 1 Name="UV" +Motor 1 Park=0 +Motor 1 Ramp=150.000000 +Motor 1 Slope=10.000000 +Motor 1 First=0.600000 +Motor 2 Equation=0 +Motor 2 Coeff="" +Motor 2 Speed=150.000000 +Motor 2 Acceleration=10.000000 +Motor 2 Current=0.600000 +Motor 2 Home=0 +Motor 2 BL Size=650 +Motor 2 BL Dir=1 +Motor 2 Max Step=200000 +Motor 2 Min Step=-20000 +Motor 2 Mix WL=1064.000000 +Motor 2 Name="Beamguide" +Motor 2 Park=0 +Motor 2 Ramp=150.000000 +Motor 2 Slope=10.000000 +Motor 2 First=0.600000 +Motor 3 Equation=0 +Motor 3 Coeff="" +Motor 3 Speed=150.000000 +Motor 3 Acceleration=10.000000 +Motor 3 Current=0.600000 +Motor 3 Home=0 +Motor 3 BL Size=650 +Motor 3 BL Dir=1 +Motor 3 Max Step=69000 +Motor 3 Min Step=-200 +Motor 3 Mix WL=1064.000000 +Motor 3 Name="UV L2" +Motor 3 Park=0 +Motor 3 Ramp=150.000000 +Motor 3 Slope=10.000000 +Motor 3 First=0.600000 + +[Port Config] +Port=7 +Baud=19200 +Data Bits=8 +Parity=0 +Stop BIts=10 +Flow=0 + +[Laser Serial Port] +Port=5 +Baud=115200 +Data Bits=8 +Parity=0 +Stop BIts=10 +Flow=0 + +[SSC Serial Port] +Port=0 +Baud=9600 +Data Bits=8 +Parity=0 +Stop BIts=10 +Flow=0 + +[Laser Config] +Laser Type=6 +Rep Rate=20 +MAX Power Param.=10.000000 +MIN Power Param.=100.000000 +Soft-Start=FALSE +SS Initial %=10.000000 +SS Steps=10 +Check Safety Interlocks=FALSE +Old Brilliant (no Q-switch control)=FALSE +Load Configuration=0 +Use External Timing=FALSE + +[Spectrometer] +Spectrometer=FALSE +Integration Time=8 +Trigger Mode=3 +Model=0 +Closed-Loop Tuning=FALSE +CL Resolution=0.500000 + +[Module Config] +Pump Wavelength=532.000000 +System Type=9 +Signal-lo=690.000000 +Signal-hi=950.000000 +Idler-lo=1200.000000 +Idler-hi=2400.000000 +UV-1=FALSE +UV-1-lo=0.000000 +UV-1-hi=0.000000 +UV-2=FALSE +UV-2-lo=0.000000 +UV-2-hi=0.000000 +UV-3=FALSE +UV-3-lo=0.000000 +UV-3-hi=0.000000 +UV-M=FALSE +UV-M-lo=0.000000 +UV-M-hi=0.000000 +UV-0=FALSE +UV-0-lo=0.000000 +UV-0-hi=0.000000 +Beamguide=FALSE + +[Miscellaneous] +OPO Recalibrate Max Step=1000 +UV Module Present=FALSE +Beamguide Present=FALSE +Period Decimal Notation=TRUE +OPO Cal. Limit Lo=0 +OPO Cal. Limit Hi=0 +Laser Control Mode=0 +Show User's LSODMM=FALSE +Hide System Configuration menu=TRUE +Closed-loop Tuning=FALSE +Digits of Precision=0 +Polarizer Present=FALSE +Attenuator Present=FALSE +LSODMM=FALSE +Show "Shutter (axis#1)"=FALSE +Shutter (axis#1).Label="" +Disable Tuning=FALSE +Suppress Polarizer Messages=FALSE + +[Automated Polarizer] +Automated Polarizer=FALSE +SIGNAL Position=293 +IDLER Position=438 +Stepper Current=0.600000 + +[Motorized Harmonics] +Motorized Harmonics=TRUE +SHG Min=-200000 +SHG Max=200000 +SHG Last=0 +THG Min=-200000 +THG Max=200000 +THG Last=0 +Fine Step=10 +Medium Step=20 +Coarse Step=50 +Stepper Current=0.600000 +Speed=100 +BL Size=200 +Steps per Revolution=96000 +Auto Optimization=TRUE +Feedback Device=2 +OPO Wavelength=760.000000 +OPO Threshold=0.000050 +Multi-Input Fiber=FALSE +532 Input=FALSE +532 Threshold=425.000000 +355 Input=FALSE +355 Threshold=425.000000 +Energy=90.000000 +Averaging=5 + +[DAQ Device] +DAQ Installed=FALSE +Model=1 +Device S/N=0 + +[Motorized Attenuator] +Motorized Attenuator=FALSE +Current Position=100.000000 +Attenuator Coeff="" +Stepper Current=0.600000 + +[Motor Controller] +Controller Type=1 +Auto Module Detection=FALSE +Motor Addresses="-1|4" +Wiring Scheme=1 + +[KAE Parameters] +Speed Mode=0 +Min Speed=10 +Run Current=20 +Hold Current=10 +Thermal Limit=0 +Output 1=FALSE +Output 2=TRUE +Output 3=TRUE +Output 4=TRUE +Output 5=FALSE +Ignore Limits=FALSE +Ignore E-Stop=TRUE +Off on E-Stop=TRUE + +[Scan Parameters] +Start WL=690.000000 +Period=50.000000 +End WL=950.000000 +Nr of shots/set=10 +Rep Rate=0 +Laser Energy=0.000000 + +[Advanced Scan Parameters] +Wavelengths="" +No. Cycles=0 + +[Burst Parameters] +Wavelength=690 +Nr of shots=10 +Rep Rate=0 +Laser Energy=0.000000 + +[Fast-Scan Parameters] +Start WL=0 +Period=50 +End WL=0 +Laser Energy=0.000000 + +[Shutter Parameters] +SSC32 Installed=FALSE +Shutter0_SSC32_Channel=0 +Shutter0_SIGNAL_Position=0 +Shutter0_IDLER_Position=0 +Shutter0_UV-1_Position=0 +Shutter0_UV-2_Position=0 +Shutter0_UV-3_Position=0 +Shutter0_UV-M_Position=0 +Shutter0_UV-0_Position=0 +Shutter1_SSC32_Channel=0 +Shutter1_SIGNAL_Position=0 +Shutter1_IDLER_Position=0 +Shutter1_UV-1_Position=0 +Shutter1_UV-2_Position=0 +Shutter1_UV-3_Position=0 +Shutter1_UV-M_Position=0 +Shutter1_UV-0_Position=0 +Shutter2_SSC32_Channel=0 +Shutter2_SIGNAL_Position=0 +Shutter2_IDLER_Position=0 +Shutter2_UV-1_Position=0 +Shutter2_UV-2_Position=0 +Shutter2_UV-3_Position=0 +Shutter2_UV-M_Position=0 +Shutter2_UV-0_Position=0 +Shutter3_SSC32_Channel=0 +Shutter3_SIGNAL_Position=0 +Shutter3_IDLER_Position=0 +Shutter3_UV-1_Position=0 +Shutter3_UV-2_Position=0 +Shutter3_UV-3_Position=0 +Shutter3_UV-M_Position=0 +Shutter3_UV-0_Position=0 +Shutter4_SSC32_Channel=0 +Shutter4_SIGNAL_Position=0 +Shutter4_IDLER_Position=0 +Shutter4_UV-1_Position=0 +Shutter4_UV-2_Position=0 +Shutter4_UV-3_Position=0 +Shutter4_UV-M_Position=0 +Shutter4_UV-0_Position=0 + +[Demo Parameters] +Motor Speed=80 +Start WL=0.000000 +End WL=0.000000 + +[Energy Metering] +Meter Installed=FALSE +Device=0 +Use Range #=0 +Device S/N="786441" +OPO S/N="781544" +OPO Channel=-1 +532nm S/N="" +532nm Scale Factor=0.000000 +532nm Channel=-1 +1064nm S/N="" +1064nm Scale Factor=0.000000 +1064nm Channel=-1 +355nm S/N="" +355nm Scale Factor=0.000000 +355nm Channel=-1 +Motor Config 0 Wavelengths="690.0|695.2|700.4|705.6|710.8|716.0|721.2|726.4|731.6|736.8|742.0|747.2|752.4|757.6|762.8|768.0|773.2|778.4|783.6|788.8|794.0|799.2|804.4|809.6|814.8|820.0|825.2|830.4|835.6|840.8|846.0|851.2|856.4|861.6|866.8|872.0|877.2|882.4|887.6|892.8|898.0|903.2|908.4|913.6|918.8|924.0|929.2|934.4|939.6|944.8" +Motor Config 0 Amplitudes="0.000727|0.000726|0.000764|0.000795|0.000824|0.000817|0.000832|0.000893|0.000898|0.000881|0.000870|0.000834|0.000849|0.000793|0.000778|0.000753|0.000755|0.000812|0.000843|0.000818|0.000843|0.000824|0.000829|0.000837|0.000832|0.000796|0.000808|0.000796|0.000774|0.000778|0.000760|0.000741|0.000724|0.000725|0.000703|0.000703|0.000695|0.000697|0.000671|0.000702|0.000679|0.000671|0.000676|0.000647|0.000660|0.000674|0.000686|0.000664|0.000658|0.000643" +Motor Config 0 Energies="0.042647|0.043251|0.045291|0.047462|0.048515|0.049305|0.049513|0.050434|0.049656|0.050895|0.048269|0.049129|0.050182|0.049334|0.046761|0.045675|0.045061|0.049129|0.050357|0.049206|0.050050|0.048745|0.048822|0.049041|0.048976|0.047813|0.047082|0.046980|0.046980|0.046442|0.045445|0.044063|0.043909|0.042451|0.041058|0.041760|0.042374|0.041683|0.040269|0.042374|0.041299|0.038996|0.041069|0.040736|0.039994|0.040839|0.040225|0.039994|0.038613|0.037692" +Motor Config 1 Wavelengths="" +Motor Config 1 Amplitudes="" +Motor Config 1 Energies="" +Motor Config 2 Wavelengths="" +Motor Config 2 Amplitudes="" +Motor Config 2 Energies="" +Motor Config 3 Wavelengths="" +Motor Config 3 Amplitudes="" +Motor Config 3 Energies="" +Motor Config 4 Wavelengths="" +Motor Config 4 Amplitudes="" +Motor Config 4 Energies="" +Motor Config 5 Wavelengths="" +Motor Config 5 Amplitudes="" +Motor Config 5 Energies="" + +[Ophir Sensor Settings] +Sensor1.Model Number="PE25-C" +Sensor1.Sensor Type="Pyroelectric" +Sensor1.Sensor S/N="781544" +Sensor1.Mode=1 +Sensor1.Wavelength=750 +Sensor1.Range=4 +Sensor1.Diffuser=FALSE +Sensor1.Pulsewidth=0 +Sensor1.Threshold=0 +Sensor1.Ext. Trigger=FALSE +Sensor2.Model Number="" +Sensor2.Sensor Type="" +Sensor2.Sensor S/N="" +Sensor2.Mode=0 +Sensor2.Wavelength=0 +Sensor2.Range=0 +Sensor2.Diffuser=FALSE +Sensor2.Pulsewidth=0 +Sensor2.Threshold=0 +Sensor2.Ext. Trigger=FALSE +Sensor3.Model Number="" +Sensor3.Sensor Type="" +Sensor3.Sensor S/N="" +Sensor3.Mode=0 +Sensor3.Wavelength=0 +Sensor3.Range=0 +Sensor3.Diffuser=FALSE +Sensor3.Pulsewidth=0 +Sensor3.Threshold=0 +Sensor3.Ext. Trigger=FALSE +Sensor4.Model Number="" +Sensor4.Sensor Type="" +Sensor4.Sensor S/N="" +Sensor4.Mode=0 +Sensor4.Wavelength=0 +Sensor4.Range=0 +Sensor4.Diffuser=FALSE +Sensor4.Pulsewidth=0 +Sensor4.Threshold=0 +Sensor4.Ext. Trigger=FALSE + +[UV Look-up Table] +UV-1 Use Lookup Table=FALSE +UV-1 Wavelengths="" +UV-1 Steps="" +UV-2 Use Lookup Table=FALSE +UV-2 Wavelengths="" +UV-2 Steps="" +UV-3 Use Lookup Table=FALSE +UV-3 Wavelengths="" +UV-3 Steps="" +UV-M Use Lookup Table=FALSE +UV-M Wavelengths="" +UV-M Steps="" +UV-0 Use Lookup Table=FALSE +UV-0 Wavelengths="" +UV-0 Steps="" + +[Fast Tuning] +Fast Tuning=TRUE +Kp=0.000000 +Ki=0.000000 +Kd=0.000000 \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/test.dmc b/Modules/PhotoacousticsHardware/Resources/test.dmc new file mode 100644 index 0000000000..af11477497 --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/test.dmc @@ -0,0 +1,46 @@ +#FASTTUNE +rtf=-1 +II1 +'AMP SETTINGS +AU 0 +BR 1 +'AG 0 +TM 1000 +TL 3 +TK 9.998 +' +'GENERAL SETTINGS +ER 10000 +OE 1 +'MT -1 +'CE 0 +CN-1 +'PID PARAMETERS +KD 17.5 +KP 15 +KI 0 +' +SHX +WT 1000 +SP 1500000 +AC 120000000 +DC 120000000 +count=0;idx=0;DM pos[2] +pos[0]=27200 +pos[1]=30900 +points=pos[-1] +#MOVE; +II 1 +WT 10 +JP #MOVE; +EN +'SUBROUTINE +'************************************** +#ININT +rtf=count+10000000; +idx = count % points +'PA pos[idx];BG;AM; +'BG;AM; +count = count + 1 +WT 1 +RI 1; \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/Resources/tuneOPOto700.dmc b/Modules/PhotoacousticsHardware/Resources/tuneOPOto700.dmc new file mode 100644 index 0000000000..ac97c28bc2 --- /dev/null +++ b/Modules/PhotoacousticsHardware/Resources/tuneOPOto700.dmc @@ -0,0 +1,13 @@ +#AUTO +#MAIN +rt=0 +' +SP 150000 +AC 12000000 +DC 12000000 +pos=36459 +PA pos;BG;AM; +BG;AM; +WT 100 +rt=1 +EN \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/files.cmake b/Modules/PhotoacousticsHardware/files.cmake new file mode 100644 index 0000000000..d6d5d51880 --- /dev/null +++ b/Modules/PhotoacousticsHardware/files.cmake @@ -0,0 +1,23 @@ +set(CPP_FILES + mitkQuantelLaser.cpp + mitkGalilMotor.cpp + mitkOphirPyro.cpp +) + +set(RESOURCE_FILES + homeOPO.dmc + + GHOME.dmc + STUNE.dmc + FTUNE.dmc + + configSlowTuneOPO.dmc + executeSlowTuneOPO.dmc + + configFastTuneOPO.dmc + executeFastTuneOPO.dmc + + test.dmc + tuneOPOto700.dmc + OpotekPhocusMobile.xml +) \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/mitkGalilMotor.cpp b/Modules/PhotoacousticsHardware/mitkGalilMotor.cpp new file mode 100644 index 0000000000..583937ab5a --- /dev/null +++ b/Modules/PhotoacousticsHardware/mitkGalilMotor.cpp @@ -0,0 +1,281 @@ +/*=================================================================== + +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 "mitkGalilMotor.h" + +#include +#include + +#include + +#include "gclib.h" +#include "gclib_errors.h" + +#include "gclibo.h" + +mitk::GalilMotor::GalilMotor() : +m_ComPort(0), +m_BaudRate(0), +m_ErrorMessage("undefined"), +m_CurrentWavelength(0), +m_HomePosition(32561) +{ +} + +mitk::GalilMotor::~GalilMotor() +{ + this->CloseConnection(); + MITK_INFO << "[GalilMotor Debug] destroyed that motor"; +} + +void mitk::GalilMotor::LoadResorceFile(std::string filename, std::string* lines) +{ + us::ModuleResource resorceFile = us::GetModuleContext()->GetModule()->GetResource(filename); + std::string line; + if (resorceFile.IsValid() && resorceFile.IsFile()) + { + us::ModuleResourceStream stream(resorceFile); + while (std::getline(stream, line)) + { + *lines = *lines + line + "\n"; + } + } + else + { + MITK_ERROR << "Resource file was not valid"; + } +} + +bool mitk::GalilMotor::OpenConnection(std::string configuration) +{ + m_GalilSystem = 0; + m_ReturnCode = G_NO_ERROR; + LoadResorceFile(configuration + ".xml", &m_XmlOpoConfiguration); + TiXmlDocument xmlDoc; + + if (xmlDoc.Parse(m_XmlOpoConfiguration.c_str(), 0, TIXML_ENCODING_UTF8)) + { + TiXmlElement* root = xmlDoc.FirstChildElement("Motor"); + if (root) + { + TiXmlElement* elementNode = root->FirstChildElement("Coefficients"); + TiXmlElement* element = elementNode->FirstChildElement("lambda0"); + m_WavelengthToStepCalibration[0] = std::stod(element->GetText()); + element = elementNode->FirstChildElement("lambda1"); + m_WavelengthToStepCalibration[1] = std::stod(element->GetText()); + element = elementNode->FirstChildElement("lambda2"); + m_WavelengthToStepCalibration[2] = std::stod(element->GetText()); + element = elementNode->FirstChildElement("lambda3"); + m_WavelengthToStepCalibration[3] = std::stod(element->GetText()); + element = elementNode->FirstChildElement("lambda4"); + m_WavelengthToStepCalibration[4] = std::stod(element->GetText()); + element = elementNode->FirstChildElement("lambda5"); + m_WavelengthToStepCalibration[5] = std::stod(element->GetText()); + element = elementNode->FirstChildElement("lambda6"); + m_WavelengthToStepCalibration[6] = std::stod(element->GetText()); + element = elementNode->FirstChildElement("home"); + m_HomePosition = std::stod(element->GetText()); + elementNode = root->FirstChildElement("Signal"); + element = elementNode->FirstChildElement("Signal-low"); + m_MinWavelength = std::stod(element->GetText()); + element = elementNode->FirstChildElement("Signal-default"); + m_CurrentWavelength = std::stod(element->GetText()); + element = elementNode->FirstChildElement("Signal-high"); + m_MaxWavelength = std::stod(element->GetText()); + elementNode = root->FirstChildElement("Seriell"); + element = elementNode->FirstChildElement("PortNumber"); + m_ComPort = std::stoi(element->GetText()); + element = elementNode->FirstChildElement("Baud"); + m_BaudRate = std::stoi(element->GetText()); + } + } + else + { + MITK_ERROR << "[GalilMotor Debug] Could not load configuration xml "; + } + std::string openCommand("COM" + std::to_string(m_ComPort) + " --baud " + std::to_string(m_BaudRate) + " --subscribe ALL --direct"); + MITK_INFO << "[Galil Debug] before GOpen(" << openCommand << ") = " << m_ReturnCode << "; m_GalilSystem = " << m_GalilSystem; + m_ReturnCode = GOpen(openCommand.c_str(), &m_GalilSystem); + MITK_INFO << "[Galil Debug] after GOpen = " << m_ReturnCode << "; m_GalilSystem = " << m_GalilSystem; + this->Home(); + return true; +} + +bool mitk::GalilMotor::CloseConnection() +{ + if (m_GalilSystem) + { + this->Home(); + m_ReturnCode = GClose(m_GalilSystem); + m_GalilSystem = 0; + return true; + } + else + return false; +} + +int mitk::GalilMotor::GetPositionFromWavelength(double wavelength) +{ + double posDouble = 0; + posDouble = m_WavelengthToStepCalibration[0] - m_HomePosition; + posDouble += (m_WavelengthToStepCalibration[1] * wavelength); + posDouble += (m_WavelengthToStepCalibration[2] * std::pow(wavelength, 2)); + posDouble += (m_WavelengthToStepCalibration[3] * std::pow(wavelength, 3)); + posDouble += (m_WavelengthToStepCalibration[4] * std::pow(wavelength, 4)); + posDouble += (m_WavelengthToStepCalibration[5] * std::pow(wavelength, 5)); + posDouble += (m_WavelengthToStepCalibration[6] * std::pow(wavelength, 6)); + int pos = posDouble; + return pos; +} + +bool mitk::GalilMotor::TuneToWavelength(double wavelength, bool isRecalibrating) +{ + std::string positionCommand; + if (!isRecalibrating) + { + positionCommand = "pos=" + std::to_string(this->GetPositionFromWavelength(wavelength)); + } + else + { + int posAbs = wavelength - m_HomePosition; + positionCommand = "pos=" + std::to_string(posAbs); + } + + m_ReturnCode = GCmd(m_GalilSystem, "AB"); // Abort any running programs + MITK_INFO << "[Galil Debug] after AB: " << m_ReturnCode << ""; + m_ReturnCode = GCmd(m_GalilSystem, "BV"); // Burn all variables + MITK_INFO << "[Galil Debug] after BV: " << m_ReturnCode << ""; + m_ReturnCode = GProgramDownload(m_GalilSystem, "", 0); // Erase the program on the system + MITK_INFO << "[Galil Debug] after empty GProgramDownload: " << m_ReturnCode << ""; + + m_ReturnCode = GCmd(m_GalilSystem, positionCommand.c_str()); + MITK_INFO << "[Galil Debug] after sending tune position(" << positionCommand << "): " << m_ReturnCode << ""; + + std::string galilProgramSTUNE; + this->LoadResorceFile("STUNE.dmc", &galilProgramSTUNE); + m_ReturnCode = GProgramDownload(m_GalilSystem, galilProgramSTUNE.c_str(), 0); + MITK_INFO << "[Galil Debug] after STUNE progam: " << m_ReturnCode << galilProgramSTUNE; + + GSleep(10); + m_ReturnCode = GCmd(m_GalilSystem, "XQ#STUNE"); + MITK_INFO << "[Galil Debug] after sending XQ#STUNE = " << m_ReturnCode; + GSleep(10000); + int success, pos = -1; + m_ReturnCode = GCmdI(m_GalilSystem, "suc=?", &success); + MITK_INFO << "[Galil Debug] after asking suc=? = " << m_ReturnCode << "; successfulTune = " << success; + m_ReturnCode = GCmdI(m_GalilSystem, "pos=?", &pos); + MITK_INFO << "[Galil Debug] after asking pos=? = " << m_ReturnCode << "; pos = " << pos; + if (success == 1) + { + m_CurrentWavelength = wavelength; + return true; + } + else + return false; +} + +bool mitk::GalilMotor::FastTuneWavelengths(std::vector wavelengthList) +{ + m_ReturnCode = GCmd(m_GalilSystem, "AB"); // Abort any running programs + GSleep(1000); + MITK_INFO << "[Galil Debug] after AB: " << m_ReturnCode << ""; + m_ReturnCode = GCmd(m_GalilSystem, "BV"); // Burn all variables + GSleep(2000); + MITK_INFO << "[Galil Debug] after BV: " << m_ReturnCode << ""; + + m_ReturnCode = GProgramDownload(m_GalilSystem, "", 0); // Erase the program on the system + MITK_INFO << "[Galil Debug] after empty GProgramDownload: " << m_ReturnCode << ""; + GSleep(1000); + std::string positionsCommand("#AUTO\n#PARA\nDA pos[0]\npoints = "+std::to_string(wavelengthList.size())+"\nDM pos[" + std::to_string(wavelengthList.size()) + "];\n"); + + for (int wavelengthIterator = 0; wavelengthIterator < wavelengthList.size(); wavelengthIterator++) + { + positionsCommand += "pos[" + std::to_string(wavelengthIterator) + "]=" + std::to_string(this->GetPositionFromWavelength(wavelengthList[wavelengthIterator])) + "\n"; + } + positionsCommand += "EN\n"; + + m_ReturnCode = GProgramDownload(m_GalilSystem, positionsCommand.c_str(), 0); + MITK_INFO << "[Galil Debug] after sending positions command(" << positionsCommand << "): " << m_ReturnCode << ""; + GSleep(1000); + m_ReturnCode = GCmd(m_GalilSystem, "XQ"); // FTUNE + MITK_INFO << "[Galil Debug] after asking XQ#PARA = " << m_ReturnCode; + m_ReturnCode = GProgramDownload(m_GalilSystem, "", 0); // Erase the program on the system + MITK_INFO << "[Galil Debug] after empty GProgramDownload: " << m_ReturnCode << ""; + GSleep(1000); + std::string galilProgramFTUNE; + this->LoadResorceFile("FTUNE.dmc", &galilProgramFTUNE); + m_ReturnCode = GProgramDownload(m_GalilSystem, galilProgramFTUNE.c_str(), 0); + MITK_INFO << "[Galil Debug] after FTUNE progam upload: " << m_ReturnCode << ""; + + GSleep(1000); + m_ReturnCode = GCmd(m_GalilSystem, "XQ"); // FTUNE + MITK_INFO << "[Galil Debug] after asking XQ#FTUNE = " << m_ReturnCode; + GSleep(10000); + int count = -1; + m_ReturnCode = GCmdI(m_GalilSystem, "count=?", &count); + MITK_INFO << "[Galil Debug] cycles = " << count; + m_ReturnCode = GCmdI(m_GalilSystem, "pos=?", &count); + MITK_INFO << "[Galil Debug] pos = " << count; + m_ReturnCode = GCmdI(m_GalilSystem, "points=?", &count); + MITK_INFO << "[Galil Debug] points = " << count; + + if (count > 0) + return true; + else + return false; +} + +bool mitk::GalilMotor::Home() +{ + m_ReturnCode = GCmd(m_GalilSystem, "AB"); // Abort any running programs + MITK_INFO << "[Galil Debug] after AB: " << m_ReturnCode << ""; + GSleep(1000); + m_ReturnCode = GCmd(m_GalilSystem, "BV"); // Burn all variables + MITK_INFO << "[Galil Debug] after BV: " << m_ReturnCode << ""; + GSleep(1000); + m_ReturnCode = GProgramDownload(m_GalilSystem, "", 0); // Erase the program on the system + MITK_INFO << "[Galil Debug] after empty GProgramDownload: " << m_ReturnCode << ""; + + std::string galilProgram; + this->LoadResorceFile("GHOME.dmc", &galilProgram); + + m_ReturnCode = GProgramDownload(m_GalilSystem, galilProgram.c_str(), 0); + MITK_INFO << "[Galil Debug] after home GProgramDownloadFile = " << m_ReturnCode << "; m_GalilSystem = " << m_GalilSystem; + + m_ReturnCode = GCmd(m_GalilSystem, "XQ"); // HOME + GSleep(15000); + int val = -2; + m_ReturnCode = GCmdI(m_GalilSystem, "suc=?", &val); + + MITK_INFO << "[Galil Debug] after home execution = " << m_ReturnCode << "; m_GalilSystem = " << m_GalilSystem << " homed = " << val; + + return true; +} + +double mitk::GalilMotor::GetMinWavelength() +{ + return m_MinWavelength; +} + +double mitk::GalilMotor::GetMaxWavelength() +{ + return m_MaxWavelength; +} + +double mitk::GalilMotor::GetCurrentWavelength() +{ + return m_CurrentWavelength; +} \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/mitkGalilMotor.h b/Modules/PhotoacousticsHardware/mitkGalilMotor.h new file mode 100644 index 0000000000..c73e07d512 --- /dev/null +++ b/Modules/PhotoacousticsHardware/mitkGalilMotor.h @@ -0,0 +1,80 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +#ifndef MITKGalilAPI_H_HEADER_INCLUDED +#define MITKGalilAPI_H_HEADER_INCLUDED + +#include "itkObject.h" +#include "mitkCommon.h" + +#include "vector" +#include "MitkPhotoacousticsHardwareExports.h" + +#include "gclib.h" +#include "gclibo.h" + +#include +#include +#include +#include +#include + +#include + +namespace mitk { + + class MITKPHOTOACOUSTICSHARDWARE_EXPORT GalilMotor : public itk::Object + { + public: + mitkClassMacroItkParent(mitk::GalilMotor, itk::Object); + itkFactorylessNewMacro(Self); + + virtual bool OpenConnection(std::string configuration); + virtual bool CloseConnection(); + + double GetMinWavelength(); + double GetMaxWavelength(); + double GetCurrentWavelength(); + + bool TuneToWavelength(double wavelength, bool isRecalibrating); + + bool FastTuneWavelengths(std::vector wavelengthList); + + protected: + virtual bool Home(); + void LoadResorceFile(std::string filename, std::string* lines); + int GetPositionFromWavelength(double wavelength); + GalilMotor(); + virtual ~GalilMotor(); + + int m_ComPort; + int m_BaudRate; + std::string m_ErrorMessage; + GCon m_GalilSystem; + GReturn m_ReturnCode; + + std::string m_XmlOpoConfiguration; + double m_MinWavelength; + double m_MaxWavelength; + double m_CurrentWavelength; + double m_WavelengthToStepCalibration[7]; + double m_HomePosition; + + }; +} // namespace mitk + +#endif /* MITKGalilAPI_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp b/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp new file mode 100644 index 0000000000..85da10fa80 --- /dev/null +++ b/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp @@ -0,0 +1,313 @@ +/*=================================================================== + +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 "mitkOphirPyro.h" + +#include +#include +#include +#include + +mitk::OphirPyro::OphirPyro() : +m_CurrentWavelength(0), +m_DeviceHandle(0), +m_Connected(false), +m_Streaming(false), +m_SerialNumber(nullptr), +m_GetDataThread(), +m_ImagePyroDelay(0), +m_EnergyMultiplicator(60000) +{ + m_PulseEnergy.clear(); + m_PulseTime.clear(); + m_PulseStatus.clear(); + m_TimeStamps.clear(); +} + +mitk::OphirPyro::~OphirPyro() +{ + if (m_Connected) + { + this->CloseConnection(); + if (m_GetDataThread.joinable()) + { + m_GetDataThread.join(); + MITK_INFO << "[OphirPyro Debug] joined data thread"; + } + } + MITK_INFO << "[OphirPyro Debug] destroying that Pyro"; + /* cleanup thread */ +} + +bool mitk::OphirPyro::StartDataAcquisition() +{ + if (ophirAPI.StartStream(m_DeviceHandle)) + { + m_Streaming = true; + m_GetDataThread = std::thread(&mitk::OphirPyro::GetDataFromSensorThread, this); + } + return m_Streaming; +} + +// this is just a little function to set the filenames below right +inline void replaceAll(std::string& str, const std::string& from, const std::string& to) { + if (from.empty()) + return; + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } +} + +void mitk::OphirPyro::SaveCsvData() +{ + // get the time and date, put them into a nice string and create a folder for the images + time_t time = std::time(nullptr); + time_t* timeptr = &time; + std::string currentDate = std::ctime(timeptr); + replaceAll(currentDate, ":", "-"); + currentDate.pop_back(); + std::string MakeFolder = "mkdir \"c:/DiPhASTimeStamps/" + currentDate + "\""; + system(MakeFolder.c_str()); + + std::string pathTS = "c:\\DiPhASTimeStamps\\" + currentDate + " Timestamps" + ".csv"; + + std::ofstream timestampFile; + timestampFile.open(pathTS); + + timestampFile << ",timestamp,PulseEnergy,PulseTime"; + + int currentSize = m_TimeStamps.size(); + + for (int index = 0; index < currentSize; ++index) + { + timestampFile << "\n" << index << "," << m_TimeStamps.at(index) << ","<< m_PulseEnergy.at(index) << "," << (long)m_PulseTime.at(index); + } + timestampFile.close(); +} + +void mitk::OphirPyro::SaveData() +{ + SaveCsvData(); +} + +bool mitk::OphirPyro::StopDataAcquisition() +{ + if (ophirAPI.StopStream(m_DeviceHandle)) + m_Streaming = false; + + SaveCsvData(); + MITK_INFO << "[OphirPyro Debug] m_Streaming = "<< m_Streaming; + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + if (m_GetDataThread.joinable()) + { + m_GetDataThread.join(); + } + return !m_Streaming; +} + +unsigned int mitk::OphirPyro::GetDataFromSensor() +{ + if (m_Streaming) + { + std::vector newEnergy; + std::vector newTimestamp; + std::vector newStatus; + unsigned int noPackages = 0; + try + { + noPackages = ophirAPI.GetData(m_DeviceHandle, &newEnergy, &newTimestamp, &newStatus); + if (noPackages > 0) + { + m_PulseEnergy.insert(m_PulseEnergy.end(), newEnergy.begin(), newEnergy.end()); + for (int i=0; iGetDataFromSensor(); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + return; +} + +double mitk::OphirPyro::LookupCurrentPulseEnergy() +{ + if (m_Connected && !m_PulseEnergy.empty()) + { + MITK_INFO << m_PulseEnergy.size(); + return m_PulseEnergy.back(); + } + return 0; +} + +double mitk::OphirPyro::GetClosestEnergyInmJ(long long ImageTimeStamp, double interval) +{ + if (m_PulseTime.size() == 0) + return 0; + + long long searchTime = (ImageTimeStamp/1000000) - m_ImagePyroDelay; // conversion from ns to ms + + //MITK_INFO << "searchTime = " << searchTime; + int foundIndex = -1; + long long shortestDifference = 250*interval; + + // search the list for a fitting energy value time + for (int index = 0; index < m_PulseTime.size();++index) + { + long long newDifference = abs(((int)m_PulseTime[index]) - searchTime); + //MITK_INFO << "newDifference[" << index << "] = " << newDifference; + if (newDifference < shortestDifference) + { + shortestDifference = newDifference; + foundIndex = index; + //MITK_INFO << "foundIndex = " << foundIndex; + } + } + + if (abs(shortestDifference) < interval) + { + // delete all elements before the one found + m_PulseEnergy.erase(m_PulseEnergy.begin(), m_PulseEnergy.begin() + foundIndex); + m_PulseTime.erase(m_PulseTime.begin(), m_PulseTime.begin() + foundIndex); + m_PulseStatus.erase(m_PulseStatus.begin(), m_PulseStatus.begin() + foundIndex); + + // multipy with m_EnergyMultiplicator, because the Pyro gives just a fraction of the actual Laser Energy + return (GetNextPulseEnergy()*m_EnergyMultiplicator); + } + + //MITK_INFO << "No matching energy value for image found in interval of " << interval << "ms. sd: " << shortestDifference; + return -1; +} + +double mitk::OphirPyro::GetNextEnergyInmJ(long long ImageTimeStamp, double interval) +{ + if (m_Connected && !(m_PulseTime.size() > 0)) + return 0; + + long long searchTime = (ImageTimeStamp / 1000000) - m_ImagePyroDelay; // conversion from ns to ms + + if (abs(searchTime - m_PulseTime.front()) < interval) + { + return (GetNextPulseEnergy()*m_EnergyMultiplicator); // multipy with m_EnergyMultiplicator, because the Pyro gives just a fraction of the actual Laser Energy + } + + MITK_INFO << "Image aquisition and energy measurement ran out of sync"; + return -1; +} + +void mitk::OphirPyro::SetSyncDelay(long long FirstImageTimeStamp) +{ + while (!m_PulseTime.size()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + m_ImagePyroDelay = (FirstImageTimeStamp / 1000000) - m_PulseTime.at(0); + + MITK_INFO << "m_ImagePyroDelay = " << m_ImagePyroDelay; + return; +} + +bool mitk::OphirPyro::IsSyncDelaySet() +{ + return (m_ImagePyroDelay != 0); +} + +double mitk::OphirPyro::GetNextPulseEnergy() +{ + if (m_Connected && m_PulseEnergy.size()>=1) + { + double out = m_PulseEnergy.front(); + m_PulseEnergy.erase(m_PulseEnergy.begin()); + m_PulseTime.erase(m_PulseTime.begin()); + m_PulseStatus.erase(m_PulseStatus.begin()); + return out; + } + return 0; +} + +double mitk::OphirPyro::LookupCurrentPulseEnergy(double* timestamp, int* status) +{ + if (m_Connected) + { + *timestamp = m_PulseTime.back(); + *status = m_PulseStatus.back(); + return m_PulseEnergy.back(); + } + return 0; +} + +double mitk::OphirPyro::GetNextPulseEnergy(double* timestamp, int* status) +{ + if (m_Connected) + { + double out = m_PulseEnergy.front(); + *timestamp = m_PulseTime.front(); + *status = m_PulseStatus.front(); + m_PulseEnergy.erase(m_PulseEnergy.begin()); + m_PulseTime.erase(m_PulseTime.begin()); + m_PulseStatus.erase(m_PulseStatus.begin()); + return out; + } + return 0; +} + +bool mitk::OphirPyro::OpenConnection() +{ + if (!m_Connected) + { + char* m_SerialNumber = ophirAPI.ScanUSB(); + if (m_SerialNumber != 0) + { + m_DeviceHandle = ophirAPI.OpenDevice(m_SerialNumber); + if (m_DeviceHandle != 0) + { + m_Connected = true; + return true; + } + } + } + return false; +} + +bool mitk::OphirPyro::CloseConnection() +{ + if (m_Connected) + { + bool closed = ophirAPI.CloseDevice(m_DeviceHandle); + if (closed) m_DeviceHandle = 0; + m_Connected = !closed; + return closed; + } + return false; +} \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/mitkOphirPyro.h b/Modules/PhotoacousticsHardware/mitkOphirPyro.h new file mode 100644 index 0000000000..de3fb7f8ab --- /dev/null +++ b/Modules/PhotoacousticsHardware/mitkOphirPyro.h @@ -0,0 +1,88 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +#ifndef MITKOPHIRPYRO_H_HEADER_INCLUDED +#define MITKOPHIRPYRO_H_HEADER_INCLUDED + +#include "itkObject.h" +#include "mitkCommon.h" + +#include "vector" +#include "MitkPhotoacousticsHardwareExports.h" + +#include "OphirPyroWrapper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mitk { + + class MITKPHOTOACOUSTICSHARDWARE_EXPORT OphirPyro : public itk::Object + { + public: + mitkClassMacroItkParent(mitk::OphirPyro, itk::Object); + itkFactorylessNewMacro(Self); + + virtual bool OpenConnection(); + virtual bool CloseConnection(); + virtual bool StartDataAcquisition(); + virtual bool StopDataAcquisition(); + unsigned int GetDataFromSensor(); + void GetDataFromSensorThread(); + void SaveData(); + + virtual double LookupCurrentPulseEnergy(); + virtual double GetNextPulseEnergy(); + virtual double LookupCurrentPulseEnergy(double* timestamp, int* status); + virtual double GetNextPulseEnergy(double* timestamp, int* status); + + virtual double GetClosestEnergyInmJ(long long ImageTimeStamp, double interval=20); + virtual double GetNextEnergyInmJ(long long ImageTimeStamp, double interval = 20); + virtual void SetSyncDelay(long long FirstImageTimeStamp); + virtual bool IsSyncDelaySet(); + + + protected: + OphirPyro(); + virtual ~OphirPyro(); + void SaveCsvData(); + OphirPyroWrapper ophirAPI; + char* m_SerialNumber; + int m_DeviceHandle; + bool m_Connected; + bool m_Streaming; + std::vector m_PulseEnergy; + std::vector m_PulseTime; + std::vector m_PulseStatus; + std::vector m_TimeStamps; + double m_CurrentWavelength; + double m_CurrentEnergyRange; + long long m_ImagePyroDelay; + float m_EnergyMultiplicator; + + std::thread m_GetDataThread; + }; +} // namespace mitk + +#endif /* MITKOPHIRPYRO_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsHardware/mitkQuantelLaser.cpp b/Modules/PhotoacousticsHardware/mitkQuantelLaser.cpp new file mode 100644 index 0000000000..2f8c8a0093 --- /dev/null +++ b/Modules/PhotoacousticsHardware/mitkQuantelLaser.cpp @@ -0,0 +1,409 @@ +/*=================================================================== + +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 "mitkQuantelLaser.h" + +#include +#include +#include + +#include + +#include +#include + +const unsigned char CR = 0xD; // == '\r' - carriage return +const unsigned char LF = 0xA; // == '\n' - line feed + +mitk::QuantelLaser::QuantelLaser() : + m_State(mitk::QuantelLaser::UNCONNECTED), + m_FlashlampRunning(false), + m_ShutterOpen(false), + m_LaserEmission(false), + m_DeviceName(), + m_PortNumber(mitk::SerialCommunication::COM6), + m_BaudRate(mitk::SerialCommunication::BaudRate115200), + m_DataBits(mitk::SerialCommunication::DataBits8), + m_Parity(mitk::SerialCommunication::None), + m_StopBits(mitk::SerialCommunication::StopBits1), + m_HardwareHandshake(mitk::SerialCommunication::HardwareHandshakeOff), + m_SerialCommunication(nullptr), + m_StayAliveMessageThread(), + m_SerialCommunicationMutex() +{ +} + +mitk::QuantelLaser::~QuantelLaser() +{ + /* stop tracking and disconnect from tracking device */ + if ((GetState() == STATE3) || (GetState() == STATE4) || (GetState() == STATE5) || (GetState() == STATE6)) + { + this->StopQswitching(); + this->StopFlashing(); + } + if (GetState() == STATE2) + { + this->CloseConnection(); + } + /* cleanup stay alive thread */ + if (m_StayAliveMessageThread.joinable()) + m_StayAliveMessageThread.join(); + + /* free serial communication interface */ + if (m_SerialCommunication.IsNotNull()) + { + m_SerialCommunication->ClearReceiveBuffer(); + m_SerialCommunication->ClearSendBuffer(); + m_SerialCommunication->CloseConnection(); + m_SerialCommunication = nullptr; + } +} + +std::string mitk::QuantelLaser::SendAndReceiveLine(const std::string* input, std::string* answer) +{ + MITK_INFO << "[Quantel Laser Debug] sending: " << input->c_str(); + if (input == nullptr) + return "SERIALSENDERROR"; + + std::string message; + + message = *input + '\n'; + + // Clear send buffer + m_SerialCommunication->ClearSendBuffer(); + m_SerialCommunication->Send(message); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + std::string m; + do + { + long returnvalue = m_SerialCommunication->Receive(m, 1); + if ((returnvalue == 0) || (m.size() != 1)) + return "SERIALRECEIVEERROR"; + *answer += m; + } while (m.at(0) != LF); + m_SerialCommunication->ClearReceiveBuffer(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + m_SerialCommunication->ClearReceiveBuffer(); + MITK_INFO << "[Quantel Laser Debug] received: " << answer->c_str(); + return "OK"; +} + +void mitk::QuantelLaser::LoadResorceFile(std::string filename, std::string* lines) +{ + us::ModuleResource resorceFile = us::GetModuleContext()->GetModule()->GetResource(filename); + std::string line; + if (resorceFile.IsValid() && resorceFile.IsFile()) + { + us::ModuleResourceStream stream(resorceFile); + while (std::getline(stream, line)) + { + *lines = *lines + line + "\n"; + } + } + else + { + MITK_ERROR << "[Quantel Laser Debug] Resource file was not valid"; + } +} + +bool mitk::QuantelLaser::OpenConnection(std::string configurationFile) +{ + LoadResorceFile(configurationFile + ".xml", &m_XmlPumpLaserConfiguration); + TiXmlDocument xmlDoc; + + if (xmlDoc.Parse(m_XmlPumpLaserConfiguration.c_str(), 0, TIXML_ENCODING_UTF8)) + { + TiXmlElement* root = xmlDoc.FirstChildElement("PumpLaser"); + if (root) + { + TiXmlElement* elementNode = root->FirstChildElement("Seriell"); + TiXmlElement* element = elementNode->FirstChildElement("PortNumber"); + m_PortNumber = mitk::SerialCommunication::PortNumber(std::stoi(element->GetText())); + element = elementNode->FirstChildElement("Baud"); + m_BaudRate = mitk::SerialCommunication::BaudRate(std::stoi(element->GetText())); + + MITK_INFO << m_PortNumber << m_BaudRate; + } + } + else + { + MITK_ERROR << "[Quantel Laser Debug] Could not load configuration xml "; + return false; + } + + m_SerialCommunication = mitk::SerialCommunication::New(); + + if (m_DeviceName.empty()) + m_SerialCommunication->SetPortNumber(m_PortNumber); + else + m_SerialCommunication->SetDeviceName(m_DeviceName); + + m_SerialCommunication->SetBaudRate(m_BaudRate); + m_SerialCommunication->SetDataBits(m_DataBits); + m_SerialCommunication->SetParity(m_Parity); + m_SerialCommunication->SetStopBits(m_StopBits); + m_SerialCommunication->SetSendTimeout(1000); + m_SerialCommunication->SetReceiveTimeout(1000); + if (m_SerialCommunication->OpenConnection() == 0) // 0 == ERROR_VALUE + { + m_SerialCommunication->CloseConnection(); + m_SerialCommunication = nullptr; + MITK_ERROR << "[Quantel Laser Debug] " << "Can not open serial port"; + return false; + } + + if (this->GetState() != UNCONNECTED) + { + std::string *command = new std::string; + std::string answer(""); + command->assign("STOP"); + this->SendAndReceiveLine(command, &answer); + return true; + } + else + return false; +} + +bool mitk::QuantelLaser::CloseConnection() +{ + if (this->GetState() != UNCONNECTED) + { + this->StopQswitching(); + this->StopFlashing(); + + // close the serial connection + m_SerialCommunication->CloseConnection(); + m_SerialCommunication = nullptr; + this->GetState(); + } + return true; +} + +mitk::QuantelLaser::LaserState mitk::QuantelLaser::GetState() +{ + if (m_SerialCommunication == nullptr) + { + m_State = UNCONNECTED; + return m_State; + } + + if (!m_SerialCommunication->IsConnected()) + { + m_State = UNCONNECTED; + return m_State; + } + + std::string *command = new std::string; + std::string answer(""); + command->assign("STATE"); + this->SendAndReceiveLine(command, &answer); + MITK_INFO << "[Quantel Laser Debug] get state:" << answer; + if (answer == "STATE = 0\n") + m_State = STATE0; + else if(answer == "STATE = 1\n") + { + m_State = STATE1; + m_FlashlampRunning = false; + m_ShutterOpen = false; + m_LaserEmission = false; + } + else if(answer == "STATE = 2\n") // laser ready for RUN + { + m_State = STATE2; + m_FlashlampRunning = false; + m_ShutterOpen = false; + m_LaserEmission = false; + } + else if(answer == "STATE = 3\n") + { + m_State = STATE3; + m_FlashlampRunning = true; + m_ShutterOpen = false; + m_LaserEmission = false; + } + else if(answer == "STATE = 4\n") + { + m_State = STATE4; + m_FlashlampRunning = true; + m_ShutterOpen = false; + m_LaserEmission = false; + } + else if (answer == "STATE = 5\n") + { + m_State = STATE5; + m_FlashlampRunning = true; + m_ShutterOpen = true; + m_LaserEmission = false; + } + else if (answer == "STATE = 6\n") + { + m_State = STATE6; + m_FlashlampRunning = true; + m_ShutterOpen = true; + m_LaserEmission = true; + } + else if (answer == "STATE = 7\n") + { + m_State = STATE7; + m_FlashlampRunning = true; + m_ShutterOpen = true; + m_LaserEmission = true; + } + else + { + m_State = UNCONNECTED; + m_FlashlampRunning = false; + m_ShutterOpen = false; + m_LaserEmission = false; + } + + return m_State; +} + + +void mitk::QuantelLaser::StayAlive() +{ + do{ + std::this_thread::sleep_for(std::chrono::seconds(2)); + std::string *command = new std::string; + std::string answer(""); + command->assign("STATE"); + this->SendAndReceiveLine(command, &answer); + } while (m_KeepAlive); +} + +bool mitk::QuantelLaser::StartFlashing() +{ + this->GetState(); + if (!m_FlashlampRunning) + { + if (m_LaserEmission) + this->StopQswitching(); + + std::string *command = new std::string; + std::string answer(""); + command->assign("RUN"); + this->SendAndReceiveLine(command, &answer); + MITK_INFO << answer; + if (answer.at(0) == 'O' && answer.at(1) == 'K') + { + m_FlashlampRunning = true; + m_ShutterOpen = false; + m_KeepAlive = true; + //m_StayAliveMessageThread = std::thread(&mitk::QuantelLaser::StayAlive, this); + } + else + { + MITK_ERROR << "[Quantel Laser Debug] " << "Cannot start flashlamps." << " Laser is telling me: " << answer; + return false; + } + } + else + MITK_INFO << "[Quantel Laser Debug] " << "Flashlamps are already running"; + + return true; +} + +bool mitk::QuantelLaser::StopFlashing() +{ + this->GetState(); + if (m_FlashlampRunning) + { + if (m_LaserEmission) + this->StopQswitching(); + + std::string *command = new std::string; + std::string answer(""); + command->assign("STOP"); + this->SendAndReceiveLine(command, &answer); + MITK_INFO << answer; + if (answer.at(0) == 'O' && answer.at(1) == 'K') + { + m_FlashlampRunning = false; + m_ShutterOpen = false; + m_KeepAlive = false; + } + else + { + MITK_ERROR << "[Quantel Laser Debug] " << "Cannot Stop flashlamps." << " Laser is telling me: " << answer; + return false; + } + + } + else + MITK_INFO << "[Quantel Laser Debug] " << "Flashlamps are not running"; + + return true; +} + +bool mitk::QuantelLaser::StartQswitching() +{ + this->GetState(); + if (!m_LaserEmission) + { + std::string *command = new std::string; + std::string answer(""); + command->assign("QSW 1"); + this->SendAndReceiveLine(command, &answer); + MITK_INFO << answer; + if (answer.at(0) == 'O' && answer.at(1) == 'K') + { + m_FlashlampRunning = true; + m_ShutterOpen = true; + return true; + } + else + { + MITK_ERROR << "[Quantel Laser Debug] " << "Cannot start Qswitch." << " Laser is telling me: " << answer; + return false; + } + } + else + { + MITK_INFO << "[Quantel Laser Debug] " << "Laser is already emitting"; + return true; + } +} + +bool mitk::QuantelLaser::StopQswitching() +{ + this->GetState(); + if (m_FlashlampRunning && m_LaserEmission) + { + std::string *command = new std::string; + std::string answer(""); + command->assign("QSW 0"); + this->SendAndReceiveLine(command, &answer); + MITK_INFO << answer; + if (answer.at(0) == 'O' && answer.at(1) == 'K') + { + m_LaserEmission = false; + } + else + MITK_ERROR << "[Quantel Laser Debug] " << "Cannot stop Q-switch."; + + } + return true; +} + +bool mitk::QuantelLaser::IsEmitting() +{ + return m_LaserEmission; +} +bool mitk::QuantelLaser::IsFlashing() +{ + return m_FlashlampRunning; +} \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/mitkQuantelLaser.h b/Modules/PhotoacousticsHardware/mitkQuantelLaser.h new file mode 100644 index 0000000000..fda48f9b15 --- /dev/null +++ b/Modules/PhotoacousticsHardware/mitkQuantelLaser.h @@ -0,0 +1,109 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +#ifndef MITKQUANTELLASER_H_HEADER_INCLUDED +#define MITKQUANTELLASER_H_HEADER_INCLUDED + +#include "itkObject.h" +#include "mitkCommon.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mitkSerialCommunication.h" +#include "MitkPhotoacousticsHardwareExports.h" + +namespace mitk { + + class MITKPHOTOACOUSTICSHARDWARE_EXPORT QuantelLaser : public itk::LightObject + { + public: + mitkClassMacroItkParent(QuantelLaser, itk::LightObject); + itkFactorylessNewMacro(Self); + + enum LaserState { UNCONNECTED, STATE0, STATE1, STATE2, STATE3, STATE4, STATE5, STATE6, STATE7 }; ///< Type for STATE variable. The LaserDevice is always in one of these states + /** + * \brief Opens a connection to the device + * + * This may only be called if there is currently no connection to the device. + * If OpenConnection() is successful, the object will change from UNCONNECTED state to a STATE state + */ + virtual bool OpenConnection(std::string configurationFile); + + /** + * \brief Closes the connection to the device + * + * This may only be called if there is currently a connection to the device. (e.g. object is in a STATE state) + */ + virtual bool CloseConnection(); ///< Closes the connection with the device + + virtual std::string SendAndReceiveLine(const std::string* input, std::string* answer); + + virtual void StayAlive(); + virtual bool StartFlashing(); + virtual bool StopFlashing(); + + virtual bool StartQswitching(); + virtual bool StopQswitching(); + virtual bool IsEmitting(); + virtual bool IsFlashing(); + + virtual LaserState GetState(); + + typedef mitk::SerialCommunication::PortNumber PortNumber; ///< Port number of the serial connection + typedef mitk::SerialCommunication::BaudRate BaudRate; ///< Baud rate of the serial connection + typedef mitk::SerialCommunication::DataBits DataBits; ///< Number of data bits used in the serial connection + typedef mitk::SerialCommunication::Parity Parity; ///< Parity mode used in the serial connection + typedef mitk::SerialCommunication::StopBits StopBits; ///< Number of stop bits used in the serial connection + typedef mitk::SerialCommunication::HardwareHandshake HardwareHandshake; ///< Hardware handshake mode of the serial connection + + private: + LaserState m_State; ///< current Laser state + protected: + + QuantelLaser(); + virtual ~QuantelLaser(); + + bool m_KeepAlive = false; + bool m_FlashlampRunning = false; + bool m_ShutterOpen = false; + bool m_LaserEmission = false; + void LoadResorceFile(std::string filename, std::string* lines); + + std::string m_DeviceName;///< Device Name + PortNumber m_PortNumber; ///< COM Port Number + BaudRate m_BaudRate; ///< COM Port Baud Rate + DataBits m_DataBits; ///< Number of Data Bits per token + Parity m_Parity; ///< Parity mode for communication + StopBits m_StopBits; ///< number of stop bits per token + HardwareHandshake m_HardwareHandshake; ///< use hardware handshake for serial port connection + + std::string m_XmlPumpLaserConfiguration; + mitk::SerialCommunication::Pointer m_SerialCommunication; ///< serial communication interface + std::thread m_StayAliveMessageThread; + std::mutex m_SerialCommunicationMutex; ///< mutex for coordinated access of serial communication interface + }; +} // namespace mitk + +#endif /* MITKQUANTELLASER_H_HEADER_INCLUDED */ diff --git a/Modules/US/CMakeLists.txt b/Modules/US/CMakeLists.txt index b56d76e52a..5add219afe 100644 --- a/Modules/US/CMakeLists.txt +++ b/Modules/US/CMakeLists.txt @@ -1,15 +1,16 @@ MITK_CREATE_MODULE( SUBPROJECTS INCLUDE_DIRS USControlInterfaces USFilters USModel INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} PACKAGE_DEPENDS Poco DEPENDS MitkOpenCVVideoSupport MitkQtWidgetsExt MitkIGTBase MitkOpenIGTLink ) ## create US config #CONFIGURE_FILE(mitkUSConfig.h.in ${PROJECT_BINARY_DIR}/mitkUSConfig.h @ONLY) ADD_SUBDIRECTORY(USHardwareTelemed) +ADD_SUBDIRECTORY(USHardwareDiPhAS) ADD_SUBDIRECTORY(USNavigation) ADD_SUBDIRECTORY(Testing) diff --git a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp new file mode 100644 index 0000000000..4903694259 --- /dev/null +++ b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp @@ -0,0 +1,192 @@ +/*=================================================================== + +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 "mitkUSDiPhASDeviceCustomControls.h" + +mitk::USDiPhASDeviceCustomControls::USDiPhASDeviceCustomControls(itk::SmartPointer device) + : mitk::USAbstractControlInterface(device.GetPointer()), m_IsActive(false), silentUpdate(false) +{ +} + +mitk::USDiPhASDeviceCustomControls::~USDiPhASDeviceCustomControls() +{ +} + +void mitk::USDiPhASDeviceCustomControls::SetIsActive(bool isActive) +{ + m_IsActive = isActive; +} + +bool mitk::USDiPhASDeviceCustomControls::GetIsActive() +{ + return m_IsActive; +} + +void mitk::USDiPhASDeviceCustomControls::passGUIOut(std::function callback) {} + +void mitk::USDiPhASDeviceCustomControls::SetSilentUpdate(bool silent) +{ + silentUpdate = silent; +} + +bool mitk::USDiPhASDeviceCustomControls::GetSilentUpdate() +{ + return silentUpdate; +} + +//Set Functions + +void mitk::USDiPhASDeviceCustomControls::SetUseBModeFilter(bool isSet) +{ + this->OnSetUseBModeFilter(isSet); +} + +void mitk::USDiPhASDeviceCustomControls::SetRecord(bool record) +{ + this->OnSetRecord(record); +} + +void mitk::USDiPhASDeviceCustomControls::SetVerticalSpacing(float mm) +{ + this->OnSetVerticalSpacing(mm); +} + +void mitk::USDiPhASDeviceCustomControls::SetScatteringCoefficient(float coeff) +{ + this->OnSetScatteringCoefficient(coeff); +} +void mitk::USDiPhASDeviceCustomControls::SetCompensateScattering(bool compensate) +{ + this->OnSetCompensateScattering(compensate); +} + +//Transmit +void mitk::USDiPhASDeviceCustomControls::SetTransmitPhaseLength(double us) +{ + this->OnSetTransmitPhaseLength(us); +} + +void mitk::USDiPhASDeviceCustomControls::SetExcitationFrequency(double MHz) +{ + this->OnSetExcitationFrequency(MHz); +} + +void mitk::USDiPhASDeviceCustomControls::SetTransmitEvents(int events) +{ + this->OnSetTransmitEvents(events); +} + +void mitk::USDiPhASDeviceCustomControls::SetVoltage(int voltage) +{ + this->OnSetVoltage(voltage); +} + +void mitk::USDiPhASDeviceCustomControls::SetMode(bool interleaved) +{ + this->OnSetMode(interleaved); +} + +//Receive +void mitk::USDiPhASDeviceCustomControls::SetScanDepth(double mm) +{ + this->OnSetScanDepth(mm); +} + +void mitk::USDiPhASDeviceCustomControls::SetAveragingCount(int count) +{ + this->OnSetAveragingCount(count); +} + +void mitk::USDiPhASDeviceCustomControls::SetTGCMin(int min) +{ + this->OnSetTGCMin(min); +} + +void mitk::USDiPhASDeviceCustomControls::SetTGCMax(int max) +{ + this->OnSetTGCMax(max); +} + +void mitk::USDiPhASDeviceCustomControls::SetDataType(DataType type) +{ + this->OnSetDataType(type); +} + +//Beamforming +void mitk::USDiPhASDeviceCustomControls::SetPitch(double mm) +{ + this->OnSetPitch(mm); +} + +void mitk::USDiPhASDeviceCustomControls::SetReconstructedSamples(int samples) +{ + this->OnSetReconstructedSamples(samples); +} + +void mitk::USDiPhASDeviceCustomControls::SetReconstructedLines(int lines) +{ + this->OnSetReconstructedLines(lines); +} + +void mitk::USDiPhASDeviceCustomControls::SetSpeedOfSound(int mps) +{ + this->OnSetSpeedOfSound(mps); +} + +//Bandpass +void mitk::USDiPhASDeviceCustomControls::SetBandpassEnabled(bool bandpass) +{ + this->OnSetBandpassEnabled(bandpass); +} + +void mitk::USDiPhASDeviceCustomControls::SetLowCut(double MHz) +{ + this->OnSetLowCut(MHz); +} + +void mitk::USDiPhASDeviceCustomControls::SetHighCut(double MHz) +{ + this->OnSetHighCut(MHz); +} + + +//OnSetDummies +void mitk::USDiPhASDeviceCustomControls::OnSetUseBModeFilter(bool isSet) {} +void mitk::USDiPhASDeviceCustomControls::OnSetRecord(bool record) {} +void mitk::USDiPhASDeviceCustomControls::OnSetVerticalSpacing(float mm) {} +void mitk::USDiPhASDeviceCustomControls::OnSetScatteringCoefficient(float coeff) {} +void mitk::USDiPhASDeviceCustomControls::OnSetCompensateScattering(bool compensate) {} +//Transmit +void mitk::USDiPhASDeviceCustomControls::OnSetTransmitPhaseLength(double ms) {} +void mitk::USDiPhASDeviceCustomControls::OnSetExcitationFrequency(double MHz) {} +void mitk::USDiPhASDeviceCustomControls::OnSetTransmitEvents(int events) {} +void mitk::USDiPhASDeviceCustomControls::OnSetVoltage(int voltage) {} +void mitk::USDiPhASDeviceCustomControls::OnSetMode(bool interleaved) {} +//Receive +void mitk::USDiPhASDeviceCustomControls::OnSetScanDepth(double mm) {} +void mitk::USDiPhASDeviceCustomControls::OnSetAveragingCount(int count) {} +void mitk::USDiPhASDeviceCustomControls::OnSetTGCMin(int min) {} +void mitk::USDiPhASDeviceCustomControls::OnSetTGCMax(int max) {} +void mitk::USDiPhASDeviceCustomControls::OnSetDataType(DataType type) {} +//Beamforming +void mitk::USDiPhASDeviceCustomControls::OnSetPitch(double mm) {} +void mitk::USDiPhASDeviceCustomControls::OnSetReconstructedSamples(int samples) {} +void mitk::USDiPhASDeviceCustomControls::OnSetReconstructedLines(int lines) {} +void mitk::USDiPhASDeviceCustomControls::OnSetSpeedOfSound(int mps) {} +//Bandpass +void mitk::USDiPhASDeviceCustomControls::OnSetBandpassEnabled(bool bandpass) {} +void mitk::USDiPhASDeviceCustomControls::OnSetLowCut(double MHz) {} +void mitk::USDiPhASDeviceCustomControls::OnSetHighCut(double MHz) {} diff --git a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.h b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.h new file mode 100644 index 0000000000..94d703fa54 --- /dev/null +++ b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.h @@ -0,0 +1,135 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef MITKUSDiPhASDeviceCustomControls_H_HEADER_INCLUDED_ +#define MITKUSDiPhASDeviceCustomControls_H_HEADER_INCLUDED_ + +#include "mitkUSAbstractControlInterface.h" +#include "mitkUSImageVideoSource.h" +#include "mitkUSDevice.h" + +#include + +#include +#include + +namespace mitk { +/** + * \brief Custom controls for mitk::USDiPhASDevice. + */ +class MITKUS_EXPORT USDiPhASDeviceCustomControls : public USAbstractControlInterface +{ +public: + mitkClassMacro(USDiPhASDeviceCustomControls, USAbstractControlInterface); + mitkNewMacro1Param(Self, itk::SmartPointer); + + /** + * Activate or deactivate the custom controls. This is just for handling + * widget visibility in a GUI for example. + */ + virtual void SetIsActive( bool isActive ) override; + + enum DataType { Image_uChar, Beamformed_Short }; + /** + * \return if this custom controls are currently activated + */ + virtual bool GetIsActive( ) override; + + virtual void SetUseBModeFilter(bool isSet); + virtual void SetVerticalSpacing(float mm); + virtual void SetRecord(bool record); + virtual void SetScatteringCoefficient(float coeff); + virtual void SetCompensateScattering(bool compensate); + + //Transmit + virtual void SetTransmitPhaseLength(double us); + virtual void SetExcitationFrequency(double MHz); + virtual void SetTransmitEvents(int events); + virtual void SetVoltage(int voltage); + virtual void SetMode(bool interleaved); + + //Receive + virtual void SetScanDepth(double mm); + virtual void SetAveragingCount(int count); + virtual void SetTGCMin(int min); + virtual void SetTGCMax(int max); + virtual void SetDataType(DataType type); + + //Beamforming + virtual void SetPitch(double mm); + virtual void SetReconstructedSamples(int samples); + virtual void SetReconstructedLines(int lines); + virtual void SetSpeedOfSound(int mps); + + //Bandpass + virtual void SetBandpassEnabled(bool bandpass); + virtual void SetLowCut(double MHz); + virtual void SetHighCut(double MHz); + + virtual void passGUIOut(std::function callback); + virtual void SetSilentUpdate(bool silent); + virtual bool GetSilentUpdate(); + + + +protected: + /** + * Class needs an mitk::USDevice object for beeing constructed. + */ + USDiPhASDeviceCustomControls( itk::SmartPointer device ); + virtual ~USDiPhASDeviceCustomControls( ); + + bool m_IsActive; + USImageVideoSource::Pointer m_ImageSource; + bool silentUpdate; + + /** virtual handlers implemented in Device Controls + */ + + virtual void OnSetUseBModeFilter(bool isSet); + virtual void OnSetRecord(bool record); + virtual void OnSetVerticalSpacing(float mm); + virtual void OnSetScatteringCoefficient(float coeff); + virtual void OnSetCompensateScattering(bool compensate); + //Transmit + virtual void OnSetTransmitPhaseLength(double us); + virtual void OnSetExcitationFrequency(double MHz); + virtual void OnSetTransmitEvents(int events); + virtual void OnSetVoltage(int voltage); + virtual void OnSetMode(bool interleaved); + + //Receive + virtual void OnSetScanDepth(double mm); + virtual void OnSetAveragingCount(int count); + virtual void OnSetTGCMin(int min); + virtual void OnSetTGCMax(int max); + virtual void OnSetDataType(DataType type); + + //Beamforming + virtual void OnSetPitch(double mm); + virtual void OnSetReconstructedSamples(int samples); + virtual void OnSetReconstructedLines(int lines); + virtual void OnSetSpeedOfSound(int mps); + + //Bandpass + virtual void OnSetBandpassEnabled(bool bandpass); + virtual void OnSetLowCut(double MHz); + virtual void OnSetHighCut(double MHz); + +}; +} // namespace mitk + +#endif // MITKUSDiPhASDeviceCustomControls_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/CMakeLists.txt b/Modules/US/USHardwareDiPhAS/CMakeLists.txt new file mode 100644 index 0000000000..00c5ff6690 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/CMakeLists.txt @@ -0,0 +1,20 @@ +IF(WIN32) + +OPTION(MITK_USE_US_DiPhAS_SDK "Enable support for DiPhAS API devices" OFF) + +IF(MITK_USE_US_DiPhAS_SDK) + +SET(MITK_US_DiPhAS_SDK_PATH "" CACHE PATH "Path to DiPhAS SDK header files.") + +MITK_CREATE_MODULE( + SUBPROJECTS + DEPENDS MitkUS MitkPhotoacousticsHardware + INCLUDE_DIRS PUBLIC "${MITK_US_DiPhAS_SDK_PATH}/Debug" "${MITK_US_DiPhAS_SDK_PATH}/Release" + INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} + ADDITIONAL_LIBS "${MITK_US_DiPhAS_SDK_PATH}/Debug/Framework.IBMT.US.CWrapper.lib" "${MITK_US_DiPhAS_SDK_PATH}/Release/Framework.IBMT.US.CWrapper.lib" + AUTOLOAD_WITH MitkUS +) + +ENDIF(MITK_USE_US_DiPhAS_SDK) + +ENDIF(WIN32) diff --git a/Modules/US/USHardwareDiPhAS/FranzTissue.nrrd b/Modules/US/USHardwareDiPhAS/FranzTissue.nrrd new file mode 100644 index 0000000000..224a89f7ff Binary files /dev/null and b/Modules/US/USHardwareDiPhAS/FranzTissue.nrrd differ diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkAnalyticSignalImageFilter.h b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkAnalyticSignalImageFilter.h new file mode 100644 index 0000000000..bebba4955b --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkAnalyticSignalImageFilter.h @@ -0,0 +1,143 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkAnalyticSignalImageFilter_h +#define itkAnalyticSignalImageFilter_h + +#include + +#include "itkFFT1DComplexToComplexImageFilter.h" +#include "itkFFT1DRealToComplexConjugateImageFilter.h" +#include "itkImageRegionSplitterDirection.h" + +namespace itk +{ +/** \class AnalyticSignalImageFilter + * \brief Generates the analytic signal from one direction of an image. + * + * This filter generates the complex valued analytic signal along one direction + * of an image. This input is a real valued image, and the output is a complex + * image. + * + * The analytic signal is given by + * + * f_a(x) = f(x) - i f_H(x) + * + * Where i is the square root of one and f_H(x) is the Hibert transform of f(x). + * + * Since the Hilbert transform in the Fourier domain is + * + * F_H(k) = F(k) i sign(k), + * + * f_a(x) is calculated by + * + * f_a(x) = F^{-1}( F(k) 2 U(k) ) + * + * where U(k) is the unit step function. + * + * \ingroup FourierTransform + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage > +class AnalyticSignalImageFilter: + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension); + + typedef AnalyticSignalImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkTypeMacro( AnalyticSignalImageFilter, ImageToImageFilter ); + itkNewMacro( Self ); + + /** Get the direction in which the filter is to be applied. */ + virtual unsigned int GetDirection() const + { + return this->m_FFTRealToComplexFilter->GetDirection(); + } + + /** Set the direction in which the filter is to be applied. */ + virtual void SetDirection( const unsigned int direction ) + { + if( this->m_FFTRealToComplexFilter->GetDirection() != direction ) + { + this->m_FFTRealToComplexFilter->SetDirection( direction ); + this->m_FFTComplexToComplexFilter->SetDirection( direction ); + this->Modified(); + } + } + +protected: + AnalyticSignalImageFilter(); + virtual ~AnalyticSignalImageFilter() {} + + void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + + // These behave like their analogs in FFT1DRealToComplexConjugateImageFilter. + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + virtual void BeforeThreadedGenerateData() ITK_OVERRIDE; + virtual void ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId ) ITK_OVERRIDE; + virtual void AfterThreadedGenerateData() ITK_OVERRIDE; + + typedef FFT1DRealToComplexConjugateImageFilter< InputImageType, OutputImageType > FFTRealToComplexType; + typedef FFT1DComplexToComplexImageFilter< OutputImageType, OutputImageType > FFTComplexToComplexType; + + typename FFTRealToComplexType::Pointer m_FFTRealToComplexFilter; + typename FFTComplexToComplexType::Pointer m_FFTComplexToComplexFilter; + + /** Override to return a splitter that does not split along the direction we + * are performing the transform. */ + virtual const ImageRegionSplitterBase* GetImageRegionSplitter() const ITK_OVERRIDE; + +private: + AnalyticSignalImageFilter( const Self& ); // purposely not implemented + void operator=( const Self& ); // purposely not implemented + + ImageRegionSplitterDirection::Pointer m_ImageRegionSplitter; +}; +} + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkAnalyticSignalImageFilter.hxx" +#endif + +#endif // itkAnalyticSignalImageFilter_h diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkAnalyticSignalImageFilter.hxx b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkAnalyticSignalImageFilter.hxx new file mode 100644 index 0000000000..a48bcba4cb --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkAnalyticSignalImageFilter.hxx @@ -0,0 +1,271 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkAnalyticSignalImageFilter_hxx +#define itkAnalyticSignalImageFilter_hxx + +#include "itkAnalyticSignalImageFilter.h" + +#include "itkVnlFFT1DRealToComplexConjugateImageFilter.h" +#include "itkVnlFFT1DComplexToComplexImageFilter.h" + +#if defined(ITK_USE_FFTWD) || defined(ITK_USE_FFTWF) +#include "itkFFTW1DRealToComplexConjugateImageFilter.h" +#include "itkFFTW1DComplexToComplexImageFilter.h" +#endif + +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" +#include "itkMetaDataObject.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::AnalyticSignalImageFilter() +{ + m_FFTRealToComplexFilter = FFTRealToComplexType::New(); + m_FFTComplexToComplexFilter = FFTComplexToComplexType::New(); + + m_FFTComplexToComplexFilter->SetTransformDirection( FFTComplexToComplexType::INVERSE ); + + this->SetDirection( 0 ); + + this->m_ImageRegionSplitter = ImageRegionSplitterDirection::New(); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + typename InputImageType::Pointer inputPtr = + const_cast (this->GetInput()); + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->GetDirection(); + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast< OutputImageType* >( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + const unsigned int direction = this->GetDirection (); + enlargedSize[direction] = outputLargeSize[direction]; + enlargedIndex[direction] = outputLargeIndex[direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + const unsigned int direction = this->GetDirection(); + os << indent << "Direction: " << direction << std::endl; + + os << indent << "FFTRealToComplexFilter: " << std::endl; + m_FFTRealToComplexFilter->Print( os, indent ); + os << indent << "FFTComplexToComplexFilter: " << std::endl; + m_FFTComplexToComplexFilter->Print( os, indent ); +} + + +template< typename TInputImage, typename TOutputImage > +const ImageRegionSplitterBase * +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::GetImageRegionSplitter() const +{ + return this->m_ImageRegionSplitter.GetPointer(); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::BeforeThreadedGenerateData() +{ + this->m_ImageRegionSplitter->SetDirection( this->GetDirection() ); + + m_FFTRealToComplexFilter->SetInput( this->GetInput() ); + m_FFTRealToComplexFilter->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); + m_FFTRealToComplexFilter->GetOutput()->SetLargestPossibleRegion( this->GetOutput()->GetLargestPossibleRegion() ); + m_FFTRealToComplexFilter->SetNumberOfThreads( this->GetNumberOfThreads() ); + m_FFTRealToComplexFilter->Update (); +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType itkNotUsed( threadId ) ) +{ + // get pointers to the input and output + const typename FFTRealToComplexType::OutputImageType * inputPtr = m_FFTRealToComplexFilter->GetOutput(); + OutputImageType * outputPtr = this->GetOutput(); + + const typename FFTRealToComplexType::OutputImageType::SizeType & inputSize = inputPtr->GetRequestedRegion().GetSize(); + const unsigned int direction = this->GetDirection (); + const unsigned int size = inputSize[direction]; + unsigned int dub_size; + bool even; + if( size % 2 == 0 ) + { + even = true; + dub_size = size / 2 - 1; + } + else + { + even = false; + dub_size = (size + 1) / 2 - 1; + } + + typedef ImageLinearConstIteratorWithIndex< typename FFTRealToComplexType::OutputImageType > InputIteratorType; + typedef ImageLinearIteratorWithIndex< OutputImageType > OutputIteratorType; + InputIteratorType inputIt( inputPtr, outputRegionForThread ); + OutputIteratorType outputIt( outputPtr, outputRegionForThread ); + inputIt.SetDirection( direction ); + outputIt.SetDirection( direction ); + + unsigned int i; + // for every fft line + for( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); + outputIt.NextLine(), inputIt.NextLine() ) + { + inputIt.GoToBeginOfLine(); + outputIt.GoToBeginOfLine(); + + // DC + outputIt.Set( inputIt.Get() ); + ++inputIt; + ++outputIt; + + for( i = 0; i < dub_size; i++ ) + { + outputIt.Set( inputIt.Get() * static_cast< typename TInputImage::PixelType >( 2 ) ); + ++outputIt; + ++inputIt; + } + if( even ) + { + outputIt.Set( inputIt.Get() ); + ++inputIt; + ++outputIt; + } + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( static_cast< typename TInputImage::PixelType >( 0 ) ); + ++outputIt; + } + } +} + + +template< typename TInputImage, typename TOutputImage > +void +AnalyticSignalImageFilter< TInputImage, TOutputImage > +::AfterThreadedGenerateData() +{ + // Trippy, eh? + m_FFTComplexToComplexFilter->SetInput( this->GetOutput() ); + m_FFTComplexToComplexFilter->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); + m_FFTComplexToComplexFilter->GetOutput()->SetLargestPossibleRegion( this->GetOutput()->GetLargestPossibleRegion() ); + m_FFTComplexToComplexFilter->SetNumberOfThreads( this->GetNumberOfThreads() ); + m_FFTComplexToComplexFilter->Update (); + this->GraftOutput( m_FFTComplexToComplexFilter->GetOutput() ); +} + +} // end namespace itk + +#endif // itkAnalyticSignalImageFilter_hxx diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkBModeImageFilter.h b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkBModeImageFilter.h new file mode 100644 index 0000000000..54bd15b325 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkBModeImageFilter.h @@ -0,0 +1,156 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkBModeImageFilter_h +#define itkBModeImageFilter_h + +#include "itkAddImageFilter.h" +#include "itkComplexToModulusImageFilter.h" +#include "itkConstantPadImageFilter.h" +#include "itkRegionFromReferenceImageFilter.h" +#include "itkImageToImageFilter.h" +#include "itkImage.h" +#include "itkLog10ImageFilter.h" + +#include "itkAnalyticSignalImageFilter.h" + +namespace itk +{ + +/** + * \class BModeImageFilter + * + * \brief Create an ultrasound B-Mode (Brightness-Mode) image from raw + * "RF" data. The RF's envelope is calculated from the analytic signal and + * logarithmic intensity transform is applied. + * + * Use SetDirection() to define the axis of propagation. + * + * \ingroup Ultrasound + * + * \sa AnalyticSignalImageFilter + * + */ +template < typename TInputImage, typename TOutputImage=TInputImage, typename TComplexImage=Image< std::complex< typename TInputImage::PixelType >, TInputImage::ImageDimension > > +class BModeImageFilter : + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef BModeImageFilter Self; + typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + /** The type of input image. */ + typedef TInputImage InputImageType; + + /** Dimension of the input and output images. */ + itkStaticConstMacro (ImageDimension, unsigned int, + TInputImage::ImageDimension); + + /** Typedef support for the input image scalar value type. */ + typedef typename InputImageType::PixelType InputPixelType; + + /** The type of output image. */ + typedef TOutputImage OutputImageType; + + /** Typedef support for the output image scalar value type. */ + typedef typename OutputImageType::PixelType OutputPixelType; + + /** Typedef of the image used for internal computations that has + * std::complex pixels. */ + typedef TComplexImage ComplexImageType; + + /** Other convenient typedefs */ + typedef typename InputImageType::RegionType InputRegionType; + typedef typename InputImageType::SizeType InputSizeType; + typedef typename InputImageType::IndexType InputIndexType; + + /** Run-time type information (and related methods) */ + itkTypeMacro( BModeImageFilter, ImageToImageFilter ); + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Set the direction in which the envelope is to be calculated. */ + virtual void SetDirection( unsigned int direction ) + { + this->m_AnalyticFilter->SetDirection( direction ); + this->Modified(); + } + + /** Get the direction in which the envelope is to be calculated. */ + virtual unsigned int GetDirection() const + { + return m_AnalyticFilter->GetDirection(); + } + +protected: + BModeImageFilter(); + ~BModeImageFilter() {} + + virtual void PrintSelf( std::ostream& os, Indent indent ) const ITK_OVERRIDE; + + virtual void GenerateData() ITK_OVERRIDE; + + // These behave like their analogs in FFT1DRealToComplexConjugateImageFilter. + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + /** Component filters. */ + typedef AnalyticSignalImageFilter< InputImageType, ComplexImageType > AnalyticType; + typedef ComplexToModulusImageFilter< typename AnalyticType::OutputImageType, OutputImageType > ComplexToModulusType; + typedef ConstantPadImageFilter< InputImageType, InputImageType > PadType; + typedef AddImageFilter< InputImageType, InputImageType > AddConstantType; + typedef Log10ImageFilter< InputImageType, OutputImageType > LogType; + typedef RegionFromReferenceImageFilter< OutputImageType, OutputImageType > ROIType; + +private: + BModeImageFilter( const Self& ); // purposely not implemented + void operator=( const Self& ); // purposely not implemented + + typename AnalyticType::Pointer m_AnalyticFilter; + typename ComplexToModulusType::Pointer m_ComplexToModulusFilter; + typename PadType::Pointer m_PadFilter; + typename AddConstantType::Pointer m_AddConstantFilter; + typename LogType::Pointer m_LogFilter; + typename ROIType::Pointer m_ROIFilter; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkBModeImageFilter.hxx" +#endif + +#endif // itkBModeImageFilter_h \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkBModeImageFilter.hxx b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkBModeImageFilter.hxx new file mode 100644 index 0000000000..aa511e03b2 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkBModeImageFilter.hxx @@ -0,0 +1,212 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkBModeImageFilter_hxx +#define itkBModeImageFilter_hxx + +#include "itkBModeImageFilter.h" + +#include "itkMetaDataDictionary.h" + +#include +#include +#include + +namespace itk +{ + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::BModeImageFilter() +{ + m_AnalyticFilter = AnalyticType::New(); + m_ComplexToModulusFilter = ComplexToModulusType::New(); + m_PadFilter = PadType::New(); + m_AddConstantFilter = AddConstantType::New(); + m_LogFilter = LogType::New(); + m_ROIFilter = ROIType::New(); + + // Avoid taking the log of zero. Assuming that the original input is coming + // from a digitizer that outputs integer types, so 1 is small. + m_AddConstantFilter->SetConstant2( 1 ); + m_PadFilter->SetConstant( 0. ); + + m_ComplexToModulusFilter->SetInput( m_AnalyticFilter->GetOutput() ); + m_ROIFilter->SetInput( m_ComplexToModulusFilter->GetOutput() ); + m_LogFilter->SetInput( m_AddConstantFilter->GetOutput() ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + InputImageType * inputPtr = const_cast (this->GetInput()); + OutputImageType * outputPtr = this->GetOutput(); + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->GetDirection(); + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast< OutputImageType* >( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + const unsigned int direction = this->GetDirection (); + enlargedSize[direction] = outputLargeSize[direction]; + enlargedIndex[direction] = outputLargeIndex[direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template < typename TInputImage, typename TOutputImage, typename TComplexImage > +void +BModeImageFilter< TInputImage, TOutputImage, TComplexImage > +::GenerateData() +{ + this->AllocateOutputs(); + + const InputImageType * inputPtr = this->GetInput(); + OutputImageType * outputPtr = this->GetOutput(); + + const unsigned int direction = m_AnalyticFilter->GetDirection(); + typename InputImageType::SizeType size = inputPtr->GetLargestPossibleRegion().GetSize(); + + // Zero padding. FFT direction should be factorable by 2 for all FFT + // implementations to work. + unsigned int n = size[direction]; + while( n % 2 == 0 ) + { + n /= 2; + } + bool doPadding; + if( n == 1 ) + { + doPadding = false; + } + else + { + doPadding = true; + } + if( doPadding ) + { + n = size[direction]; + unsigned int newSizeDirection = 1; + while( newSizeDirection < n ) + { + newSizeDirection *= 2; + } + typename InputImageType::SizeType padSize; + padSize.Fill( 0 ); + padSize[direction] = newSizeDirection - size[direction]; + size[direction] = newSizeDirection; + m_PadFilter->SetPadUpperBound( padSize ); + m_PadFilter->SetInput( inputPtr ); + m_AnalyticFilter->SetInput( m_PadFilter->GetOutput() ); + m_ROIFilter->SetReferenceImage( inputPtr ); + m_ROIFilter->SetInput( m_ComplexToModulusFilter->GetOutput() ); + m_AddConstantFilter->SetInput( m_ROIFilter->GetOutput() ); + } + else // padding is not required + { + m_AnalyticFilter->SetInput( inputPtr ); + m_AddConstantFilter->SetInput( m_ComplexToModulusFilter->GetOutput() ); + } + m_LogFilter->GraftOutput( outputPtr ); + m_LogFilter->Update(); + this->GraftOutput( m_LogFilter->GetOutput() ); +} + +} // end namespace itk + +#endif \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h new file mode 100644 index 0000000000..ed9b8b90f6 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.h @@ -0,0 +1,142 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DComplexToComplexImageFilter_h +#define itkFFT1DComplexToComplexImageFilter_h + +#include + +#include "itkImage.h" +#include "itkImageToImageFilter.h" +#include "itkImageRegionSplitterDirection.h" + +namespace itk +{ +/** \class FFT1DComplexToComplexImageFilter + * \brief Perform the Fast Fourier Transform, complex input to complex output, + * but only along one dimension. + * + * The direction of the transform, 'Forward' or 'Inverse', can be set with + * SetTransformDirection() and GetTransformDirection(). + * + * The dimension along which to apply to filter can be specified with + * SetDirection() and GetDirection(). + * + * \ingroup FourierTransform + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=TInputImage > +class FFT1DComplexToComplexImageFilter: + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + typedef FFT1DComplexToComplexImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension ); + + itkTypeMacro( FFT1DComplexToComplexImageFilter, ImageToImageFilter ); + + /** Customized object creation methods that support configuration-based + * selection of FFT implementation. + * + * Default implementation is VnlFFT1D. + */ + static Pointer New(); + + /** Transform direction. */ + typedef enum { DIRECT = 1, INVERSE } TransformDirectionType; + + /** Set/Get the direction in which the transform will be applied. + * By selecting DIRECT, this filter will perform a direct (forward) Fourier + * Transform. + * By selecting INVERSE, this filter will perform an inverse Fourier + * Transform. */ + itkSetMacro( TransformDirection, TransformDirectionType ); + itkGetConstMacro( TransformDirection, TransformDirectionType ); + + /** Get the direction in which the filter is to be applied. */ + itkGetMacro(Direction, unsigned int); + + /** Set the direction in which the filter is to be applied. */ + itkSetClampMacro(Direction, unsigned int, 0, ImageDimension - 1); + +protected: + FFT1DComplexToComplexImageFilter(); + virtual ~FFT1DComplexToComplexImageFilter() {} + + void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + virtual void BeforeThreadedGenerateData() ITK_OVERRIDE; + + /** Override to return a splitter that does not split along the direction we + * are performing the transform. */ + virtual const ImageRegionSplitterBase* GetImageRegionSplitter() const ITK_OVERRIDE; + + /** Direction in which the filter is to be applied + * this should be in the range [0,ImageDimension-1]. */ + unsigned int m_Direction; + + /** Direction to apply the transform (forward/inverse). */ + TransformDirectionType m_TransformDirection; + +private: + FFT1DComplexToComplexImageFilter( const Self& ); + void operator=( const Self& ); + + ImageRegionSplitterDirection::Pointer m_ImageRegionSplitter; +}; +} + +#ifndef ITK_MANUAL_INSTANTIATION +#ifndef itkVnlFFT1DComplexToComplexImageFilter_h +#ifndef itkVnlFFT1DComplexToComplexImageFilter_hxx +#ifndef itkFFTW1DComplexToComplexImageFilter_h +#ifndef itkFFTW1DComplexToComplexImageFilter_hxx +#include "itkFFT1DComplexToComplexImageFilter.hxx" +#endif +#endif +#endif +#endif +#endif + +#endif // itkFFT1DComplexToComplexImageFilter_h diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx new file mode 100644 index 0000000000..f287799e1c --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DComplexToComplexImageFilter.hxx @@ -0,0 +1,210 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DComplexToComplexImageFilter_hxx +#define itkFFT1DComplexToComplexImageFilter_hxx + +#include "itkFFT1DComplexToComplexImageFilter.h" + +#include "itkVnlFFT1DComplexToComplexImageFilter.h" + +#if defined(ITK_USE_FFTWD) || defined(ITK_USE_FFTWF) +#include "itkFFTW1DComplexToComplexImageFilter.h" +#endif + +#include "itkMetaDataDictionary.h" +#include "itkMetaDataObject.h" + +namespace itk +{ + +template < typename TInputImage, typename TOutputImage > +typename FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage >::Pointer +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::New() +{ + Pointer smartPtr = ::itk::ObjectFactory< Self >::Create(); + +#ifdef ITK_USE_FFTWD + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( double ) ) + { + smartPtr = dynamic_cast< Self* >( + FFTW1DComplexToComplexImageFilter< double, VDimension > + ::New().GetPointer() ); + } + } +#endif +#ifdef ITK_USE_FFTWF + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( float ) ) + { + smartPtr = dynamic_cast( + FFTW1DComplexToComplexImageFilter< float, VDimension > + ::New().GetPointer() ); + } + } +#endif + + if( smartPtr.IsNull() ) + { + smartPtr = VnlFFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > + ::New().GetPointer(); + } + + return smartPtr; +} + + +template< typename TInputImage, typename TOutputImage > +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::FFT1DComplexToComplexImageFilter(): + m_Direction(0), m_TransformDirection( DIRECT ) +{ + this->m_ImageRegionSplitter = ImageRegionSplitterDirection::New(); +} + + +template +const ImageRegionSplitterBase* +FFT1DComplexToComplexImageFilter < TInputImage, TOutputImage > +::GetImageRegionSplitter(void) const +{ + return this->m_ImageRegionSplitter.GetPointer(); +} + + +template +void +FFT1DComplexToComplexImageFilter < TInputImage, TOutputImage > +::BeforeThreadedGenerateData() +{ + this->m_ImageRegionSplitter->SetDirection( this->GetDirection() ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + typename InputImageType::Pointer inputPtr = + const_cast (this->GetInput()); + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->m_Direction; + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + enlargedSize[this->m_Direction] = outputLargeSize[this->m_Direction]; + enlargedIndex[this->m_Direction] = outputLargeIndex[this->m_Direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + os << indent << "Direction: " << m_Direction << std::endl; + os << indent << "TransformDirection: " << m_TransformDirection << std::endl; +} + + +} // end namespace itk + +#endif // itkFFT1DComplexToComplexImageFilter_hxx diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h new file mode 100644 index 0000000000..9ff85ad00c --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h @@ -0,0 +1,123 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DRealToComplexConjugateImageFilter_h +#define itkFFT1DRealToComplexConjugateImageFilter_h + +#include + +#include "itkImageToImageFilter.h" +#include "itkImageRegionSplitterDirection.h" + +namespace itk +{ +/** \class FFT1DRealToComplexConjugateImageFilter + * \brief Perform the Fast Fourier Transform, in the forward direction, with + * real inputs, but only along one dimension. + * + * \ingroup FourierTransform + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=Image< std::complex< typename TInputImage::PixelType >, TInputImage::ImageDimension > > +class FFT1DRealToComplexConjugateImageFilter: + public ImageToImageFilter< TInputImage, TOutputImage > +{ +public: + + /** Standard class typedefs. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + typedef FFT1DRealToComplexConjugateImageFilter Self; + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + itkStaticConstMacro( ImageDimension, unsigned int, InputImageType::ImageDimension ); + + itkTypeMacro( FFT1DRealToComplexConjugateImageFilter, ImageToImageFilter ); + + /** Customized object creation methods that support configuration-based + * selection of FFT implementation. + * + * Default implementation is VnlFFT1D. + */ + static Pointer New(); + + /** Get the direction in which the filter is to be applied. */ + itkGetMacro(Direction, unsigned int); + + /** Set the direction in which the filter is to be applied. */ + itkSetClampMacro(Direction, unsigned int, 0, ImageDimension - 1); + +protected: + FFT1DRealToComplexConjugateImageFilter(); + virtual ~FFT1DRealToComplexConjugateImageFilter() {} + + void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + virtual void BeforeThreadedGenerateData() ITK_OVERRIDE; + + /** Override to return a splitter that does not split along the direction we + * are performing the transform. */ + virtual const ImageRegionSplitterBase* GetImageRegionSplitter() const ITK_OVERRIDE; + +private: + FFT1DRealToComplexConjugateImageFilter( const Self& ); + void operator=( const Self& ); + + ImageRegionSplitterDirection::Pointer m_ImageRegionSplitter; + + /** Direction in which the filter is to be applied + * this should be in the range [0,ImageDimension-1]. */ + unsigned int m_Direction; + +}; +} + +#ifndef ITK_MANUAL_INSTANTIATION +#ifndef itkVnlFFT1DRealToComplexConjugateImageFilter_h +#ifndef itkVnlFFT1DRealToComplexConjugateImageFilter_hxx +#ifndef itkFFTW1DRealToComplexConjugateImageFilter_h +#ifndef itkFFTW1DRealToComplexConjugateImageFilter_hxx +#include "itkFFT1DRealToComplexConjugateImageFilter.hxx" +#endif +#endif +#endif +#endif +#endif + +#endif // itkFFT1DRealToComplexConjugateImageFilter_h diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx new file mode 100644 index 0000000000..16c10f5477 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.hxx @@ -0,0 +1,207 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkFFT1DRealToComplexConjugateImageFilter_hxx +#define itkFFT1DRealToComplexConjugateImageFilter_hxx + +#include "itkFFT1DRealToComplexConjugateImageFilter.h" + +#include "itkVnlFFT1DRealToComplexConjugateImageFilter.h" + +#if defined(ITK_USE_FFTWD) || defined(ITK_USE_FFTWF) +#include "itkFFTW1DRealToComplexConjugateImageFilter.h" +#endif + +#include "itkMetaDataObject.h" + +namespace itk +{ + +template < typename TInputImage, typename TOutputImage > +typename FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage >::Pointer +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::New() +{ + Pointer smartPtr = ::itk::ObjectFactory< Self >::Create(); + +#ifdef ITK_USE_FFTWD + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( double ) ) + { + smartPtr = dynamic_cast< Self* >( + FFTW1DRealToComplexConjugateImageFilter< double, VDimension > + ::New().GetPointer() ); + } + } +#endif +#ifdef ITK_USE_FFTWF + if( smartPtr.IsNull() ) + { + if( typeid( TPixel ) == typeid( float ) ) + { + smartPtr = dynamic_cast( + FFTW1DRealToComplexConjugateImageFilter< float, VDimension > + ::New().GetPointer() ); + } + } +#endif + + if( smartPtr.IsNull() ) + { + smartPtr = VnlFFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > + ::New().GetPointer(); + } + + return smartPtr; +} + + +template< typename TInputImage, typename TOutputImage > +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::FFT1DRealToComplexConjugateImageFilter(): + m_Direction( 0 ) +{ + this->m_ImageRegionSplitter = ImageRegionSplitterDirection::New(); +} + + +template< typename TInputImage, typename TOutputImage > +const ImageRegionSplitterBase* +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::GetImageRegionSplitter() const +{ + return this->m_ImageRegionSplitter.GetPointer(); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::BeforeThreadedGenerateData() +{ + this->m_ImageRegionSplitter->SetDirection( this->GetDirection() ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + typename InputImageType::Pointer inputPtr = + const_cast (this->GetInput()); + typename OutputImageType::Pointer outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->m_Direction; + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize( inputRequestedRegionSize ); + inputRequestedRegion.SetIndex( inputRequestedRegionStartIndex ); + + inputPtr->SetRequestedRegion( inputRequestedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DRealToComplexConjugateImageFilter < TInputImage, TOutputImage > +::EnlargeOutputRequestedRegion(DataObject *output) +{ + OutputImageType* outputPtr = dynamic_cast< OutputImageType * >( output ); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + enlargedSize[this->m_Direction] = outputLargeSize[this->m_Direction]; + enlargedIndex[this->m_Direction] = outputLargeIndex[this->m_Direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize( enlargedSize ); + enlargedRegion.SetIndex( enlargedIndex ); + outputPtr->SetRequestedRegion( enlargedRegion ); +} + + +template< typename TInputImage, typename TOutputImage > +void +FFT1DRealToComplexConjugateImageFilter < TInputImage, TOutputImage > +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os, indent ); + + os << indent << "Direction: " << m_Direction << std::endl; +} + +} // end namespace itk + +#endif // itkFFT1DRealToComplexConjugateImageFilter_hxx diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkRegionFromReferenceImageFilter.h b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkRegionFromReferenceImageFilter.h new file mode 100644 index 0000000000..5a15e24723 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkRegionFromReferenceImageFilter.h @@ -0,0 +1,143 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkRegionFromReferenceImageFilter_h +#define itkRegionFromReferenceImageFilter_h + +#include "itkExtractImageFilter.h" + +namespace itk +{ + +/** \class RegionFromReferenceImageFilter + * \brief Decrease the image size by cropping the image by an itk::Size at + * both the upper and lower bounds of the largest possible region. + * + * RegionFromReferenceImageFilter changes the image boundary of an image by removing + * pixels outside the target region. The target region is not specified in + * advance, but calculated in BeforeThreadedGenerateData(). + * + * This filter uses ExtractImageFilter to perform the cropping. + * + * \ingroup GeometricTransforms + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=TInputImage > +class RegionFromReferenceImageFilter: + public ExtractImageFilter +{ +public: + /** Standard class typedefs. */ + typedef RegionFromReferenceImageFilter Self; + typedef ExtractImageFilter Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(RegionFromReferenceImageFilter, ExtractImageFilter); + + /** Typedef to describe the output and input image region types. */ + typedef typename Superclass::OutputImageRegionType OutputImageRegionType; + typedef typename Superclass::InputImageRegionType InputImageRegionType; + + /** Typedef to describe the type of pixel. */ + typedef typename Superclass::OutputImagePixelType OutputImagePixelType; + typedef typename Superclass::InputImagePixelType InputImagePixelType; + + /** Typedef to describe the output and input image index and size types. */ + typedef typename Superclass::OutputImageIndexType OutputImageIndexType; + typedef typename Superclass::InputImageIndexType InputImageIndexType; + typedef typename Superclass::OutputImageSizeType OutputImageSizeType; + typedef typename Superclass::InputImageSizeType InputImageSizeType; + typedef InputImageSizeType SizeType; + + /** ImageDimension constants */ + itkStaticConstMacro(InputImageDimension, unsigned int, + Superclass::InputImageDimension); + itkStaticConstMacro(OutputImageDimension, unsigned int, + Superclass::OutputImageDimension); + itkStaticConstMacro(ImageDimension, unsigned int, + Superclass::OutputImageDimension); + + typedef ImageBase< itkGetStaticConstMacro( ImageDimension ) > ReferenceImageType; + + /** Copy the output information from another Image. */ + void SetReferenceImage ( const ReferenceImageType *image ); + + const ReferenceImageType * GetReferenceImage() const; + + /** Set the input image */ + void SetInput1(const TInputImage *input) + { + this->SetInput( input ); + } + + /** Set the reference image */ + void SetInput2(const ReferenceImageType *input) + { + this->SetReferenceImage( input ); + } + + +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(InputConvertibleToOutputCheck, + (Concept::Convertible)); + itkConceptMacro(SameDimensionCheck, + (Concept::SameDimension)); + /** End concept checking */ +#endif + +protected: + RegionFromReferenceImageFilter() + { + this->SetNumberOfRequiredInputs(2); + } + ~RegionFromReferenceImageFilter() {} + + virtual void GenerateOutputInformation() ITK_OVERRIDE; + +private: + RegionFromReferenceImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkRegionFromReferenceImageFilter.hxx" +#endif + +#endif diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx new file mode 100644 index 0000000000..463ef984eb --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkRegionFromReferenceImageFilter.hxx @@ -0,0 +1,87 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkRegionFromReferenceImageFilter_hxx +#define itkRegionFromReferenceImageFilter_hxx + +#include "itkRegionFromReferenceImageFilter.h" + +namespace itk +{ + +template +void +RegionFromReferenceImageFilter +::GenerateOutputInformation() +{ + if( !this->GetInput() || !this->GetReferenceImage() ) + { + return; + } + + // Superclass::Superclass::GenerateOutputInformation(); + this->SetExtractionRegion( this->GetReferenceImage()->GetLargestPossibleRegion() ); + Superclass::GenerateOutputInformation(); +} + + +template +void +RegionFromReferenceImageFilter +::SetReferenceImage ( const ReferenceImageType *image ) +{ + itkDebugMacro("setting input ReferenceImage to " << image); + if( image != static_cast(this->GetInput( 1 )) ) + { + this->ProcessObject::SetNthInput(1, const_cast< ReferenceImageType *>( image ) ); + this->Modified(); + } +} + + +template +const typename RegionFromReferenceImageFilter::ReferenceImageType * +RegionFromReferenceImageFilter +::GetReferenceImage() const +{ + Self * surrogate = const_cast< Self * >( this ); + + const DataObject * input = surrogate->ProcessObject::GetInput(1); + + const ReferenceImageType * referenceImage = static_cast( input ); + + return referenceImage; +} + +} // end namespace itk + +#endif diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h new file mode 100644 index 0000000000..91b2db0240 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.h @@ -0,0 +1,87 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DComplexConjugateToRealImageFilter_h +#define itkVnlFFT1DComplexConjugateToRealImageFilter_h + +#include "itkFFT1DComplexConjugateToRealImageFilter.h" +#include + +namespace itk +{ + +/** \class VnlFFT1DComplexConjugateToRealImageFilter + * + * \brief Perform the FFT along one dimension of an image using Vnl as a + * backend. + * + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=Image< typename NumericTraits< typename TInputImage::PixelType >::ValueType, TInputImage::ImageDimension > > +class VnlFFT1DComplexConjugateToRealImageFilter: + public FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef VnlFFT1DComplexConjugateToRealImageFilter Self; + typedef FFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( VnlFFT1DComplexConjugateToRealImageFilter, FFT1DComplexConjugateToRealImageFilter ); + +protected: + virtual void ThreadedGenerateData( const OutputImageRegionType&, ThreadIdType threadID ); // generates output from input + + VnlFFT1DComplexConjugateToRealImageFilter() { } + virtual ~VnlFFT1DComplexConjugateToRealImageFilter() { } + +private: + VnlFFT1DComplexConjugateToRealImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkVnlFFT1DComplexConjugateToRealImageFilter.hxx" +#endif + +#endif diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx new file mode 100644 index 0000000000..6a628451d3 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexConjugateToRealImageFilter.hxx @@ -0,0 +1,114 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DComplexConjugateToRealImageFilter_hxx +#define itkVnlFFT1DComplexConjugateToRealImageFilter_hxx + +#include "itkVnlFFT1DComplexConjugateToRealImageFilter.h" + +#include "itkFFT1DComplexConjugateToRealImageFilter.hxx" +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" +#include "itkIndent.h" +#include "itkMetaDataObject.h" +#include "itkExceptionObject.h" +#include "vnl/algo/vnl_fft_base.h" +#include "vnl/algo/vnl_fft_1d.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +void +VnlFFT1DComplexConjugateToRealImageFilter< TInputImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType& outputRegion, ThreadIdType itkNotUsed( threadID ) ) +{ + // get pointers to the input and output + const typename Superclass::InputImageType * inputPtr = this->GetInput(); + typename Superclass::OutputImageType * outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + const typename Superclass::InputImageType::SizeType & inputSize = inputPtr->GetRequestedRegion().GetSize(); + + unsigned int vec_size = inputSize[this->m_Direction]; + + typedef itk::ImageLinearConstIteratorWithIndex< InputImageType > InputIteratorType; + typedef itk::ImageLinearIteratorWithIndex< OutputImageType > OutputIteratorType; + InputIteratorType inputIt( inputPtr, outputRegion ); + OutputIteratorType outputIt( outputPtr, outputRegion ); + + inputIt.SetDirection(this->m_Direction); + outputIt.SetDirection(this->m_Direction); + + typedef typename TOutputImage::PixelType OutputPixelType; + vnl_vector< vcl_complex< OutputPixelType > > inputBuffer( vec_size ); + typename vnl_vector< vcl_complex< OutputPixelType > >::iterator inputBufferIt = inputBuffer.begin(); + // fft is done in-place + typename vnl_vector< vcl_complex< OutputPixelType > >::iterator outputBufferIt = inputBuffer.begin(); + vnl_fft_1d< OutputPixelType > v1d(vec_size); + + // for every fft line + for( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); + outputIt.NextLine(), inputIt.NextLine() ) + { + // copy the input line into our buffer + inputIt.GoToBeginOfLine(); + inputBufferIt = inputBuffer.begin(); + while( !inputIt.IsAtEndOfLine() ) + { + *inputBufferIt = inputIt.Get(); + ++inputIt; + ++inputBufferIt; + } + + // do the transform + v1d.fwd_transform(inputBuffer); + + // copy the output from the buffer into our line + outputBufferIt = inputBuffer.begin(); + outputIt.GoToBeginOfLine(); + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( (*outputBufferIt).real() / vec_size ); + ++outputIt; + ++outputBufferIt; + } + } +} + +} // end namespace itk + +#endif diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h new file mode 100644 index 0000000000..f2a80377ca --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.h @@ -0,0 +1,89 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DComplexToComplexImageFilter_h +#define itkVnlFFT1DComplexToComplexImageFilter_h + +#include "itkFFT1DComplexToComplexImageFilter.h" +#include + +namespace itk +{ + +/** \class VnlFFT1DComplexToComplexImageFilter + * + * \brief Perform the FFT along one dimension of an image using Vnl as a + * backend. + * + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage > +class VnlFFT1DComplexToComplexImageFilter: + public FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef VnlFFT1DComplexToComplexImageFilter Self; + typedef FFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + typedef typename Superclass::TransformDirectionType TransformDirectionType; + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( VnlFFT1DComplexToComplexImageFilter, FFT1DComplexToComplexImageFilter ); + +protected: + VnlFFT1DComplexToComplexImageFilter() {} + virtual ~VnlFFT1DComplexToComplexImageFilter() {} + + virtual void ThreadedGenerateData( const OutputImageRegionType&, ThreadIdType threadID ) ITK_OVERRIDE; + +private: + VnlFFT1DComplexToComplexImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkVnlFFT1DComplexToComplexImageFilter.hxx" +#endif + +#endif diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx new file mode 100644 index 0000000000..31639f9780 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DComplexToComplexImageFilter.hxx @@ -0,0 +1,131 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DComplexToComplexImageFilter_hxx +#define itkVnlFFT1DComplexToComplexImageFilter_hxx + +#include "itkVnlFFT1DComplexToComplexImageFilter.h" + +#include "itkFFT1DComplexToComplexImageFilter.hxx" +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" +#include "itkIndent.h" +#include "itkMetaDataObject.h" +#include "itkExceptionObject.h" +#include "vnl/algo/vnl_fft_base.h" +#include "vnl/algo/vnl_fft_1d.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +void +VnlFFT1DComplexToComplexImageFilter< TInputImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType& outputRegion, ThreadIdType itkNotUsed( threadID ) ) +{ + // get pointers to the input and output + const typename Superclass::InputImageType * inputPtr = this->GetInput(); + typename Superclass::OutputImageType * outputPtr = this->GetOutput(); + + if ( !inputPtr || !outputPtr ) + { + return; + } + + const typename Superclass::InputImageType::SizeType & inputSize = inputPtr->GetRequestedRegion().GetSize(); + + const unsigned int direction = this->GetDirection(); + const unsigned int vectorSize = inputSize[direction]; + + typedef itk::ImageLinearConstIteratorWithIndex< InputImageType > InputIteratorType; + typedef itk::ImageLinearIteratorWithIndex< OutputImageType > OutputIteratorType; + InputIteratorType inputIt( inputPtr, outputRegion ); + OutputIteratorType outputIt( outputPtr, outputRegion ); + + inputIt.SetDirection( direction ); + outputIt.SetDirection( direction ); + + typedef typename TInputImage::PixelType PixelType; + typedef vnl_vector< PixelType > VNLVectorType; + VNLVectorType inputBuffer( vectorSize ); + typename VNLVectorType::iterator inputBufferIt = inputBuffer.begin(); + // fft is done in-place + typename VNLVectorType::iterator outputBufferIt = inputBuffer.begin(); + vnl_fft_1d< typename NumericTraits< PixelType >::ValueType > v1d(vectorSize); + + // for every fft line + for( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); + outputIt.NextLine(), inputIt.NextLine() ) + { + // copy the input line into our buffer + inputIt.GoToBeginOfLine(); + inputBufferIt = inputBuffer.begin(); + while( !inputIt.IsAtEndOfLine() ) + { + *inputBufferIt = inputIt.Get(); + ++inputIt; + ++inputBufferIt; + } + + // do the transform + if( this->m_TransformDirection == Superclass::DIRECT ) + { + v1d.bwd_transform(inputBuffer); + // copy the output from the buffer into our line + outputBufferIt = inputBuffer.begin(); + outputIt.GoToBeginOfLine(); + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( *outputBufferIt ); + ++outputIt; + ++outputBufferIt; + } + } + else // m_TransformDirection == INVERSE + { + v1d.fwd_transform(inputBuffer); + // copy the output from the buffer into our line + outputBufferIt = inputBuffer.begin(); + outputIt.GoToBeginOfLine(); + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( (*outputBufferIt) / static_cast< PixelType >( vectorSize )); + ++outputIt; + ++outputBufferIt; + } + } + } +} + +} // end namespace itk + +#endif diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h new file mode 100644 index 0000000000..e0e99f70f8 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.h @@ -0,0 +1,87 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DRealToComplexConjugateImageFilter_h +#define itkVnlFFT1DRealToComplexConjugateImageFilter_h + +#include "itkFFT1DRealToComplexConjugateImageFilter.h" +#include + +namespace itk +{ + +/** \class VnlFFT1DRealToComplexConjugateImageFilter + * + * \brief Perform the FFT along one dimension of an image using Vnl as a + * backend. + * + * \ingroup Ultrasound + */ +template< typename TInputImage, typename TOutputImage=Image< std::complex< typename TInputImage::PixelType >, TInputImage::ImageDimension > > +class VnlFFT1DRealToComplexConjugateImageFilter : + public FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +{ +public: + /** Standard class typedefs. */ + typedef VnlFFT1DRealToComplexConjugateImageFilter Self; + typedef FFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( VnlFFT1DRealToComplexConjugateImageFilter, FFT1DRealToComplexConjugateImageFilter ); + +protected: + virtual void ThreadedGenerateData( const OutputImageRegionType&, ThreadIdType threadID ) ITK_OVERRIDE; + + VnlFFT1DRealToComplexConjugateImageFilter() { } + ~VnlFFT1DRealToComplexConjugateImageFilter() { } + +private: + VnlFFT1DRealToComplexConjugateImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkVnlFFT1DRealToComplexConjugateImageFilter.hxx" +#endif + +#endif diff --git a/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx new file mode 100644 index 0000000000..57d3532734 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/ITKUltrasound/itkVnlFFT1DRealToComplexConjugateImageFilter.hxx @@ -0,0 +1,119 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#ifndef itkVnlFFT1DRealToComplexConjugateImageFilter_hxx +#define itkVnlFFT1DRealToComplexConjugateImageFilter_hxx + +#include "itkVnlFFT1DRealToComplexConjugateImageFilter.h" + +#include "itkFFT1DRealToComplexConjugateImageFilter.hxx" +#include "itkImageLinearConstIteratorWithIndex.h" +#include "itkImageLinearIteratorWithIndex.h" +#include "itkIndent.h" +#include "itkMetaDataObject.h" +#include "itkExceptionObject.h" +#include "itkVnlFFTCommon.h" +#include "vnl/algo/vnl_fft_base.h" +#include "vnl/algo/vnl_fft_1d.h" + +namespace itk +{ + +template< typename TInputImage, typename TOutputImage > +void +VnlFFT1DRealToComplexConjugateImageFilter< TInputImage, TOutputImage > +::ThreadedGenerateData( const OutputImageRegionType& outputRegion, ThreadIdType itkNotUsed( threadID ) ) +{ + // get pointers to the input and output + const typename Superclass::InputImageType * inputPtr = this->GetInput(); + typename Superclass::OutputImageType * outputPtr = this->GetOutput(); + + const typename Superclass::InputImageType::SizeType & inputSize = inputPtr->GetRequestedRegion().GetSize(); + + const unsigned int direction = this->GetDirection(); + unsigned int vectorSize = inputSize[direction]; + if( ! VnlFFTCommon::IsDimensionSizeLegal(vectorSize) ) + { + itkExceptionMacro("Illegal Array DIM for FFT"); + } + + + typedef ImageLinearConstIteratorWithIndex< InputImageType > InputIteratorType; + typedef ImageLinearIteratorWithIndex< OutputImageType > OutputIteratorType; + InputIteratorType inputIt( inputPtr, outputRegion ); + OutputIteratorType outputIt( outputPtr, outputRegion ); + + inputIt.SetDirection( direction ); + outputIt.SetDirection( direction ); + + typedef typename TInputImage::PixelType PixelType; + typedef vcl_complex< PixelType > ComplexType; + typedef vnl_vector< ComplexType > ComplexVectorType; + ComplexVectorType inputBuffer( vectorSize ); + typename ComplexVectorType::iterator inputBufferIt = inputBuffer.begin(); + // fft is done in-place + typename ComplexVectorType::iterator outputBufferIt = inputBuffer.begin(); + vnl_fft_1d< PixelType > v1d( vectorSize ); + + // for every fft line + for( inputIt.GoToBegin(), outputIt.GoToBegin(); + !inputIt.IsAtEnd(); + outputIt.NextLine(), inputIt.NextLine() ) + { + // copy the input line into our buffer + inputIt.GoToBeginOfLine(); + inputBufferIt = inputBuffer.begin(); + while( !inputIt.IsAtEndOfLine() ) + { + *inputBufferIt = inputIt.Value(); + ++inputIt; + ++inputBufferIt; + } + + // do the transform + v1d.bwd_transform( inputBuffer ); + + // copy the output from the buffer into our line + outputBufferIt = inputBuffer.begin(); + outputIt.GoToBeginOfLine(); + while( !outputIt.IsAtEndOfLine() ) + { + outputIt.Set( *outputBufferIt ); + ++outputIt; + ++outputBufferIt; + } + } +} + +} // end namespace itk + +#endif diff --git a/Modules/US/USHardwareDiPhAS/files.cmake b/Modules/US/USHardwareDiPhAS/files.cmake new file mode 100644 index 0000000000..cef4d07acc --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/files.cmake @@ -0,0 +1,10 @@ +SET(CPP_FILES +mitkUSDiPhASActivator.cpp +mitkUSDiPhASDevice.cpp +mitkUSDiPhASImageSource.cpp +mitkUSDiPhASProbe.cpp +mitkUSDiPhASProbesControls.cpp +mitkUSDiPhASCustomControls.cpp +mitkUSDiPhASBModeImageFilter.hxx +mitkUSDiPhASBModeImageFilter.h +) diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASActivator.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASActivator.cpp new file mode 100644 index 0000000000..db7d7549ed --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASActivator.cpp @@ -0,0 +1,40 @@ +/*=================================================================== + +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 "mitkUSDiPhASActivator.h" + +mitk::USDiPhASActivator::USDiPhASActivator() +{ + MITK_INFO << "USDiPhASActivator created"; +} + +mitk::USDiPhASActivator::~USDiPhASActivator() +{ +} + +void mitk::USDiPhASActivator::Load(us::ModuleContext* context) +{ + // create a new device + m_Device = mitk::USDiPhASDevice::New("DiPhAS", "Ultrasound System"); + m_Device->Initialize(); +} + +void mitk::USDiPhASActivator::Unload(us::ModuleContext* context) +{ + // set smart pointer to null (device will be unregistered from + // micro service in it's destrcutor) + m_Device = 0; +} \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASActivator.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASActivator.h new file mode 100644 index 0000000000..f8f4fc617a --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASActivator.h @@ -0,0 +1,53 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef __mitkUSDiPhASActivator_h +#define __mitkUSDiPhASActivator_h + +#include "mitkUSDiPhASDevice.h" + +// Microservices +#include +#include + +namespace mitk +{ + class USDiPhASActivator : public us::ModuleActivator { + public: + + USDiPhASActivator(); + virtual ~USDiPhASActivator(); + + /** + * \brief DiPhAS device is created and initialized on module load. + * Service registration is done during the initialization process. + */ + void Load(us::ModuleContext* context); + + /** + * \brief Device pointer is removed on module unload. + * Service deregistration is done in the device destructor. + */ + void Unload(us::ModuleContext* context); + + protected: + USDiPhASDevice::Pointer m_Device; + }; +} // namespace mitk + +US_EXPORT_MODULE_ACTIVATOR(mitk::USDiPhASActivator) + +#endif // __mitkUSDiPhASActivator_h \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASBModeImageFilter.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASBModeImageFilter.h new file mode 100644 index 0000000000..d71dc6f838 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASBModeImageFilter.h @@ -0,0 +1,147 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= +* +* Copyright Insight Software Consortium +* +* 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 +* +* http://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. +* +*=========================================================================*/ +#ifndef itkPhotoacousticBModeImageFilter_h +#define itkPhotoacousticBModeImageFilter_h + +#include "itkComplexToModulusImageFilter.h" +#include "itkConstantPadImageFilter.h" +#include "itkImageToImageFilter.h" +#include "itkImage.h" + +#include "ITKUltrasound/itkRegionFromReferenceImageFilter.h" +#include "ITKUltrasound/itkAnalyticSignalImageFilter.h" + +namespace itk +{ + + /** + * \class PhotoacousticBModeImageFilter + * + * \brief Create an Photoacoustic B-Mode (Brightness-Mode) image from raw + * "RF" data. The RF's envelope is calculated from the analytic signal and + * logarithmic intensity transform is NOT applied. This is for now the only + * difference to the "normal" BModeImageFilter. + * + * Use SetDirection() to define the axis of propagation. + * + */ + template < typename TInputImage, typename TOutputImage = TInputImage, typename TComplexImage = Image< std::complex< typename TInputImage::PixelType >, TInputImage::ImageDimension > > + class PhotoacousticBModeImageFilter : + public ImageToImageFilter< TInputImage, TOutputImage > + { + public: + /** Standard class typedefs. */ + typedef PhotoacousticBModeImageFilter Self; + typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + /** The type of input image. */ + typedef TInputImage InputImageType; + + /** Dimension of the input and output images. */ + itkStaticConstMacro(ImageDimension, unsigned int, + TInputImage::ImageDimension); + + /** Typedef support for the input image scalar value type. */ + typedef typename InputImageType::PixelType InputPixelType; + + /** The type of output image. */ + typedef TOutputImage OutputImageType; + + /** Typedef support for the output image scalar value type. */ + typedef typename OutputImageType::PixelType OutputPixelType; + + /** Typedef of the image used for internal computations that has + * std::complex pixels. */ + typedef TComplexImage ComplexImageType; + + /** Other convenient typedefs */ + typedef typename InputImageType::RegionType InputRegionType; + typedef typename InputImageType::SizeType InputSizeType; + typedef typename InputImageType::IndexType InputIndexType; + + /** Run-time type information (and related methods) */ + itkTypeMacro(PhotoacousticBModeImageFilter, ImageToImageFilter); + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Set the direction in which the envelope is to be calculated. */ + virtual void SetDirection(unsigned int direction) + { + this->m_AnalyticFilter->SetDirection(direction); + this->Modified(); + } + + /** Get the direction in which the envelope is to be calculated. */ + virtual unsigned int GetDirection() const + { + return m_AnalyticFilter->GetDirection(); + } + + protected: + PhotoacousticBModeImageFilter(); + ~PhotoacousticBModeImageFilter() {} + + virtual void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + + virtual void GenerateData() ITK_OVERRIDE; + + // These behave like their analogs in FFT1DRealToComplexConjugateImageFilter. + virtual void GenerateInputRequestedRegion() ITK_OVERRIDE; + virtual void EnlargeOutputRequestedRegion(DataObject *output) ITK_OVERRIDE; + + /** Component filters. */ + typedef AnalyticSignalImageFilter< InputImageType, ComplexImageType > AnalyticType; + typedef ComplexToModulusImageFilter< typename AnalyticType::OutputImageType, OutputImageType > ComplexToModulusType; + typedef ConstantPadImageFilter< InputImageType, InputImageType > PadType; + typedef RegionFromReferenceImageFilter< OutputImageType, OutputImageType > ROIType; + + private: + PhotoacousticBModeImageFilter(const Self&); // purposely not implemented + void operator=(const Self&); // purposely not implemented + + typename AnalyticType::Pointer m_AnalyticFilter; + typename ComplexToModulusType::Pointer m_ComplexToModulusFilter; + typename PadType::Pointer m_PadFilter; + typename ROIType::Pointer m_ROIFilter; + }; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "mitkUSDiPhASBModeImageFilter.hxx" +#endif + +#endif // itkPhotoacousticBModeImageFilter_h diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASBModeImageFilter.hxx b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASBModeImageFilter.hxx new file mode 100644 index 0000000000..d7ccf510b1 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASBModeImageFilter.hxx @@ -0,0 +1,207 @@ +/*=================================================================== + +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. + +===================================================================*/ +/*========================================================================= +* +* Copyright Insight Software Consortium +* +* 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 +* +* http://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. +* +*=========================================================================*/ +#ifndef itkPhotoacousticBModeImageFilter_hxx +#define itkPhotoacousticBModeImageFilter_hxx + +#include "mitkUSDiPhASBModeImageFilter.h" + +#include "itkMetaDataDictionary.h" + +#include +#include +#include + +namespace itk +{ + + template < typename TInputImage, typename TOutputImage, typename TComplexImage > + PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > + ::PhotoacousticBModeImageFilter() + { + m_AnalyticFilter = AnalyticType::New(); + m_ComplexToModulusFilter = ComplexToModulusType::New(); + m_PadFilter = PadType::New(); + m_ROIFilter = ROIType::New(); + + m_PadFilter->SetConstant(0.); + m_ComplexToModulusFilter->SetInput(m_AnalyticFilter->GetOutput()); + m_ROIFilter->SetInput(m_ComplexToModulusFilter->GetOutput()); + } + + + template < typename TInputImage, typename TOutputImage, typename TComplexImage > + void + PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > + ::PrintSelf(std::ostream& os, Indent indent) const + { + Superclass::PrintSelf(os, indent); + } + + + template < typename TInputImage, typename TOutputImage, typename TComplexImage > + void + PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > + ::GenerateInputRequestedRegion() + { + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the inputs + InputImageType * inputPtr = const_cast (this->GetInput()); + OutputImageType * outputPtr = this->GetOutput(); + + // we need to compute the input requested region (size and start index) + typedef const typename OutputImageType::SizeType& OutputSizeType; + OutputSizeType outputRequestedRegionSize = + outputPtr->GetRequestedRegion().GetSize(); + typedef const typename OutputImageType::IndexType& OutputIndexType; + OutputIndexType outputRequestedRegionStartIndex = + outputPtr->GetRequestedRegion().GetIndex(); + + //// the regions other than the fft direction are fine + typename InputImageType::SizeType inputRequestedRegionSize = outputRequestedRegionSize; + typename InputImageType::IndexType inputRequestedRegionStartIndex = outputRequestedRegionStartIndex; + + // we but need all of the input in the fft direction + const unsigned int direction = this->GetDirection(); + const typename InputImageType::SizeType& inputLargeSize = + inputPtr->GetLargestPossibleRegion().GetSize(); + inputRequestedRegionSize[direction] = inputLargeSize[direction]; + const typename InputImageType::IndexType& inputLargeIndex = + inputPtr->GetLargestPossibleRegion().GetIndex(); + inputRequestedRegionStartIndex[direction] = inputLargeIndex[direction]; + + typename InputImageType::RegionType inputRequestedRegion; + inputRequestedRegion.SetSize(inputRequestedRegionSize); + inputRequestedRegion.SetIndex(inputRequestedRegionStartIndex); + + inputPtr->SetRequestedRegion(inputRequestedRegion); + } + + + template < typename TInputImage, typename TOutputImage, typename TComplexImage > + void + PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > + ::EnlargeOutputRequestedRegion(DataObject *output) + { + OutputImageType* outputPtr = dynamic_cast< OutputImageType* >(output); + + // we need to enlarge the region in the fft direction to the + // largest possible in that direction + typedef const typename OutputImageType::SizeType& ConstOutputSizeType; + ConstOutputSizeType requestedSize = + outputPtr->GetRequestedRegion().GetSize(); + ConstOutputSizeType outputLargeSize = + outputPtr->GetLargestPossibleRegion().GetSize(); + typedef const typename OutputImageType::IndexType& ConstOutputIndexType; + ConstOutputIndexType requestedIndex = + outputPtr->GetRequestedRegion().GetIndex(); + ConstOutputIndexType outputLargeIndex = + outputPtr->GetLargestPossibleRegion().GetIndex(); + + typename OutputImageType::SizeType enlargedSize = requestedSize; + typename OutputImageType::IndexType enlargedIndex = requestedIndex; + const unsigned int direction = this->GetDirection(); + enlargedSize[direction] = outputLargeSize[direction]; + enlargedIndex[direction] = outputLargeIndex[direction]; + + typename OutputImageType::RegionType enlargedRegion; + enlargedRegion.SetSize(enlargedSize); + enlargedRegion.SetIndex(enlargedIndex); + outputPtr->SetRequestedRegion(enlargedRegion); + } + + + template < typename TInputImage, typename TOutputImage, typename TComplexImage > + void + PhotoacousticBModeImageFilter< TInputImage, TOutputImage, TComplexImage > + ::GenerateData() + { + this->AllocateOutputs(); + + const InputImageType * inputPtr = this->GetInput(); + OutputImageType * outputPtr = this->GetOutput(); + + const unsigned int direction = m_AnalyticFilter->GetDirection(); + typename InputImageType::SizeType size = inputPtr->GetLargestPossibleRegion().GetSize(); + + // Zero padding. FFT direction should be factorable by 2 for all FFT + // implementations to work. + unsigned int n = size[direction]; + while (n % 2 == 0) + { + n /= 2; + } + bool doPadding; + if (n == 1) + { + doPadding = false; + } + else + { + doPadding = true; + } + if (doPadding) + { + n = size[direction]; + unsigned int newSizeDirection = 1; + while (newSizeDirection < n) + { + newSizeDirection *= 2; + } + typename InputImageType::SizeType padSize; + padSize.Fill(0); + padSize[direction] = newSizeDirection - size[direction]; + size[direction] = newSizeDirection; + m_PadFilter->SetPadUpperBound(padSize); + m_PadFilter->SetInput(inputPtr); + m_AnalyticFilter->SetInput(m_PadFilter->GetOutput()); + m_ROIFilter->SetReferenceImage(inputPtr); + m_ROIFilter->SetInput(m_ComplexToModulusFilter->GetOutput()); + m_ROIFilter->GraftOutput(outputPtr); + m_ROIFilter->Update(); + this->GraftOutput(m_ROIFilter->GetOutput()); + } + else // padding is not required + { + m_AnalyticFilter->SetInput(inputPtr); + m_ComplexToModulusFilter->GraftOutput(outputPtr); + m_ComplexToModulusFilter->Update(); + this->GraftOutput(m_ComplexToModulusFilter->GetOutput()); + } + + } + +} // end namespace itk + +#endif \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp new file mode 100644 index 0000000000..c33248296d --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp @@ -0,0 +1,213 @@ +/*=================================================================== + +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 "mitkUSDiPhASCustomControls.h" +#include + +mitk::USDiPhASCustomControls::USDiPhASCustomControls(USDiPhASDevice* device) + : mitk::USDiPhASDeviceCustomControls(device), m_IsActive(false), m_device(device), currentBeamformingAlgorithm((int)Beamforming::PlaneWaveCompound) +{ +} + +mitk::USDiPhASCustomControls::~USDiPhASCustomControls() +{ +} + +void mitk::USDiPhASCustomControls::SetIsActive(bool isActive) +{ + m_IsActive = isActive; +} + +bool mitk::USDiPhASCustomControls::GetIsActive() +{ + return m_IsActive; +} + +void mitk::USDiPhASCustomControls::passGUIOut(std::function callback) +{ + mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); + callback("initializing"); + imageSource->SetGUIOutput(callback); +} + +// OnSet methods + +void mitk::USDiPhASCustomControls::OnSetUseBModeFilter(bool isSet) +{ + mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); + imageSource->ModifyUseBModeFilter(isSet); +} + +void mitk::USDiPhASCustomControls::OnSetRecord(bool record) +{ + mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); + imageSource->SetRecordingStatus(record); +} + +void mitk::USDiPhASCustomControls::OnSetVerticalSpacing(float mm) +{ + mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); + imageSource->SetVerticalSpacing(mm); +} + +void mitk::USDiPhASCustomControls::OnSetScatteringCoefficient(float coeff) +{ + mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); + imageSource->ModifyScatteringCoefficient(coeff); +} +void mitk::USDiPhASCustomControls::OnSetCompensateScattering(bool compensate) +{ + mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); + imageSource->ModifyCompensateForScattering(compensate); +} + +//Transmit +void mitk::USDiPhASCustomControls::OnSetTransmitPhaseLength(double us) +{ + m_device->GetScanMode().transmitPhaseLengthSeconds = us/1000000; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetExcitationFrequency(double MHz) +{ + m_device->SetBursts(round(((120 / MHz) - 2) / 2)); + m_device->UpdateScanmode(); + // b = (c/f - 2) * 1/2, where c is the internal clock, f the wanted frequency, b the burst count +} + +void mitk::USDiPhASCustomControls::OnSetTransmitEvents(int events) +{ + m_device->GetScanMode().transmitEventsCount = events; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetVoltage(int voltage) +{ + m_device->GetScanMode().voltageV = voltage; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetMode(bool interleaved) +{ + m_device->SetInterleaved(interleaved); + m_device->UpdateScanmode(); +} + +//Receive +void mitk::USDiPhASCustomControls::OnSetScanDepth(double mm) +{ + auto& scanMode = m_device->GetScanMode(); + float time = 2 * (0.001 * mm) / scanMode.averageSpeedOfSound; + m_device->GetScanMode().receivePhaseLengthSeconds = time; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetAveragingCount(int count) +{ + m_device->GetScanMode().averagingCount = count; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetTGCMin(int min) +{ + auto& scanMode = m_device->GetScanMode(); + char range = scanMode.tgcdB[7] - min; + for (int tgc = 0; tgc < 7; ++tgc) + scanMode.tgcdB[tgc] = round(tgc*range / 7 + min); + + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetTGCMax(int max) +{ + auto& scanMode = m_device->GetScanMode(); + char range = max - scanMode.tgcdB[0]; + for (int tgc = 1; tgc < 8; ++tgc) + scanMode.tgcdB[tgc] = round(tgc*range / 7 + scanMode.tgcdB[0]); + + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetDataType(DataType type) +{ + auto& scanMode = m_device->GetScanMode(); + auto imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); + switch (type) { + case DataType::Image_uChar : { + scanMode.transferBeamformedData = false; + scanMode.transferImageData = true; + m_device->UpdateScanmode(); + imageSource->ModifyDataType(DataType::Image_uChar); + break; + } + case DataType::Beamformed_Short : { + scanMode.transferBeamformedData = true; + scanMode.transferImageData = false; + m_device->UpdateScanmode(); + imageSource->ModifyDataType(DataType::Beamformed_Short); + break; + } + + default: + MITK_INFO << "Unknown Data Type requested"; + break; + } +} +// 0= image; 1= beamformed + +//Beamforming +void mitk::USDiPhASCustomControls::OnSetPitch(double mm) +{ + m_device->GetScanMode().reconstructedLinePitchMmOrAngleDegree = mm; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetReconstructedSamples(int samples) +{ + m_device->GetScanMode().reconstructionSamplesPerLine = samples; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetReconstructedLines(int lines) +{ + m_device->GetScanMode().reconstructionLines = lines; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetSpeedOfSound(int mps) +{ + m_device->GetScanMode().averageSpeedOfSound = mps; + m_device->UpdateScanmode(); +} + +//Bandpass +void mitk::USDiPhASCustomControls::OnSetBandpassEnabled(bool bandpass) +{ + m_device->GetScanMode().bandpassApply = bandpass; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetLowCut(double MHz) +{ + m_device->GetScanMode().bandpassFrequencyLowHz = MHz*1000*1000; + m_device->UpdateScanmode(); +} + +void mitk::USDiPhASCustomControls::OnSetHighCut(double MHz) +{ + m_device->GetScanMode().bandpassFrequencyHighHz = MHz*1000*1000; + m_device->UpdateScanmode(); +} \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.h new file mode 100644 index 0000000000..2d6d64e9a5 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.h @@ -0,0 +1,104 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef MITKUSDiPhASCustomControls_H_HEADER_INCLUDED_ +#define MITKUSDiPhASCustomControls_H_HEADER_INCLUDED_ + +#include "mitkUSDiPhASDeviceCustomControls.h" +#include "mitkUSDevice.h" +#include "mitkUSDiPhASDevice.h" +#include "Framework.IBMT.US.CWrapper.h" + +#include + +namespace mitk { +/** + * \brief Custom controls for mitk::USDiPhASDevice. + */ +class USDiPhASDevice; +class USDiPhASCustomControls : public USDiPhASDeviceCustomControls +{ +public: + mitkClassMacro(USDiPhASCustomControls, USAbstractControlInterface); + mitkNewMacro1Param(Self, mitk::USDiPhASDevice*); + + typedef USDiPhASDeviceCustomControls::DataType DataType; + + /** + * Activate or deactivate the custom controls. This is just for handling + * widget visibility in a GUI for example. + */ + virtual void SetIsActive( bool isActive ) override; + + /** + * \return if this custom controls are currently activated + */ + virtual bool GetIsActive( ) override; + + virtual void passGUIOut(std::function callback) override; + + BeamformingParametersPlaneWaveCompound parametersPW; + BeamformingParametersInterleaved_OA_US parametersOSUS; + +protected: + /** + * Class needs an mitk::USDiPhASDevice object for beeing constructed. + * This object's ScanMode will be manipulated by the custom controls methods. + */ + USDiPhASCustomControls(USDiPhASDevice* device); + virtual ~USDiPhASCustomControls( ); + + bool m_IsActive; + USImageVideoSource::Pointer m_ImageSource; + USDiPhASDevice* m_device; + int currentBeamformingAlgorithm; + + /** handlers for value changes + */ + virtual void OnSetUseBModeFilter(bool isSet) override; + virtual void OnSetRecord(bool record) override; + virtual void OnSetVerticalSpacing(float mm) override; + virtual void OnSetScatteringCoefficient(float coeff) override; + virtual void OnSetCompensateScattering(bool compensate) override; + + //Transmit + virtual void OnSetTransmitPhaseLength(double us) override; + virtual void OnSetExcitationFrequency(double MHz) override; + virtual void OnSetTransmitEvents(int events) override; + virtual void OnSetVoltage(int voltage) override; + virtual void OnSetMode(bool interleaved) override; + + //Receive + virtual void OnSetScanDepth(double mm) override; + virtual void OnSetAveragingCount(int count) override; + virtual void OnSetTGCMin(int min) override; + virtual void OnSetTGCMax(int max) override; + virtual void OnSetDataType(DataType type) override; + + //Beamforming + virtual void OnSetPitch(double mm) override; + virtual void OnSetReconstructedSamples(int samples) override; + virtual void OnSetReconstructedLines(int lines) override; + virtual void OnSetSpeedOfSound(int mps) override; + + //Bandpass + virtual void OnSetBandpassEnabled(bool bandpass) override; + virtual void OnSetLowCut(double MHz) override; + virtual void OnSetHighCut(double MHz) override; +}; +} // namespace mitk + +#endif // MITKUSDiPhASCustomControls_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.cpp new file mode 100644 index 0000000000..597dacb8d8 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.cpp @@ -0,0 +1,303 @@ +/*=================================================================== + +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 "mitkUSDiPhASDevice.h" +#include "mitkUSDiPhASCustomControls.h" + +mitk::USDiPhASDevice::USDiPhASDevice(std::string manufacturer, std::string model) + : mitk::USDevice(manufacturer, model), m_ControlsProbes(mitk::USDiPhASProbesControls::New(this)), + m_ImageSource(mitk::USDiPhASImageSource::New(this)), + m_ControlInterfaceCustom(mitk::USDiPhASCustomControls::New(this)), + m_IsRunning(false), + m_BurstHalfwaveClockCount(7), + m_Interleaved(true) +{ + SetNumberOfOutputs(1); + SetNthOutput(0, this->MakeOutput(0)); +} + +mitk::USDiPhASDevice::~USDiPhASDevice() +{ +} + +//Gets + +std::string mitk::USDiPhASDevice::GetDeviceClass() +{ + return "org.mitk.modules.us.USDiPhASDevice"; +} + +mitk::USControlInterfaceProbes::Pointer mitk::USDiPhASDevice::GetControlInterfaceProbes() +{ + return m_ControlsProbes.GetPointer(); +}; + +mitk::USAbstractControlInterface::Pointer mitk::USDiPhASDevice::GetControlInterfaceCustom() +{ + return m_ControlInterfaceCustom.GetPointer(); +} + +mitk::USImageSource::Pointer mitk::USDiPhASDevice::GetUSImageSource() +{ + return m_ImageSource.GetPointer(); +} + +ScanModeNative& mitk::USDiPhASDevice::GetScanMode() +{ + return m_ScanMode; +} + +// Setup and Cleanup + +bool mitk::USDiPhASDevice::OnInitialization() +{ + return true; +} + +//---------------------------------------------------------------------------------------------------------------------------- +/* ugly wrapper stuff - find better solution so it isn't necessary to create a global pointer to USDiPhASDevice... + * passing a lambda function would be nicer - sadly something goes wrong when passing the adress of a lambda function: + * the API produces access violations. Passing the Lambda function itself would be preferable, but that's not possible +*/ + +mitk::USDiPhASDevice* w_device; +mitk::USDiPhASImageSource* w_ISource; + +void WrapperMessageCallback(const char* message) +{ + w_device->MessageCallback(message); +} + +void WrapperImageDataCallback( + short* rfDataChannelData, int channelDatalinesPerDataset, int channelDataSamplesPerChannel, int channelDataTotalDatasets, + short* rfDataArrayBeamformed, int beamformedLines, int beamformedSamples, int beamformedTotalDatasets, + unsigned char* imageData, int imageWidth, int imageHeight, int imagePixelFormat, int imageSetsTotal, + + double timeStamp) +{ + w_ISource->ImageDataCallback( + rfDataChannelData, channelDatalinesPerDataset, channelDatalinesPerDataset, channelDataTotalDatasets, + rfDataArrayBeamformed, beamformedLines, beamformedSamples, beamformedTotalDatasets, + imageData, imageWidth, imageHeight, imagePixelFormat, imageSetsTotal, timeStamp); +} + +//---------------------------------------------------------------------------------------------------------------------------- + +bool mitk::USDiPhASDevice::OnConnection() +{ + w_device = this; + w_ISource = m_ImageSource; + // Need those pointers for the forwarders to call member functions; createBeamformer expects non-member function pointers. + createBeamformer((StringMessageCallback)&WrapperMessageCallback, (NewDataCallback)&WrapperImageDataCallback); + + InitializeScanMode(); + initBeamformer(); //start the hardware connection + + m_ImageSource->UpdateImageGeometry(); //make sure the image geometry is initialized! + // pass the new scanmode to the device: + setupScan(this->m_ScanMode); + return true; +} + +bool mitk::USDiPhASDevice::OnDisconnection() +{ + //close the beamformer so hardware is disconnected + closeBeamformer(); + return true; +} + +bool mitk::USDiPhASDevice::OnActivation() +{ + // probe controls are available now + m_ControlsProbes->SetIsActive(true); + + if (m_ControlsProbes->GetProbesCount() < 1) + { + MITK_WARN("USDevice")("USDiPhASDevice") << "No probe found."; + return false; + } + + m_ControlsProbes->SelectProbe(0); + + // toggle the beamformer of the API + if(!m_IsRunning) + m_IsRunning=toggleFreeze(); + return true; +} + +bool mitk::USDiPhASDevice::OnDeactivation() +{ + if(m_IsRunning) + m_IsRunning=toggleFreeze(); + return true; +} + +void mitk::USDiPhASDevice::OnFreeze(bool freeze) +{ + if(m_IsRunning==freeze) + m_IsRunning=toggleFreeze(); // toggleFreeze() returns true if it starts running the beamformer, otherwise false +} + +void mitk::USDiPhASDevice::UpdateScanmode() +{ + OnFreeze(true); + + UpdateTransmitEvents(); + + if (!(dynamic_cast(this->m_ControlInterfaceCustom.GetPointer())->GetSilentUpdate())) + { + setupScan(this->m_ScanMode); + m_ImageSource->UpdateImageGeometry(); + } + + OnFreeze(false); +} + +void mitk::USDiPhASDevice::UpdateTransmitEvents() +{ + int numChannels = m_ScanMode.reconstructionLines; + + // transmitEventsCount defines only the number of acoustic measurements (angles); there will be one event added to the start for OA measurement + m_ScanMode.TransmitEvents = new TransmitEventNative[m_ScanMode.transmitEventsCount]; + + for (int ev = 0; ev < m_ScanMode.transmitEventsCount; ++ev) + { + m_ScanMode.TransmitEvents[ev].transmitEventDelays = new float[numChannels]; + m_ScanMode.TransmitEvents[ev].BurstHalfwaveClockCountPerChannel = new int[numChannels]; + m_ScanMode.TransmitEvents[ev].BurstCountPerChannel = new int[numChannels]; + m_ScanMode.TransmitEvents[ev].BurstUseNegativePolarityPerChannel = new bool[numChannels]; + m_ScanMode.TransmitEvents[ev].ChannelMultiplexerSetups = nullptr; + + for (int i = 0; i < numChannels; ++i) + { + m_ScanMode.TransmitEvents[ev].BurstHalfwaveClockCountPerChannel[i] = m_BurstHalfwaveClockCount; // 120 MHz / (2 * (predefinedBurstHalfwaveClockCount + 1)) --> 7.5 MHz + m_ScanMode.TransmitEvents[ev].BurstCountPerChannel[i] = 1; // Burst with 1 cycle + m_ScanMode.TransmitEvents[ev].BurstUseNegativePolarityPerChannel[i] = true; + m_ScanMode.TransmitEvents[ev].transmitEventDelays[i] = 0; + } + } + + m_ScanMode.transmitSequenceCount = 1; + m_ScanMode.transmitSequences = new SequenceNative[m_ScanMode.transmitSequenceCount]; + m_ScanMode.transmitSequences[0].startEvent = 0; + m_ScanMode.transmitSequences[0].endEvent = m_ScanMode.transmitEventsCount; +} + +void mitk::USDiPhASDevice::InitializeScanMode() +{ + // create a scanmode to be used for measurements: + m_ScanMode.scanModeName = "InterleavedMode"; + + // configure a linear transducer + m_ScanMode.transducerName = "L5-10"; + m_ScanMode.transducerCurvedRadiusMeter = 0; + m_ScanMode.transducerElementCount = 128; + m_ScanMode.transducerFrequencyHz = 7500000; + m_ScanMode.transducerPitchMeter = 0.0003f; + m_ScanMode.transducerType = 1; + + // configure the receive paramters: + m_ScanMode.receivePhaseLengthSeconds = 65e-6f; // 5 cm imaging depth + m_ScanMode.tgcdB = new unsigned char[8]; + for (int tgc = 0; tgc < 8; ++tgc) + m_ScanMode.tgcdB[tgc] = tgc * 2 + 10; + m_ScanMode.accumulation = 1; + m_ScanMode.bandpassApply = false; + m_ScanMode.averagingCount = 1; + + // configure general processing: + m_ScanMode.transferChannelData = false; + + // configure reconstruction processing: + m_ScanMode.averageSpeedOfSound = 1540; + m_ScanMode.computeBeamforming = true; + + // setup beamforming parameters: + SetInterleaved(true); + + m_ScanMode.reconstructedLinePitchMmOrAngleDegree = 0.15f; + m_ScanMode.reconstructionLines = 256; + m_ScanMode.reconstructionSamplesPerLine = 2048; + m_ScanMode.transferBeamformedData = true; + + // configure the transmit sequence(s): + m_ScanMode.transmitEventsCount = 1; + m_ScanMode.transmitPhaseLengthSeconds = 1e-6f; + m_ScanMode.voltageV = 70; + UpdateTransmitEvents(); + + // configure bandpass: + m_ScanMode.bandpassApply = false; + m_ScanMode.bandpassFrequencyLowHz = 1e6f; + m_ScanMode.bandpassFrequencyHighHz = 20e6f; + + // configure image generation: + m_ScanMode.imageWidth = 512; + m_ScanMode.imageHeight = 512; + m_ScanMode.imageMultiplier = 1; + m_ScanMode.imageLeveling = 0; + m_ScanMode.transferImageData = true; + + // Trigger setup: + m_ScanMode.triggerSetup.enabled = true; + m_ScanMode.triggerSetup.constantPulseRepetitionRateHz = 20; + m_ScanMode.triggerSetup.triggerWidthMicroseconds = 15; + m_ScanMode.triggerSetup.delayTrigger2Microseconds = 300; +} + +// callback for the DiPhAS API + +void mitk::USDiPhASDevice::MessageCallback(const char* message) +{ + MITK_INFO << "DiPhAS API: " << message << '\n'; +} + +void mitk::USDiPhASDevice::SetBursts(int bursts) +{ + m_BurstHalfwaveClockCount = bursts; +} + +bool mitk::USDiPhASDevice::IsInterleaved() +{ + return m_Interleaved; +} + +void mitk::USDiPhASDevice::SetInterleaved(bool interleaved) +{ + m_Interleaved = interleaved; + if (interleaved) { + m_ScanMode.scanModeName = "Interleaved Beamforming Mode"; + m_CurrentBeamformingAlgorithm = Beamforming::Interleaved_OA_US; + + paramsInterleaved.SpeedOfSoundMeterPerSecond = m_ScanMode.averageSpeedOfSound; + paramsInterleaved.angleSkipFactor = 1; + paramsInterleaved.OptoacousticDelay = 0.0000003; // 300ns + paramsInterleaved.filter = Filter::None; + + m_ScanMode.beamformingAlgorithmParameters = ¶msInterleaved; + } + else { + m_ScanMode.scanModeName = "Plane Wave Beamforming Mode"; + m_CurrentBeamformingAlgorithm = Beamforming::PlaneWaveCompound; + + paramsPlaneWave.SpeedOfSoundMeterPerSecond = m_ScanMode.averageSpeedOfSound; + paramsPlaneWave.angleSkipFactor = 0; + paramsPlaneWave.usePhaseCoherence = 0; + + m_ScanMode.beamformingAlgorithmParameters = ¶msPlaneWave; + } + m_ScanMode.beamformingAlgorithm = m_CurrentBeamformingAlgorithm; +} \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.h new file mode 100644 index 0000000000..2732f4f7c8 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.h @@ -0,0 +1,173 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef MITKUSDiPhASDevice_H_HEADER_INCLUDED_ +#define MITKUSDiPhASDevice_H_HEADER_INCLUDED_ + +#include +#include "mitkUSDiPhASImageSource.h" +#include "mitkUSDevice.h" +#include "mitkUSDiPhASProbesControls.h" +#include "mitkUSDiPhASImageSource.h" +#include "mitkUSDiPhASCustomControls.h" + +#include "Framework.IBMT.US.CWrapper.h" + +#include +#include +#include +#include +#include + +#include + + +namespace mitk { + /** + * \brief Implementation of mitk::USDevice for DiPhAS API devices. + * Connects to a DiPhAS API device through its COM library interface. + * + * This class handles all API communications and creates interfaces for + * b mode, doppler and probes controls. + * Images given by the device are put into an object of + * mitk::USDiPhASImageSource. + */ + class USDiPhASImageSource; + + class USDiPhASDevice : public USDevice + { + public: + mitkClassMacro(USDiPhASDevice, mitk::USDevice); + mitkNewMacro2Param(Self, std::string, std::string); + + /** + * \brief Returns the class of the device. + */ + virtual std::string GetDeviceClass(); + + virtual USControlInterfaceProbes::Pointer GetControlInterfaceProbes(); + virtual itk::SmartPointer GetControlInterfaceCustom(); + + /** + * \brief Is called during the initialization process. + * There is nothing done on the initialization of a mik::USDiPhASDevive object. + * + * \return always true + */ + virtual bool OnInitialization(); + + /** + * \brief Is called during the connection process. + * Connect to the DiPhAS API. + * + * \return true if successfull, false if no device is connected to the pc + * \throws mitk::Exception if something goes wrong at the API calls + */ + virtual bool OnConnection(); + + /** + * \brief Is called during the disconnection process. + * Deactivate and remove all DiPhAS API controls. A disconnect from the + * DiPhAS API is not possible for which reason the hardware stays in connected + * state even after calling this method. + * + * \return always true + * \throws mitk::Exception if something goes wrong at the API calls + */ + virtual bool OnDisconnection(); + + /** + * \brief Is called during the activation process. + * After this method is finished, the device is generating images in b mode. + * Changing scanning mode is possible afterwards by using the appropriate + * control interfaces. + * + * \return always true + * \throws mitk::Exception if something goes wrong at the API calls + */ + virtual bool OnActivation(); + + /** + * \brief Is called during the deactivation process. + * After a call to this method the device is connected, but not producing images anymore. + * + * \return always true + * \throws mitk::Exception if something goes wrong at the API calls + */ + virtual bool OnDeactivation(); + + /** + * \brief Changes scan state of the device if freeze is toggeled in mitk::USDevice. + */ + virtual void OnFreeze(bool freeze); + + /** @return Returns the current image source of this device. */ + USImageSource::Pointer GetUSImageSource( ); + + /** @return Returns the currently used scanmode of this device*/ + ScanModeNative& GetScanMode(); + + /** Updates the Scanmode and feeds it to the hardware + */ + void UpdateScanmode(); + /** This method forwards messages from the API to the user*/ + void MessageCallback(const char* message); + void SetBursts(int bursts); + void SetInterleaved(bool interleaved); + bool IsInterleaved(); + + BeamformingParametersInterleaved_OA_US paramsInterleaved; + BeamformingParametersPlaneWaveCompound paramsPlaneWave; + + protected: + /** + * Constructs a mitk::USDiPhASDevice object by given manufacturer + * and model string. These strings are just for labeling the device + * in the micro service. + * + * Control interfaces and image source are available directly after + * construction. Registration at the micro service happens not before + * initialization method was called. + */ + USDiPhASDevice(std::string manufacturer, std::string model); + virtual ~USDiPhASDevice(); + + /** + * The DiPhAS API expects callback functions to pass + * both status messages and the processed images to the user. + * The message callback is here, the data itself is given directly to the image source. + */ + + /** + * This method sets up the scanmode at the begining + */ + void InitializeScanMode(); + void UpdateTransmitEvents(); + + USDiPhASProbesControls::Pointer m_ControlsProbes; + itk::SmartPointer m_ControlInterfaceCustom; + + mitk::USDiPhASImageSource::Pointer m_ImageSource; + + bool m_IsRunning; + ScanModeNative m_ScanMode; + int m_BurstHalfwaveClockCount; + Beamforming m_CurrentBeamformingAlgorithm; + bool m_Interleaved; + }; +} // namespace mitk + +#endif // MITKUSDiPhASDevice_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp new file mode 100644 index 0000000000..309a400f99 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp @@ -0,0 +1,702 @@ +/*=================================================================== + +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. + +===================================================================*/ + +// std dependencies +#include +#include + +// mitk dependencies +#include "mitkUSDiPhASDevice.h" +#include "mitkUSDiPhASImageSource.h" +#include +#include "mitkUSDiPhASBModeImageFilter.h" +#include "ITKUltrasound/itkBModeImageFilter.h" +#include "mitkImageCast.h" +#include "mitkITKImageImport.h" + +// itk dependencies +#include "itkImage.h" +#include "itkResampleImageFilter.h" +#include "itkCastImageFilter.h" +#include "itkCropImageFilter.h" +#include "itkRescaleIntensityImageFilter.h" +#include "itkIntensityWindowingImageFilter.h" +#include +#include "itkMultiplyImageFilter.h" + + +mitk::USDiPhASImageSource::USDiPhASImageSource(mitk::USDiPhASDevice* device) + : m_device(device), + m_StartTime(((float)std::clock()) / CLOCKS_PER_SEC), + m_UseGUIOutPut(false), + m_DataType(DataType::Image_uChar), + m_GUIOutput(nullptr), + m_UseBModeFilter(false), + m_CurrentlyRecording(false), + m_DataTypeModified(true), + m_DataTypeNext(DataType::Image_uChar), + m_CurrentImageTimestamp(0), + m_PyroConnected(false), + m_ImageTimestampBuffer(), + m_VerticalSpacing(0), + m_UseBModeFilterModified(false), + m_UseBModeFilterNext(false), + m_ScatteringCoefficientModified(false), + m_CompensateForScatteringModified(false), + m_VerticalSpacingModified(false), + m_ScatteringCoefficient(15), + m_CompensateForScattering(false) +{ + m_BufferSize = 100; + m_ImageTimestampBuffer.insert(m_ImageTimestampBuffer.begin(), m_BufferSize, 0); + m_LastWrittenImage = m_BufferSize - 1; + m_ImageBuffer.insert(m_ImageBuffer.begin(), m_BufferSize, nullptr); + + us::ModuleResource resourceFile; + std::string name; + m_FluenceCompOriginal.insert(m_FluenceCompOriginal.begin(), 5, Image::New()); + for (int i = 5; i <= 25; ++i) + { + name = "Fluence" + i; + name += ".nrrd"; + + name = "FranzTissue.nrrd"; + + resourceFile = us::GetModuleContext()->GetModule()->GetResource(name); + + //m_FluenceCompensationImagesOriginal.push_back(mitk::IOUtil::LoadImage(resourceFile.GetResourcePath())); + m_FluenceCompOriginal.push_back(mitk::IOUtil::LoadImage("d:\\FranzTissue.nrrd")); // TODO: make it actually load the images we want, not some test image.... + } + + m_FluenceCompResized.insert(m_FluenceCompResized.begin(), 26, Image::New()); + m_FluenceCompResizedItk.insert(m_FluenceCompResizedItk.begin(), 26, itk::Image::New()); +} + +mitk::USDiPhASImageSource::~USDiPhASImageSource() +{ + // close the pyro + MITK_INFO("Pyro Debug") << "StopDataAcquisition: " << m_Pyro->StopDataAcquisition(); + MITK_INFO("Pyro Debug") << "CloseConnection: " << m_Pyro->CloseConnection(); + m_PyroConnected = false; + m_Pyro = nullptr; +} + +void mitk::USDiPhASImageSource::GetNextRawImage( mitk::Image::Pointer& image) +{ + // we get this image pointer from the USDevice and write into it the data we got from the DiPhAS API + + // resize the fluence reference images, if needed + + // modify all settings + if (m_DataTypeModified) + { + SetDataType(m_DataTypeNext); + m_DataTypeModified = false; + } + if (m_UseBModeFilterModified) + { + SetUseBModeFilter(m_UseBModeFilterNext); + m_UseBModeFilterModified = false; + } + if (m_VerticalSpacingModified) + { + m_VerticalSpacing = m_VerticalSpacingNext; + m_VerticalSpacingModified = false; + } + if (m_ScatteringCoefficientModified) + { + m_ScatteringCoefficient = m_ScatteringCoefficientNext; + m_ScatteringCoefficientModified = false; + } + if (m_CompensateForScatteringModified) + { + m_CompensateForScattering = m_CompensateForScatteringNext; + m_CompensateForScatteringModified = false; + } + + // make sure image is nullptr + image = nullptr; + float ImageEnergyValue = 0; + + for (int i = 100; i > 90 && ImageEnergyValue <= 0; --i) + { + if (m_ImageTimestampBuffer[(m_LastWrittenImage + i) % 100] != 0) + { + ImageEnergyValue = m_Pyro->GetClosestEnergyInmJ(m_ImageTimestampBuffer[(m_LastWrittenImage + i) % 100]); + if (ImageEnergyValue > 0) { + image = &(*m_ImageBuffer[(m_LastWrittenImage + i) % 100]); + } + } + } + // if we did not get any usable Energy value, compensate using this default value + if (image == nullptr) + { + image = &(*m_ImageBuffer[m_LastWrittenImage]); + ImageEnergyValue = 40; + if (image == nullptr) + return; + } + + // do image processing before displaying it + if (image.IsNotNull()) + { + + // first, we compensate using our ImageEnergyValue + + // dooooooooit + + // now apply BmodeFilter and/or scattering compensation to the image, if the option has been selected. + if ((m_CompensateForScattering || m_UseBModeFilter) && m_DataType == DataType::Beamformed_Short) + { + if (image->GetDimension(2) == 1 && m_UseBModeFilter) + { + image = ApplyBmodeFilter(image, true, m_VerticalSpacing); + } // this is for ultrasound only mode + else + { + Image::Pointer imageCopy = Image::New(); + unsigned int dim[] = { image->GetDimension(0),image->GetDimension(1),1}; + imageCopy->Initialize(image->GetPixelType(), 3, dim); + imageCopy->SetGeometry(image->GetGeometry()); + mitk::ImageReadAccessor inputReadAccessorCopy(image, image->GetSliceData(0)); + imageCopy->SetSlice(inputReadAccessorCopy.GetData(), 0); + if (m_UseBModeFilter) + { + image = ApplyBmodeFilter(image, true, m_VerticalSpacing); + imageCopy = ApplyBmodeFilter(imageCopy, false, m_VerticalSpacing); + } + if (m_CompensateForScattering) + { + // update the fluence reference images! + bool doResampling = image->GetDimension(0) != m_FluenceCompResized.at(m_ScatteringCoefficient)->GetDimension(0) || image->GetDimension(1) != m_FluenceCompResized.at(m_ScatteringCoefficient)->GetDimension(1); + if (doResampling) + { + auto& curResizeImage = m_FluenceCompResized.at(m_ScatteringCoefficient); + curResizeImage = ApplyResampling(m_FluenceCompOriginal.at(m_ScatteringCoefficient), image->GetGeometry()->GetSpacing(), image->GetDimensions()); + + double* rawOutputData = new double[image->GetDimension(0)*image->GetDimension(1)]; + double* rawScatteringData = (double*)curResizeImage->GetData(); + int sizeRawScatteringData = curResizeImage->GetDimension(0) * curResizeImage->GetDimension(1); + + for (int i = 0; i < image->GetDimension(0)*image->GetDimension(1); ++i) + { + if (i < sizeRawScatteringData) + rawOutputData[i] = 1/rawScatteringData[i]; + else + rawOutputData[i] = 0; + } + + unsigned int dim[] = { image->GetDimension(0), image->GetDimension(1), 1 }; + curResizeImage->Initialize(mitk::MakeScalarPixelType(), 3, dim); + curResizeImage->SetGeometry(image->GetGeometry()); + curResizeImage->SetSlice(rawOutputData,0); + + mitk::CastToItkImage(curResizeImage, m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); + } + imageCopy = ApplyScatteringCompensation(imageCopy, m_ScatteringCoefficient); + } + mitk::ImageReadAccessor inputReadAccessor(imageCopy, imageCopy->GetSliceData(0)); + image->SetSlice(inputReadAccessor.GetData(), 0); + } + } + } +} + +mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyBmodeFilter(mitk::Image::Pointer inputImage, bool UseLogFilter, float resampleSpacing) +{ + // we use this seperate ApplyBmodeFilter Method for processing of two-dimensional images + + // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage + typedef itk::Image< float, 3 > itkFloatImageType; + + typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; + BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter + + typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; + PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter + + typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; + ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); + + itkFloatImageType::Pointer itkImage; + + mitk::CastToItkImage(inputImage, itkImage); + + itkFloatImageType::Pointer bmode; + + if (UseLogFilter) + { + bModeFilter->SetInput(itkImage); + bModeFilter->SetDirection(1); + bmode = bModeFilter->GetOutput(); + } + else + { + photoacousticBModeFilter->SetInput(itkImage); + photoacousticBModeFilter->SetDirection(1); + bmode = photoacousticBModeFilter->GetOutput(); + } + + // resampleSpacing == 0 means: do no resampling + if (resampleSpacing == 0) + { + return mitk::GrabItkImageMemory(bmode); + } + + itkFloatImageType::SpacingType outputSpacing; + itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); + itkFloatImageType::SizeType outputSize = inputSize; + outputSize[0] = 256; + + outputSpacing[0] = itkImage->GetSpacing()[0] * (static_cast(inputSize[0]) / static_cast(outputSize[0])); + outputSpacing[1] = resampleSpacing; + outputSpacing[2] = 0.6; + + outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; + + typedef itk::IdentityTransform TransformType; + resampleImageFilter->SetInput(bmode); + resampleImageFilter->SetSize(outputSize); + resampleImageFilter->SetOutputSpacing(outputSpacing); + resampleImageFilter->SetTransform(TransformType::New()); + + resampleImageFilter->UpdateLargestPossibleRegion(); + return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); +} + +mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scattering) +{ + typedef itk::Image< float, 3 > itkFloatImageType; + typedef itk::MultiplyImageFilter MultiplyImageFilterType; + + itkFloatImageType::Pointer itkImage; + mitk::CastToItkImage(inputImage, itkImage); + + MultiplyImageFilterType::Pointer multiplyFilter = MultiplyImageFilterType::New(); + multiplyFilter->SetInput1(itkImage); + multiplyFilter->SetInput2(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); + + return mitk::GrabItkImageMemory(multiplyFilter->GetOutput()); +} + +mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyResampling(mitk::Image::Pointer inputImage, mitk::Vector3D outputSpacing, unsigned int outputSize[3]) +{ + typedef itk::Image< double, 3 > itkFloatImageType; + + typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; + ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); + + itkFloatImageType::Pointer itkImage; + + mitk::CastToItkImage(inputImage, itkImage); + + + itkFloatImageType::SpacingType outputSpacingItk; + itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); + itkFloatImageType::SizeType outputSizeItk = inputSizeItk; + itkFloatImageType::SpacingType inputSpacing = itkImage->GetSpacing(); + + outputSizeItk[0] = outputSize[0]; + outputSizeItk[1] = (inputSizeItk[1] * outputSize[0] / inputSizeItk[1]); + outputSizeItk[2] = 1; + + outputSpacingItk[0] = inputSpacing[0] * (double)inputSizeItk[0] / (double)outputSize[0]; + outputSpacingItk[1] = inputSpacing[1] * (double)inputSizeItk[1] / (double)outputSize[1]; + outputSpacingItk[2] = outputSpacing[2]; + + typedef itk::IdentityTransform TransformType; + resampleImageFilter->SetInput(itkImage); + resampleImageFilter->SetSize(outputSizeItk); + resampleImageFilter->SetOutputSpacing(outputSpacingItk); + resampleImageFilter->SetTransform(TransformType::New()); + + resampleImageFilter->UpdateLargestPossibleRegion(); + return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); +} + +void mitk::USDiPhASImageSource::ImageDataCallback( + short* rfDataChannelData, + int& channelDataChannelsPerDataset, + int& channelDataSamplesPerChannel, + int& channelDataTotalDatasets, + + short* rfDataArrayBeamformed, + int& beamformedLines, + int& beamformedSamples, + int& beamformedTotalDatasets, + + unsigned char* imageData, + int& imageWidth, + int& imageHeight, + int& imageBytesPerPixel, + int& imageSetsTotal, + + double& timeStamp) +{ + if (!m_PyroConnected) + { + m_Pyro = mitk::OphirPyro::New(); + MITK_INFO << "[Pyro Debug] OpenConnection: " << m_Pyro->OpenConnection(); + MITK_INFO << "[Pyro Debug] StartDataAcquisition: " << m_Pyro->StartDataAcquisition(); + m_PyroConnected = true; + } + + bool writeImage = ((m_DataType == DataType::Image_uChar) && (imageData != nullptr)) || ((m_DataType == DataType::Beamformed_Short) && (rfDataArrayBeamformed != nullptr)); + if (writeImage) + { + //get the timestamp we might save later on + m_CurrentImageTimestamp = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + + // create a new image and initialize it + mitk::Image::Pointer image = mitk::Image::New(); + + switch (m_DataType) + { + case DataType::Image_uChar: { + m_ImageDimensions[0] = imageWidth; + m_ImageDimensions[1] = imageHeight; + m_ImageDimensions[2] = imageSetsTotal; + image->Initialize(mitk::MakeScalarPixelType(), 3, m_ImageDimensions); + break; + } + case DataType::Beamformed_Short: { + m_ImageDimensions[0] = beamformedLines; + m_ImageDimensions[1] = beamformedSamples; + m_ImageDimensions[2] = beamformedTotalDatasets; + image->Initialize(mitk::MakeScalarPixelType(), 3, m_ImageDimensions); + break; + } + } + image->GetGeometry()->SetSpacing(m_ImageSpacing); + image->GetGeometry()->Modified(); + + // write the given buffer into the image + switch (m_DataType) + { + case DataType::Image_uChar: { + for (int i = 0; i < imageSetsTotal; i++) { + image->SetSlice(&imageData[i*imageHeight*imageWidth], i); + } + break; + } + + case DataType::Beamformed_Short: { + short* flipme = new short[beamformedLines*beamformedSamples*beamformedTotalDatasets]; + int pixelsPerImage = beamformedLines*beamformedSamples; + + for (int currentSet = 0; currentSet < beamformedTotalDatasets; currentSet++) + { + for (int sample = 0; sample < beamformedSamples; sample++) + { + for (int line = 0; line < beamformedLines; line++) + { + flipme[sample*beamformedLines + line + pixelsPerImage*currentSet] + = rfDataArrayBeamformed[line*beamformedSamples + sample + pixelsPerImage*currentSet]; + } + } // the beamformed pa image is flipped by 90 degrees; we need to flip it manually + } + + for (int i = 0; i < beamformedTotalDatasets; i++) { + image->SetSlice(&flipme[i*beamformedLines*beamformedSamples], i); + // set every image to a different slice + } + + delete[] flipme; + break; + } + } + + itk::Index<3> pixel = { { (image->GetDimension(0) / 2), 84, 0 } }; //22/532*2048 TODO: make this more general to any Spacing/Sampling, Depth, etc + if (!m_Pyro->IsSyncDelaySet() &&(image->GetPixelValueByIndex(pixel) < -30)) // #MagicNumber + { + MITK_INFO << "Setting SyncDelay"; + m_Pyro->SetSyncDelay(m_CurrentImageTimestamp); + } + + m_ImageTimestampBuffer[(m_LastWrittenImage + 1) % m_BufferSize] = m_CurrentImageTimestamp; + m_ImageBuffer[(m_LastWrittenImage + 1) % m_BufferSize] = image; + m_LastWrittenImage = (m_LastWrittenImage + 1) % m_BufferSize; + + // if the user decides to start recording, we feed the vector the generated images + if (m_CurrentlyRecording) { + for (int index = 0; index < image->GetDimension(2); ++index) + { + if (image->IsSliceSet(index)) + { + m_RecordedImages.push_back(Image::New()); + unsigned int dim[] = { image ->GetDimension(0), image->GetDimension(1), 1}; + m_RecordedImages.back()->Initialize(image->GetPixelType(), 3, dim); + m_RecordedImages.back()->SetGeometry(image->GetGeometry()); + + mitk::ImageReadAccessor inputReadAccessor(image, image->GetSliceData(index)); + m_RecordedImages.back()->SetSlice(inputReadAccessor.GetData(),0); + } + } + m_ImageTimestampRecord.push_back(m_CurrentImageTimestamp); + // save timestamps for each laser image! + } + } +} + +void mitk::USDiPhASImageSource::UpdateImageGeometry() +{ + MITK_INFO << "Retreaving Image Geometry Information for Spacing..."; + float& recordTime = m_device->GetScanMode().receivePhaseLengthSeconds; + int& speedOfSound = m_device->GetScanMode().averageSpeedOfSound; + float& pitch = m_device->GetScanMode().reconstructedLinePitchMmOrAngleDegree; + int& reconstructionLines = m_device->GetScanMode().reconstructionLines; + + switch (m_DataType) + { + case DataType::Image_uChar : { + int& imageWidth = m_device->GetScanMode().imageWidth; + int& imageHeight = m_device->GetScanMode().imageHeight; + m_ImageSpacing[0] = pitch * reconstructionLines / imageWidth; + m_ImageSpacing[1] = recordTime * speedOfSound / 2 * 1000 / imageHeight; + break; + } + case DataType::Beamformed_Short : { + int& imageWidth = reconstructionLines; + int& imageHeight = m_device->GetScanMode().reconstructionSamplesPerLine; + m_ImageSpacing[0] = pitch; + m_ImageSpacing[1] = recordTime * speedOfSound / 2 * 1000 / imageHeight; + break; + } + } + m_ImageSpacing[2] = 0.6; + + MITK_INFO << "Retreaving Image Geometry Information for Spacing " << m_ImageSpacing[0] << " ... " << m_ImageSpacing[1] << " ... " << m_ImageSpacing[2] << " ...[DONE]"; +} + +void mitk::USDiPhASImageSource::ModifyDataType(DataType DataT) +{ + m_DataTypeModified = true; + m_DataTypeNext = DataT; +} + +void mitk::USDiPhASImageSource::ModifyUseBModeFilter(bool isSet) +{ + m_UseBModeFilterModified = true; + m_UseBModeFilterNext = isSet; +} + +void mitk::USDiPhASImageSource::ModifyScatteringCoefficient(int coeff) +{ + m_ScatteringCoefficientNext = coeff; + m_ScatteringCoefficientModified = true; +} + +void mitk::USDiPhASImageSource::ModifyCompensateForScattering(bool useIt) +{ + m_CompensateForScatteringNext = useIt; + m_CompensateForScatteringModified = true; +} + +void mitk::USDiPhASImageSource::SetDataType(DataType DataT) +{ + if (DataT != m_DataType) + { + m_DataType = DataT; + MITK_INFO << "Setting new DataType..." << DataT; + switch (m_DataType) + { + case DataType::Image_uChar : + MITK_INFO << "height: " << m_device->GetScanMode().imageHeight << " width: " << m_device->GetScanMode().imageWidth; + break; + case DataType::Beamformed_Short : + MITK_INFO << "samples: " << m_device->GetScanMode().reconstructionSamplesPerLine << " lines: " << m_device->GetScanMode().reconstructionLines; + break; + } + } +} + +void mitk::USDiPhASImageSource::SetGUIOutput(std::function out) +{ + USDiPhASImageSource::m_GUIOutput = out; + m_StartTime = ((float)std::clock()) / CLOCKS_PER_SEC; //wait till the callback is available again + m_UseGUIOutPut = false; +} + +void mitk::USDiPhASImageSource::SetUseBModeFilter(bool isSet) +{ + m_UseBModeFilter = isSet; +} + +void mitk::USDiPhASImageSource::SetVerticalSpacing(float mm) +{ + m_VerticalSpacingNext = mm; + m_VerticalSpacingModified = true; +} + +// this is just a little function to set the filenames below right +inline void replaceAll(std::string& str, const std::string& from, const std::string& to) { + if (from.empty()) + return; + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } +} + +void mitk::USDiPhASImageSource::SetRecordingStatus(bool record) +{ + // start the recording process + if (record) + { + m_RecordedImages.clear(); // we make sure there are no leftovers + m_ImageTimestampRecord.clear(); // also for the timestamps + m_PixelValues.clear(); // aaaand for the pixel values + + // tell the callback to start recording images + m_CurrentlyRecording = true; + } + // save images, end recording, and clean up + else + { + m_CurrentlyRecording = false; + + // get the time and date, put them into a nice string and create a folder for the images + time_t time = std::time(nullptr); + time_t* timeptr = &time; + std::string currentDate = std::ctime(timeptr); + replaceAll(currentDate, ":", "-"); + currentDate.pop_back(); + std::string MakeFolder = "mkdir \"c:/DiPhASImageData/" + currentDate + "\""; + system(MakeFolder.c_str()); + + // initialize file paths and the images + Image::Pointer PAImage = Image::New(); + Image::Pointer USImage = Image::New(); + std::string pathPA = "c:\\DiPhASImageData\\" + currentDate + "\\" + "PAImages" + ".nrrd"; + std::string pathUS = "c:\\DiPhASImageData\\" + currentDate + "\\" + "USImages" + ".nrrd"; + std::string pathTS = "c:\\DiPhASImageData\\" + currentDate + "\\" + "TimestampsImages" + ".csv"; + + if (m_device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) // save a PAImage if we used interleaved mode + { + // first, save the data, so the pyro does not aquire more unneccessary timestamps + m_Pyro->SaveData(); + + // now order the images and save them + OrderImagesInterleaved(PAImage, USImage); + mitk::IOUtil::Save(USImage, pathUS); + mitk::IOUtil::Save(PAImage, pathPA); + + // read the pixelvalues of the enveloped images at this position + itk::Index<3> pixel = { { m_RecordedImages.at(1)->GetDimension(0) / 2, 84, 0 } }; //22/532*2048 + GetPixelValues(pixel); + + // save the timestamps! + ofstream timestampFile; + + timestampFile.open(pathTS); + timestampFile << ",timestamp,pixelvalue"; // write the header + + for (int index = 0; index < m_ImageTimestampRecord.size(); ++index) + { + timestampFile << "\n" << index << "," << m_ImageTimestampRecord.at(index) << "," << m_PixelValues.at(index); + } + timestampFile.close(); + } + else if (m_device->GetScanMode().beamformingAlgorithm == (int)Beamforming::PlaneWaveCompound) // save no PAImage if we used US only mode + { + OrderImagesUltrasound(USImage); + mitk::IOUtil::Save(USImage, pathUS); + } + + m_PixelValues.clear(); // clean up the pixel values + m_RecordedImages.clear(); // clean up the images + m_ImageTimestampRecord.clear(); // clean up the timestamps + } +} + +void mitk::USDiPhASImageSource::GetPixelValues(itk::Index<3> pixel) +{ + unsigned int events = m_device->GetScanMode().transmitEventsCount + 1; // the PA event is not included in the transmitEvents, so we add 1 here + for (int index = 0; index < m_RecordedImages.size(); index += events) // omit sound images + { + Image::Pointer image = ApplyBmodeFilter(m_RecordedImages.at(index)); + m_PixelValues.push_back(image.GetPointer()->GetPixelValueByIndex(pixel)); + } +} + +void mitk::USDiPhASImageSource::OrderImagesInterleaved(Image::Pointer PAImage, Image::Pointer USImage) +{ + unsigned int width = 32; + unsigned int height = 32; + unsigned int events = m_device->GetScanMode().transmitEventsCount + 1; // the PA event is not included in the transmitEvents, so we add 1 here + + if (m_DataType == DataType::Beamformed_Short) + { + width = m_device->GetScanMode().reconstructionLines; + height = m_device->GetScanMode().reconstructionSamplesPerLine; + } + else if (m_DataType == DataType::Image_uChar) + { + width = m_device->GetScanMode().imageWidth; + height = m_device->GetScanMode().imageHeight; + } + + unsigned int dimLaser[] = { width, height, m_RecordedImages.size() / events}; + unsigned int dimSound[] = { width, height, m_RecordedImages.size() / events * (events-1)}; + + PAImage->Initialize(m_RecordedImages.back()->GetPixelType(), 3, dimLaser); + PAImage->SetGeometry(m_RecordedImages.back()->GetGeometry()); + USImage->Initialize(m_RecordedImages.back()->GetPixelType(), 3, dimSound); + USImage->SetGeometry(m_RecordedImages.back()->GetGeometry()); + + for (int index = 0; index < m_RecordedImages.size(); ++index) + { + mitk::ImageReadAccessor inputReadAccessor(m_RecordedImages.at(index)); + if (index % events == 0) + { + PAImage->SetSlice(inputReadAccessor.GetData(), index / events); + } + else + { + USImage->SetSlice(inputReadAccessor.GetData(), ((index - (index % events)) / events) + (index % events)-1); + } + } +} + +void mitk::USDiPhASImageSource::OrderImagesUltrasound(Image::Pointer SoundImage) +{ + unsigned int width = 32; + unsigned int height = 32; + unsigned int events = m_device->GetScanMode().transmitEventsCount; + + if (m_DataType == DataType::Beamformed_Short) + { + width = m_device->GetScanMode().reconstructionLines; + height = m_device->GetScanMode().reconstructionSamplesPerLine; + } + else if (m_DataType == DataType::Image_uChar) + { + width = m_device->GetScanMode().imageWidth; + height = m_device->GetScanMode().imageHeight; + } + + unsigned int dimSound[] = { width, height, m_RecordedImages.size()}; + + SoundImage->Initialize(m_RecordedImages.back()->GetPixelType(), 3, dimSound); + SoundImage->SetGeometry(m_RecordedImages.back()->GetGeometry()); + + for (int index = 0; index < m_RecordedImages.size(); ++index) + { + mitk::ImageReadAccessor inputReadAccessor(m_RecordedImages.at(index)); + SoundImage->SetSlice(inputReadAccessor.GetData(), index); + } +} \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h new file mode 100644 index 0000000000..6d7d745e4e --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h @@ -0,0 +1,179 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef MITKUSDiPhASImageSource_H_HEADER_INCLUDED_ +#define MITKUSDiPhASImageSource_H_HEADER_INCLUDED_ + + +#include "mitkUSImageSource.h" +#include "mitkUSDiPhASCustomControls.h" + +#include "Framework.IBMT.US.CWrapper.h" + +#include "mitkImageReadAccessor.h" +#include "itkFastMutexLock.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace mitk { + +class USDiPhASDevice; +/** + * \brief Implementation of mitk::USImageSource for DiPhAS API devices. + * The method mitk::USImageSource::GetNextRawImage() is implemented for + * getting images from the DiPhAS API. + * + * The image data is given to this class from the DiPhAS API by calling + * a callback method that writes the image data to an mitk::image + */ +class USDiPhASImageSource : public USImageSource +{ + +public: + mitkClassMacro(USDiPhASImageSource, USImageSource); + mitkNewMacro1Param(Self, mitk::USDiPhASDevice*); + itkCloneMacro(Self); + + typedef mitk::USDiPhASDeviceCustomControls::DataType DataType; + + /** + * Implementation of the superclass method. Returns the pointer + * to the mitk::Image filled by DiPhAS API callback. + */ + virtual void GetNextRawImage( mitk::Image::Pointer& ); + + /** + * The API calls this function to pass the image data to the + * user; here the m_Image is updated + */ + void mitk::USDiPhASImageSource::ImageDataCallback( + short* rfDataChannelData, + int& channelDataChannelsPerDataset, + int& channelDataSamplesPerChannel, + int& channelDataTotalDatasets, + + short* rfDataArrayBeamformed, + int& beamformedLines, + int& beamformedSamples, + int& beamformedTotalDatasets, + + unsigned char* imageData, + int& imageWidth, + int& imageHeight, + int& imagePixelFormat, + int& imageSetsTotal, + + double& timeStamp); + + void SetGUIOutput(std::function out); + + /** This starts or ends the recording session*/ + void SetRecordingStatus(bool record); + void SetVerticalSpacing(float mm); + + void ModifyDataType(DataType DataT); + void ModifyUseBModeFilter(bool isSet); + void ModifyScatteringCoefficient(int coeff); + void ModifyCompensateForScattering(bool useIt); + + /** + * Sets the spacing used in the image based on the informations of the ScanMode in USDiPhAS Device + */ + void UpdateImageGeometry(); + +protected: + void SetDataType(DataType DataT); + void SetUseBModeFilter(bool isSet); + + USDiPhASImageSource(mitk::USDiPhASDevice* device); + virtual ~USDiPhASImageSource( ); + + /** This vector holds all the images we record, if recording is set to active. */ + std::vector m_RecordedImages; + std::vector m_ImageTimestampRecord; + std::vector m_ImageTimestampBuffer; + long long m_CurrentImageTimestamp; + bool m_CurrentlyRecording; + mitk::OphirPyro::Pointer m_Pyro; + bool m_PyroConnected; + + std::vector m_FluenceCompOriginal; + std::vector m_FluenceCompResized; + std::vector::Pointer> m_FluenceCompResizedItk; + + std::vector m_ImageBuffer; + int m_LastWrittenImage; + int m_BufferSize; + + unsigned int m_ImageDimensions[3]; + mitk::Vector3D m_ImageSpacing; + + mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, bool UseLogFilter = false, float resampleSpacing = 0.15); + mitk::Image::Pointer ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scatteringCoefficient); + mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, mitk::Vector3D outputSpacing, unsigned int outputSize[3]); + + void OrderImagesInterleaved(Image::Pointer LaserImage, Image::Pointer SoundImage); + void OrderImagesUltrasound(Image::Pointer SoundImage); + + void GetPixelValues(itk::Index<3> pixel); + float GetPixelValue(itk::Index<3> pixel); + std::vector m_PixelValues; + + mitk::USDiPhASDevice* m_device; + + /** This is a callback to pass text data to the GUI. */ + std::function m_GUIOutput; + + + /** + * Variables for management of current state. + */ + float m_StartTime; + bool m_UseGUIOutPut; + + BeamformerStateInfoNative m_BeamformerInfos; + bool m_UseBModeFilter; + + bool m_DataTypeModified; + DataType m_DataTypeNext; + + bool m_UseBModeFilterModified; + bool m_UseBModeFilterNext; + + float m_VerticalSpacing; + float m_VerticalSpacingNext; + bool m_VerticalSpacingModified; + + int m_ScatteringCoefficient; + int m_ScatteringCoefficientNext; + bool m_ScatteringCoefficientModified; + + bool m_CompensateForScattering; + bool m_CompensateForScatteringNext; + bool m_CompensateForScatteringModified; + + DataType m_DataType; +}; +} // namespace mitk + +#endif // MITKUSDiPhASImageSource_H diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbe.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbe.cpp new file mode 100644 index 0000000000..b51f585976 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbe.cpp @@ -0,0 +1,27 @@ +/*=================================================================== + +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 "mitkUSDiPhASProbe.h" +#include "Framework.IBMT.US.CWrapper.h" + +mitk::USDiPhASProbe::USDiPhASProbe(std::string ProbeName) +{ + SetName(ProbeName); +} + +mitk::USDiPhASProbe::~USDiPhASProbe() +{ +} \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbe.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbe.h new file mode 100644 index 0000000000..e89e3abf3b --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbe.h @@ -0,0 +1,50 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef MITKUSDiPhASProbe_H_HEADER_INCLUDED_ +#define MITKUSDiPhASProbe_H_HEADER_INCLUDED_ + +#include "mitkUSProbe.h" + +namespace mitk +{ + /** + * \brief Specialized mitk::USProbe for handling DiPhAS API probe objects. + * It encapsulates a probe object from the DiPhAS API. + * + * This class should only be instantiated by mitk::USDiPhASProbesControls. + * Every other object can get instances of mitk::USDiPhASProbe from there. + */ + class USDiPhASProbe : public USProbe + { + public: + mitkClassMacro(USDiPhASProbe, USProbe); + mitkNewMacro1Param(Self, std::string); + + protected: + /** + * Constructs mitk::USDiPhASProbe object with given API objects. + * + * \param probe API probe object which should be represented by the constructed object + * \param dataView API data view object conected to this probe object + */ + USDiPhASProbe(std::string ProbeName); + virtual ~USDiPhASProbe(); + + }; +} // namespace mitk + +#endif // MITKUSDiPhASProbe_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbesControls.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbesControls.cpp new file mode 100644 index 0000000000..d40d09d4da --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbesControls.cpp @@ -0,0 +1,113 @@ +/*=================================================================== + +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 "mitkUSDiPhASProbesControls.h" +#include "mitkUSDiPhASDevice.h" +#include + +mitk::USDiPhASProbesControls::USDiPhASProbesControls(itk::SmartPointer device) + : mitk::USControlInterfaceProbes(device.GetPointer()), + m_IsActive(false), m_DiPhASDevice(device) +{ +} + +mitk::USDiPhASProbesControls::~USDiPhASProbesControls() +{ +} + + +void mitk::USDiPhASProbesControls::SetIsActive(bool isActive) +{ + this->CreateProbesSet(); + m_IsActive = isActive; +} + +bool mitk::USDiPhASProbesControls::GetIsActive() +{ + return m_IsActive; +} + +std::vector mitk::USDiPhASProbesControls::GetProbeSet() +{ + // create a new vector of base class (USProbe) objects, because + // interface wants a vector of this type + std::vector usProbes(m_ProbesSet.size(), 0); + for (unsigned int n = 0; n < m_ProbesSet.size(); ++n) + { + usProbes.at(n) = m_ProbesSet.at(n).GetPointer(); + } + return usProbes; +} + +void mitk::USDiPhASProbesControls::OnSelectProbe(unsigned int index) +{ + if (index >= m_ProbesSet.size()) + { + MITK_ERROR("USDiPhASProbesControls")("USControlInterfaceProbes") + << "Cannot select probe with index " << index << ". Maximum possible index is " << m_ProbesSet.size() - 1 << "."; + mitkThrow() << "Cannot select probe with index " << index << + ". Maximum possible index is " << m_ProbesSet.size() - 1 << "."; + } + + m_SelectedProbeIndex = index; +} + +void mitk::USDiPhASProbesControls::OnSelectProbe(mitk::USProbe::Pointer probe) +{ +} + +mitk::USProbe::Pointer mitk::USDiPhASProbesControls::GetSelectedProbe() +{ + if (m_SelectedProbeIndex >= m_ProbesSet.size()) + { + MITK_ERROR("USDiPhASProbesControls")("USControlInterfaceProbes") + << "Cannot get active probe as the current index is" << m_SelectedProbeIndex << + ". Maximum possible index is " << m_ProbesSet.size() - 1 << "."; + mitkThrow() << "Cannot get active probe as the current index is" << m_SelectedProbeIndex << + ". Maximum possible index is " << m_ProbesSet.size() - 1 << "."; + } + + return m_ProbesSet.at(m_SelectedProbeIndex).GetPointer(); +} + +unsigned int mitk::USDiPhASProbesControls::GetProbesCount() const +{ + return m_ProbesSet.size(); +} + + +void mitk::USDiPhASProbesControls::ProbeRemoved(unsigned int index) +{ + MITK_INFO << "Probe removed..."; + + if (m_ProbesSet.size() > index) + { + m_ProbesSet.erase(m_ProbesSet.begin() + index); + } +} + +void mitk::USDiPhASProbesControls::ProbeAdded(unsigned int index) +{ + MITK_INFO << "Probe arrived..."; + + this->CreateProbesSet(); +} + +void mitk::USDiPhASProbesControls::CreateProbesSet() +{ + m_ProbesSet.push_back(mitk::USDiPhASProbe::New( m_DiPhASDevice->GetScanMode().transducerName )); +} \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbesControls.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbesControls.h new file mode 100644 index 0000000000..daaa9c6466 --- /dev/null +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASProbesControls.h @@ -0,0 +1,87 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef MITKUSDiPhASProbesControls_H_HEADER_INCLUDED_ +#define MITKUSDiPhASProbesControls_H_HEADER_INCLUDED_ + +#include "Framework.IBMT.US.CWrapper.h" +#include "mitkUSDiPhASProbe.h" +#include "mitkUSControlInterfaceProbes.h" + +#include + +namespace mitk { + class USDiPhASDevice; + + /** + * \brief Implementation of mitk::USControlInterfaceProbes for DiPhAS ultrasound devices. + * See documentation of mitk::USControlInterfaceProbes for a description of the interface methods. + * This class has to be implemented for the USDevice but the DiPhAS API does not support multiple devices. + * Therefore there will be just one probe at all times. + */ + class USDiPhASProbesControls : public USControlInterfaceProbes + { + public: + mitkClassMacro(USDiPhASProbesControls, USControlInterfaceProbes); + mitkNewMacro1Param(Self, itk::SmartPointer); + + /** + * Probe informations are fetched on activation. On deactivation there is nothing done. + */ + virtual void SetIsActive(bool); + + virtual bool GetIsActive(); + + virtual std::vector GetProbeSet(); + virtual void OnSelectProbe(unsigned int index); + virtual void OnSelectProbe(USProbe::Pointer probe); + virtual USProbe::Pointer GetSelectedProbe(); + virtual unsigned int GetProbesCount() const; + + void ProbeRemoved(unsigned int index); + void ProbeAdded(unsigned int index); + + protected: + /** + * Constructs an empty object. + * DiPhAS device has to be set after constructing by calling + * mitk::USDiPhASProbesControls::SetDiPhASDevice before the + * object can be used. + */ + USDiPhASProbesControls(itk::SmartPointer device); + virtual ~USDiPhASProbesControls(); + + /** + * Create collection object (DiPhAS API) for the API device. + */ + bool CreateProbesCollection(); + + /** + * Create vector of mitk::USDiPhASProbe objects from the + * DiPhAS API probe collection. Hence + * mitk::USDiPhASProbesControls::CreateProbesCollection has to + * be called before. + */ + void CreateProbesSet(); + + bool m_IsActive; + unsigned int m_SelectedProbeIndex; + std::vector m_ProbesSet; + itk::SmartPointer m_DiPhASDevice; + }; +} + +#endif // MITKUSDiPhASProbesControls_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/resources/FranzTissue.nrrd b/Modules/US/USHardwareDiPhAS/resources/FranzTissue.nrrd new file mode 100644 index 0000000000..224a89f7ff Binary files /dev/null and b/Modules/US/USHardwareDiPhAS/resources/FranzTissue.nrrd differ diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index c926eea67c..e9b0f45c6b 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,664 +1,671 @@ /*=================================================================== 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 "mitkUSDevice.h" #include "mitkImageReadAccessor.h" // US Control Interfaces #include "mitkUSControlInterfaceProbes.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceDoppler.h" // Microservices #include #include #include #include mitk::USDevice::PropertyKeys mitk::USDevice::GetPropertyKeys() { static mitk::USDevice::PropertyKeys propertyKeys; return propertyKeys; } mitk::USDevice::USImageCropArea mitk::USDevice::GetCropArea() { MITK_INFO << "Return Crop Area L:" << m_CropArea.cropLeft << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop << " B:" << m_CropArea.cropBottom; return m_CropArea; } mitk::USDevice::USDevice(std::string manufacturer, std::string model) : mitk::ImageSource(), m_IsFreezed(false), m_DeviceState(State_NoState), m_Manufacturer(manufacturer), m_Name(model), m_SpawnAcquireThread(true), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_UnregisteringStarted(false) { USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(1); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::USDevice(mitk::USImageMetadata::Pointer metadata) : mitk::ImageSource(), m_IsFreezed(false), m_DeviceState(State_NoState), m_SpawnAcquireThread(true), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_UnregisteringStarted(false) { m_Manufacturer = metadata->GetDeviceManufacturer(); m_Name = metadata->GetDeviceModel(); m_Comment = metadata->GetDeviceComment(); USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(1); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::~USDevice() { if (m_ThreadID >= 0) { m_MultiThreader->TerminateThread(m_ThreadID); } // make sure that the us device is not registered at the micro service // anymore after it is destructed this->UnregisterOnService(); } mitk::USAbstractControlInterface::Pointer mitk::USDevice::GetControlInterfaceCustom() { MITK_INFO << "Custom control interface does not exist for this object."; return 0; } mitk::USControlInterfaceBMode::Pointer mitk::USDevice::GetControlInterfaceBMode() { MITK_INFO << "Control interface BMode does not exist for this object."; return 0; } mitk::USControlInterfaceProbes::Pointer mitk::USDevice::GetControlInterfaceProbes() { MITK_INFO << "Control interface Probes does not exist for this object."; return 0; } mitk::USControlInterfaceDoppler::Pointer mitk::USDevice::GetControlInterfaceDoppler() { MITK_INFO << "Control interface Doppler does not exist for this object."; return 0; } void mitk::USDevice::SetManufacturer(std::string manufacturer) { m_Manufacturer = manufacturer; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER, manufacturer); } } void mitk::USDevice::SetName(std::string name) { m_Name = name; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME, name); } } void mitk::USDevice::SetComment(std::string comment) { m_Comment = comment; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_COMMENT, comment); } } us::ServiceProperties mitk::USDevice::ConstructServiceProperties() { mitk::USDevice::PropertyKeys propertyKeys = mitk::USDevice::GetPropertyKeys(); us::ServiceProperties props; props[propertyKeys.US_PROPKEY_ISCONNECTED] = this->GetIsConnected() ? "true" : "false"; props[propertyKeys.US_PROPKEY_ISACTIVE] = this->GetIsActive() ? "true" : "false"; props[propertyKeys.US_PROPKEY_LABEL] = this->GetServicePropertyLabel(); // get identifier of selected probe if there is one selected mitk::USControlInterfaceProbes::Pointer probesControls = this->GetControlInterfaceProbes(); if (probesControls.IsNotNull() && probesControls->GetIsActive()) { mitk::USProbe::Pointer probe = probesControls->GetSelectedProbe(); if (probe.IsNotNull()) { props[propertyKeys.US_PROPKEY_PROBES_SELECTED] = probe->GetName(); } } props[propertyKeys.US_PROPKEY_CLASS] = GetDeviceClass(); props[propertyKeys.US_PROPKEY_MANUFACTURER] = m_Manufacturer; props[propertyKeys.US_PROPKEY_NAME] = m_Name; props[propertyKeys.US_PROPKEY_COMMENT] = m_Comment; m_ServiceProperties = props; return props; } void mitk::USDevice::UnregisterOnService() { // unregister on micro service if (m_ServiceRegistration && !m_UnregisteringStarted) { // make sure that unregister is not started a second // time due to a callback during unregister for example m_UnregisteringStarted = true; m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; } } bool mitk::USDevice::Initialize() { if (!this->OnInitialization()) { return false; } m_DeviceState = State_Initialized; // Get Context and Module us::ModuleContext* context = us::GetModuleContext(); us::ServiceProperties props = this->ConstructServiceProperties(); m_ServiceRegistration = context->RegisterService(this, props); return true; } bool mitk::USDevice::Connect() { MITK_DEBUG << "mitk::USDevice::Connect() called"; if (this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Tried to connect an ultrasound device that " "was already connected. Ignoring call..."; return true; } if (!this->GetIsInitialized()) { MITK_ERROR("mitkUSDevice") << "Cannot connect device if it is not in initialized state."; return false; } // Prepare connection, fail if this fails. if (!this->OnConnection()) { return false; } // Update state m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, true); return true; } void mitk::USDevice::ConnectAsynchron() { this->m_MultiThreader->SpawnThread(this->ConnectThread, this); } bool mitk::USDevice::Disconnect() { if (!GetIsConnected()) { MITK_WARN << "Tried to disconnect an ultrasound device that was not " "connected. Ignoring call..."; return false; } // Prepare connection, fail if this fails. if (!this->OnDisconnection()) return false; // Update state m_DeviceState = State_Initialized; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, false); return true; } bool mitk::USDevice::Activate() { if (!this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Cannot activate device if it is not in connected state."; return true; } if (OnActivation()) { m_DeviceState = State_Activated; m_FreezeBarrier = itk::ConditionVariable::New(); // spawn thread for aquire images if us device is active if (m_SpawnAcquireThread) { this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); } this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, true); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); // initialize the b mode control properties of the micro service mitk::USControlInterfaceBMode::Pointer bmodeControls = this->GetControlInterfaceBMode(); if (bmodeControls.IsNotNull()) { bmodeControls->Initialize(); } } this->ProvideViaOIGTL(); return m_DeviceState == State_Activated; } void mitk::USDevice::ProvideViaOIGTL() { // create a new OpenIGTLink Server if (m_IGTLServer.IsNull()) m_IGTLServer = mitk::IGTLServer::New(true); m_IGTLServer->SetName(this->GetName()); // create a new OpenIGTLink Device source if (m_IGTLMessageProvider.IsNull()) m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); // set the OpenIGTLink server as the source for the device source m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); // register the provider so that it can be configured with the IGTL manager // plugin. This could be hardcoded but now I already have the fancy plugin. m_IGTLMessageProvider->RegisterAsMicroservice(); m_ImageToIGTLMsgFilter = mitk::ImageToIGTLMessageFilter::New(); m_ImageToIGTLMsgFilter->ConnectTo(this); // set the name of this filter to identify it easier m_ImageToIGTLMsgFilter->SetName(this->GetName()); // register this filter as micro service. The message provider looks for // provided IGTLMessageSources, once it found this microservice and someone // requested this data type then the provider will connect with this filter // automatically. m_ImageToIGTLMsgFilter->RegisterAsMicroservice(); } void mitk::USDevice::Deactivate() { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot deactivate a device which is not activae."; return; } if (!OnDeactivation()) { return; } DisableOIGTL(); m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, false); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); } void mitk::USDevice::DisableOIGTL() { // TODO: This seems not to be enough cleanup to catch all cases. For example, if the device is disconnected // from the OIGTL GUI, this won't get cleaned up correctly. m_IGTLServer->CloseConnection(); m_IGTLMessageProvider->UnRegisterMicroservice(); m_ImageToIGTLMsgFilter->UnRegisterMicroservice(); } void mitk::USDevice::SetIsFreezed(bool freeze) { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot freeze or unfreeze if device is not active."; return; } this->OnFreeze(freeze); if (freeze) { m_IsFreezed = true; } else { m_IsFreezed = false; // wake up the image acquisition thread m_FreezeBarrier->Signal(); } } bool mitk::USDevice::GetIsFreezed() { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice")("mitkUSTelemedDevice") << "Cannot get freeze state if the hardware interface is not ready. " "Returning false..."; return false; } return m_IsFreezed; } void mitk::USDevice::PushFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } imageSource->PushFilter(filter); } void mitk::USDevice::PushFilterIfNotPushedBefore( AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } if (!imageSource->GetIsFilterInThePipeline(filter)) { imageSource->PushFilter(filter); } } bool mitk::USDevice::RemoveFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when removing a filter."; } return imageSource->RemoveFilter(filter); } void mitk::USDevice::UpdateServiceProperty(std::string key, std::string value) { m_ServiceProperties[key] = value; m_ServiceRegistration.SetProperties(m_ServiceProperties); // send event to notify listeners about the changed property m_PropertyChangedMessage(key, value); } void mitk::USDevice::UpdateServiceProperty(std::string key, double value) { std::stringstream stream; stream << value; this->UpdateServiceProperty(key, stream.str()); } void mitk::USDevice::UpdateServiceProperty(std::string key, bool value) { this->UpdateServiceProperty( key, value ? std::string("true") : std::string("false")); } /** mitk::Image* mitk::USDevice::GetOutput() { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetPrimaryOutput()); } mitk::Image* mitk::USDevice::GetOutput(unsigned int idx) { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetOutput(idx)); } void mitk::USDevice::GraftOutput(itk::DataObject *graft) { this->GraftNthOutput(0, graft); } void mitk::USDevice::GraftNthOutput(unsigned int idx, itk::DataObject *graft) { if ( idx >= this->GetNumberOfOutputs() ) { itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter only has " << this->GetNumberOfOutputs() << " Outputs."); } if ( !graft ) { itkExceptionMacro(<<"Requested to graft output with a nullptr pointer object" ); } itk::DataObject* output = this->GetOutput(idx); if ( !output ) { itkExceptionMacro(<<"Requested to graft output that is a nullptr pointer" ); } // Call Graft on USImage to copy member data output->Graft( graft ); } */ void mitk::USDevice::GrabImage() { mitk::Image::Pointer image = this->GetUSImageSource()->GetNextImage(); m_ImageMutex->Lock(); this->SetImage(image); m_ImageMutex->Unlock(); // if (image.IsNotNull() && (image->GetGeometry()!=nullptr)){ // MITK_INFO << "Spacing: " << image->GetGeometry()->GetSpacing();} } //########### GETTER & SETTER ##################// bool mitk::USDevice::GetIsInitialized() { return m_DeviceState == State_Initialized; } bool mitk::USDevice::GetIsActive() { return m_DeviceState == State_Activated; } bool mitk::USDevice::GetIsConnected() { return m_DeviceState == State_Connected; } std::string mitk::USDevice::GetDeviceManufacturer() { return m_Manufacturer; } std::string mitk::USDevice::GetDeviceModel() { return m_Name; } std::string mitk::USDevice::GetDeviceComment() { return m_Comment; } void mitk::USDevice::GenerateData() { m_ImageMutex->Lock(); if (m_Image.IsNull() || !m_Image->IsInitialized()) { m_ImageMutex->Unlock(); return; } mitk::Image::Pointer output = this->GetOutput(); if (!output->IsInitialized() || output->GetDimension(0) != m_Image->GetDimension(0) || - output->GetDimension(1) != m_Image->GetDimension(1)) + output->GetDimension(1) != m_Image->GetDimension(1) || + output->GetDimension(2) != m_Image->GetDimension(2) || + output->GetPixelType() != m_Image->GetPixelType()) { output->Initialize(m_Image->GetPixelType(), m_Image->GetDimension(), m_Image->GetDimensions()); } - mitk::ImageReadAccessor inputReadAccessor(m_Image, - m_Image->GetSliceData(0, 0, 0)); - output->SetSlice(inputReadAccessor.GetData()); + // copy contents of the given image into the member variable, slice after slice + for (int sliceNumber = 0; sliceNumber < m_Image->GetDimension(2); ++sliceNumber) + { + if (m_Image->IsSliceSet(sliceNumber)) { + mitk::ImageReadAccessor inputReadAccessor(m_Image, m_Image->GetSliceData(sliceNumber, 0, 0)); + output->SetSlice(inputReadAccessor.GetData(), sliceNumber); + } + } + output->SetGeometry(m_Image->GetGeometry()); m_ImageMutex->Unlock(); }; std::string mitk::USDevice::GetServicePropertyLabel() { std::string isActive; if (this->GetIsActive()) { isActive = " (Active)"; } else { isActive = " (Inactive)"; } // e.g.: Zonare MyLab5 (Active) return m_Manufacturer + " " + m_Name + isActive; } ITK_THREAD_RETURN_TYPE mitk::USDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; while (device->GetIsActive()) { // lock this thread when ultrasound device is freezed if (device->m_IsFreezed) { itk::SimpleMutexLock* mutex = &(device->m_FreezeMutex); mutex->Lock(); if (device->m_FreezeBarrier.IsNotNull()) { device->m_FreezeBarrier->Wait(mutex); } } - device->GrabImage(); } return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::USDevice::ConnectThread(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; device->Connect(); return ITK_THREAD_RETURN_VALUE; } void mitk::USDevice::ProbeChanged(std::string probename) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED, probename); } void mitk::USDevice::DepthChanged(double depth) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH, depth); } diff --git a/Modules/US/files.cmake b/Modules/US/files.cmake index 7125e7cc77..93bf7bcfb2 100644 --- a/Modules/US/files.cmake +++ b/Modules/US/files.cmake @@ -1,33 +1,34 @@ SET(CPP_FILES ## Module Activator mitkUSActivator.cpp ## Model Classes USModel/mitkUSImage.cpp USModel/mitkUSImageMetadata.cpp USModel/mitkUSDevice.cpp USModel/mitkUSIGTLDevice.cpp USModel/mitkUSVideoDevice.cpp USModel/mitkUSVideoDeviceCustomControls.cpp USModel/mitkUSProbe.cpp USModel/mitkUSDevicePersistence.cpp ## Filters and Sources USFilters/mitkUSImageLoggingFilter.cpp USFilters/mitkUSImageSource.cpp USFilters/mitkUSImageVideoSource.cpp USFilters/mitkIGTLMessageToUSImageFilter.cpp ## Control Interfaces USControlInterfaces/mitkUSAbstractControlInterface.cpp USControlInterfaces/mitkUSControlInterfaceBMode.cpp USControlInterfaces/mitkUSControlInterfaceProbes.cpp USControlInterfaces/mitkUSControlInterfaceDoppler.cpp +USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp ) set(RESOURCE_FILES Interactions/USPointMarkInteractions.xml Interactions/USZoneInteractions.xml Interactions/USZoneInteractionsHold.xml ) diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp new file mode 100644 index 0000000000..4231a6cafb --- /dev/null +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp @@ -0,0 +1,335 @@ +/*=================================================================== + +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 "QmitkUSControlsCustomDiPhASDeviceWidget.h" +#include "ui_QmitkUSControlsCustomDiPhASDeviceWidget.h" +#include + + +#include + +QmitkUSControlsCustomDiPhASDeviceWidget::QmitkUSControlsCustomDiPhASDeviceWidget(QWidget *parent) + : QmitkUSAbstractCustomWidget(parent), ui(new Ui::QmitkUSControlsCustomDiPhASDeviceWidget) +{ +} + +QmitkUSControlsCustomDiPhASDeviceWidget::~QmitkUSControlsCustomDiPhASDeviceWidget() +{ + m_ControlInterface = dynamic_cast + (this->GetDevice()->GetControlInterfaceCustom().GetPointer()); + + if (m_ControlInterface.IsNotNull()) + { + m_ControlInterface->passGUIOut([](QString str)->void {} ); + } + delete ui; +} + +std::string QmitkUSControlsCustomDiPhASDeviceWidget::GetDeviceClass() const +{ + return "org.mitk.modules.us.USDiPhASDevice"; +} + +QmitkUSAbstractCustomWidget* QmitkUSControlsCustomDiPhASDeviceWidget::Clone(QWidget* parent) const +{ + QmitkUSAbstractCustomWidget* clonedWidget = new QmitkUSControlsCustomDiPhASDeviceWidget(parent); + clonedWidget->SetDevice(this->GetDevice()); + return clonedWidget; +} + +void QmitkUSControlsCustomDiPhASDeviceWidget::OnDeviceSet() +{ + m_ControlInterface = dynamic_cast + (this->GetDevice()->GetControlInterfaceCustom().GetPointer()); + + if ( m_ControlInterface.IsNotNull() ) + { + m_ControlInterface->passGUIOut([this](QString str)->void{ + if (this && this->ui) { + this->ui->CurrentState->setText(str); + } }); + } + else + { + MITK_WARN("QmitkUSAbstractCustomWidget")("QmitkUSControlsCustomDiPhASDeviceWidget") + << "Did not get a custom device control interface."; + } + + //now pass the default values + + m_ControlInterface->SetSilentUpdate(true); // don't update the scanmode everytime + + OnTransmitPhaseLengthChanged(); + OnExcitationFrequencyChanged(); + OnTransmitEventsChanged(); + OnVoltageChanged(); + OnScanDepthChanged(); // HERE + OnAveragingCountChanged(); + OnTGCMinChanged(); + OnTGCMaxChanged(); + OnDataTypeChanged(); + OnPitchChanged(); + OnReconstructedSamplesChanged(); + OnReconstructedLinesChanged(); + OnSpeedOfSoundChanged(); + OnBandpassEnabledChanged(); + OnLowCutChanged(); + OnHighCutChanged(); + OnUseBModeFilterChanged(); // HERE + OnVerticalSpacingChanged(); + OnScatteringCoefficientChanged(); + OnCompensateScatteringChanged(); + + m_ControlInterface->SetSilentUpdate(false); // on the last update pass the scanmode and geometry! + + OnModeChanged(); // HERE +} + +void QmitkUSControlsCustomDiPhASDeviceWidget::Initialize() +{ + ui->setupUi(this); + + connect(ui->UseBModeFilter, SIGNAL(stateChanged(int)), this, SLOT(OnUseBModeFilterChanged())); + connect(ui->StartStopRecord, SIGNAL(clicked()), this, SLOT(OnRecordChanged())); + connect(ui->ScatteringCoefficient, SIGNAL(valueChanged(int)), this, SLOT(OnScatteringCoefficientChanged())); + connect(ui->CompensateScattering, SIGNAL(stateChanged(int)), this, SLOT(OnCompensateScatteringChanged())); + connect(ui->VerticalSpacing, SIGNAL(valueChanged(double)), this, SLOT(OnVerticalSpacingChanged())); + + //transmit + connect(ui->TransmitPhaseLength, SIGNAL(valueChanged(double)), this, SLOT(OnTransmitPhaseLengthChanged())); + connect(ui->ExcitationFrequency, SIGNAL(valueChanged(double)), this, SLOT(OnExcitationFrequencyChanged())); + connect(ui->TransmitEvents, SIGNAL(valueChanged(int)), this, SLOT(OnTransmitEventsChanged())); + connect(ui->Voltage, SIGNAL(valueChanged(int)), this, SLOT(OnVoltageChanged())); + connect(ui->Mode, SIGNAL(currentTextChanged(QString)), this, SLOT(OnModeChanged())); + + //Receive + connect(ui->ScanDepth, SIGNAL(valueChanged(double)), this, SLOT(OnScanDepthChanged())); + connect(ui->AveragingCount, SIGNAL(valueChanged(int)), this, SLOT(OnAveragingCountChanged())); + connect(ui->TimeGainCompensationMinSlider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCMinChanged())); + connect(ui->TimeGainCompensationMaxSlider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCMaxChanged())); + connect(ui->DataType, SIGNAL(currentTextChanged(QString)), this, SLOT(OnDataTypeChanged())); + + //Beamforming + connect(ui->PitchOfTransducer, SIGNAL(valueChanged(double)), this, SLOT(OnPitchChanged())); + connect(ui->ReconstructedSamplesPerLine, SIGNAL(valueChanged(int)), this, SLOT(OnReconstructedSamplesChanged())); + connect(ui->ReconstructedLines, SIGNAL(valueChanged(int)), this, SLOT(OnReconstructedLinesChanged())); + connect(ui->SpeedOfSound, SIGNAL(valueChanged(int)), this, SLOT(OnSpeedOfSoundChanged())); + + //Bandpass + connect(ui->BandpassEnabled, SIGNAL(currentTextChanged(QString)), this, SLOT(OnBandpassEnabledChanged())); + connect(ui->LowCut, SIGNAL(valueChanged(double)), this, SLOT(OnLowCutChanged())); + connect(ui->HighCut, SIGNAL(valueChanged(double)), this, SLOT(OnHighCutChanged())); +} + +//slots + +void QmitkUSControlsCustomDiPhASDeviceWidget::OnUseBModeFilterChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + bool UseBModeFilter = ui->UseBModeFilter->isChecked(); + m_ControlInterface->SetUseBModeFilter(UseBModeFilter); +} + +void QmitkUSControlsCustomDiPhASDeviceWidget::OnRecordChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + if (ui->StartStopRecord->text() == "Start Recording") + { + ui->StartStopRecord->setText("Stop Recording"); + m_ControlInterface->SetRecord(true); + } + else + { + ui->StartStopRecord->setText("Start Recording"); + m_ControlInterface->SetRecord(false); + } +} + +void QmitkUSControlsCustomDiPhASDeviceWidget::OnVerticalSpacingChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetVerticalSpacing(ui->VerticalSpacing->value()); +} + +void QmitkUSControlsCustomDiPhASDeviceWidget::OnScatteringCoefficientChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetScatteringCoefficient(ui->ScatteringCoefficient->value()); +} + +void QmitkUSControlsCustomDiPhASDeviceWidget::OnCompensateScatteringChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + if (ui->CompensateScattering->isChecked()) + ui->ScatteringCoefficient->setEnabled(true); + else + ui->ScatteringCoefficient->setEnabled(false); + + m_ControlInterface->SetCompensateScattering(ui->CompensateScattering->isChecked()); +} + + +//Transmit +void QmitkUSControlsCustomDiPhASDeviceWidget::OnTransmitPhaseLengthChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetTransmitPhaseLength(ui->TransmitPhaseLength->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnExcitationFrequencyChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetExcitationFrequency(ui->ExcitationFrequency->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnTransmitEventsChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + + m_ControlInterface->SetTransmitEvents(ui->TransmitEvents->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnVoltageChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetVoltage(ui->Voltage->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnModeChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + QString Mode = ui->Mode->currentText(); + bool silent = m_ControlInterface->GetSilentUpdate(); + m_ControlInterface->SetSilentUpdate(true); + + if (Mode == "Ultrasound only") { + m_ControlInterface->SetMode(false); + ui->TransmitEvents->setValue(1); + } + else if (Mode == "Interleaved") { + m_ControlInterface->SetMode(true); + ui->TransmitEvents->setValue(1); + } + if (!silent) { m_ControlInterface->SetSilentUpdate(false); } + OnTransmitEventsChanged(); +} + +//Receive +void QmitkUSControlsCustomDiPhASDeviceWidget::OnScanDepthChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetScanDepth(ui->ScanDepth->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnAveragingCountChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetAveragingCount(ui->AveragingCount->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnTGCMinChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + + int tgcMin = ui->TimeGainCompensationMinSlider->value(); + int tgcMax = ui->TimeGainCompensationMaxSlider->value(); + if (tgcMin > tgcMax) { + ui->TimeGainCompensationMinSlider->setValue(tgcMax); + MITK_INFO << "User tried to set tgcMin>tgcMax."; + } + + m_ControlInterface->SetTGCMin(ui->TimeGainCompensationMinSlider->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnTGCMaxChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + + int tgcMin = ui->TimeGainCompensationMinSlider->value(); + int tgcMax = ui->TimeGainCompensationMaxSlider->value(); + if (tgcMin > tgcMax) { + ui->TimeGainCompensationMaxSlider->setValue(tgcMin); + MITK_INFO << "User tried to set tgcMin>tgcMax."; + } + + m_ControlInterface->SetTGCMax(ui->TimeGainCompensationMaxSlider->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnDataTypeChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + QString DataType = ui->DataType->currentText(); + if (DataType == "Image Data") { + m_ControlInterface->SetDataType(mitk::USDiPhASDeviceCustomControls::DataType::Image_uChar); + } + else if (DataType == "Beamformed Data") { + m_ControlInterface->SetDataType(mitk::USDiPhASDeviceCustomControls::DataType::Beamformed_Short); + } +} + +//Beamforming +void QmitkUSControlsCustomDiPhASDeviceWidget::OnPitchChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetPitch(ui->PitchOfTransducer->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnReconstructedSamplesChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetReconstructedSamples(ui->ReconstructedSamplesPerLine->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnReconstructedLinesChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + m_ControlInterface->SetReconstructedLines(ui->ReconstructedLines->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnSpeedOfSoundChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + + m_ControlInterface->SetSpeedOfSound(ui->SpeedOfSound->value()); +} + +//Bandpass +void QmitkUSControlsCustomDiPhASDeviceWidget::OnBandpassEnabledChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + + if (ui->BandpassEnabled->currentText() == "On") { + m_ControlInterface->SetBandpassEnabled(true); + } + else { + m_ControlInterface->SetBandpassEnabled(false); + } +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnLowCutChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + + unsigned int Low = ui->LowCut->value(); + unsigned int High = ui->HighCut->value(); + if (Low > High) { + ui->LowCut->setValue(High); + MITK_INFO << "User tried to set LowCut>HighCut."; + } + + m_ControlInterface->SetLowCut(ui->LowCut->value()); +} +void QmitkUSControlsCustomDiPhASDeviceWidget::OnHighCutChanged() +{ + if (m_ControlInterface.IsNull()) { return; } + + unsigned int Low = ui->LowCut->value(); + unsigned int High = ui->HighCut->value(); + if (Low > High) { + ui->HighCut->setValue(Low); + MITK_INFO << "User tried to set LowCut>HighCut."; + } + + m_ControlInterface->SetHighCut(ui->HighCut->value()); +} diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h new file mode 100644 index 0000000000..de4c13f864 --- /dev/null +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h @@ -0,0 +1,112 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef QmitkUSControlsCustomDiPhASDeviceWidget_H +#define QmitkUSControlsCustomDiPhASDeviceWidget_H + +#include "QmitkUSAbstractCustomWidget.h" +#include "mitkUSDiPhASDeviceCustomControls.h" + +#include "mitkUSDevice.h" + +#include + +namespace Ui { +class QmitkUSControlsCustomDiPhASDeviceWidget; +} + +/** \brief Widget for custom controls of mitk::USDiPhASDevice. + * This class handles the itk::USDiPhASDeviceCustomControls of video device + * objects. + */ +class QmitkUSControlsCustomDiPhASDeviceWidget : public QmitkUSAbstractCustomWidget +{ + Q_OBJECT + +private slots: + virtual void OnUseBModeFilterChanged(); + virtual void OnVerticalSpacingChanged(); + virtual void OnRecordChanged(); + virtual void OnScatteringCoefficientChanged(); + virtual void OnCompensateScatteringChanged(); + + //Transmit + virtual void OnTransmitPhaseLengthChanged(); + virtual void OnExcitationFrequencyChanged(); + virtual void OnTransmitEventsChanged(); + virtual void OnVoltageChanged(); + virtual void OnModeChanged(); + + //Receive + virtual void OnScanDepthChanged(); + virtual void OnAveragingCountChanged(); + virtual void OnTGCMinChanged(); + virtual void OnTGCMaxChanged(); + virtual void OnDataTypeChanged(); + + //Beamforming + virtual void OnPitchChanged(); + virtual void OnReconstructedSamplesChanged(); + virtual void OnReconstructedLinesChanged(); + virtual void OnSpeedOfSoundChanged(); + + //Bandpass + virtual void OnBandpassEnabledChanged(); + virtual void OnLowCutChanged(); + virtual void OnHighCutChanged(); + +public: + /** + * Constructs widget object. All gui control elements will be disabled until + * QmitkUSAbstractCustomWidget::SetDevice() was called. + */ + explicit QmitkUSControlsCustomDiPhASDeviceWidget(QWidget *parent = 0); + ~QmitkUSControlsCustomDiPhASDeviceWidget(); + + /** + * Getter for the device class of mitk:USDiPhASDevice. + */ + virtual std::string GetDeviceClass() const override; + + /** + * Creates new QmitkUSAbstractCustomWidget with the same mitk::USDiPhASDevice + * and the same mitk::USDiPhASDeviceCustomControls which were set on the + * original object. + * + * This method is just for being calles by the factory. Use + * QmitkUSAbstractCustomWidget::CloneForQt() instead, if you want a clone of + * an object. + */ + virtual QmitkUSAbstractCustomWidget* Clone(QWidget* parent = 0) const override; + + /** + * Gets control interface from the device which was currently set. Control + * elements are according to current crop area of the device. If custom + * control interface is null, the control elements stay disabled. + */ + virtual void OnDeviceSet() override; + + virtual void Initialize() override; + +protected: + void BlockSignalAndSetValue(QSpinBox* target, int value); + +private: + Ui::QmitkUSControlsCustomDiPhASDeviceWidget* ui; + mitk::USDiPhASDeviceCustomControls::Pointer m_ControlInterface; +}; + +#endif // QmitkUSControlsCustomDiPhASDeviceWidget_H \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui new file mode 100644 index 0000000000..4b3fff08d5 --- /dev/null +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui @@ -0,0 +1,614 @@ + + + QmitkUSControlsCustomDiPhASDeviceWidget + + + + 0 + 0 + 259 + 903 + + + + Form + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + QFrame::WinPanel + + + QFrame::Raised + + + Started + + + Qt::AlignCenter + + + + + + + <html><head/><body><p><span style=" font-weight:600;">General Settings</span></p></body></html> + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 100 + 25 + + + + Start Recording + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Receive Parameters</span></p></body></html> + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 200 + 200 + + + + 42 + + + Qt::Horizontal + + + + + + + 42 + + + Qt::Horizontal + + + 0 + + + + + + + Scan Depth [mm] + + + + + + + 1 + + + 100 + + + 1 + + + + + + + Averaging Count + + + + + + + false + + + + Beamformed Data + + + + + Image Data + + + + + + + + 1000.000000000000000 + + + 40.000000000000000 + + + + + + + DataType + + + + + + + TGC Min + + + + + + + TGC Max + + + + + + + + + + + Compensate Fluence For Scattering + + + + + + + + + false + + + 5 + + + 25 + + + 15 + + + + + + + false + + + Avg. μs' [1/cm] + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Beamforming Parameters</span></p></body></html> + + + + + + + + + 256 + + + 4096 + + + 256 + + + 2048 + + + + + + + 0.050000000000000 + + + 0.150000000000000 + + + + + + + Qt::PreventContextMenu + + + 128 + + + 1024 + + + 128 + + + 256 + + + + + + + Samples per Line + + + + + + + Reconstructed Lines + + + + + + + 1000 + + + 1000000 + + + 1540 + + + + + + + Speed of Sound [m/s] + + + + + + + Pitch of Transducer [mm] + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Display Parameters</span></p></body></html> + + + + + + + + + Envelope Filter + + + true + + + + + + + + + 1.000000000000000 + + + 0.050000000000000 + + + 0.150000000000000 + + + + + + + Vertical Spacing + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Transmit Parameters</span></p></body></html> + + + + + + + + + 1.000000000000000 + + + 15.000000000000000 + + + 0.100000000000000 + + + 7.500000000000000 + + + + + + + 1 + + + 1 + + + + + + + Transmit Events + + + + + + + true + + + false + + + 1 + + + 1.000000000000000 + + + 10000.000000000000000 + + + 1.000000000000000 + + + + + + + Transmit Phase Length [us] + + + + + + + Excitation Frequency [MHz] + + + + + + + true + + + + Interleaved + + + + + Ultrasound only + + + + + + + + false + + + 5 + + + 75 + + + 70 + + + + + + + Voltage [V] + + + + + + + Mode + + + + + + + + + false + + + <html><head/><body><p><span style=" font-weight:600;">Bandpass Parameters</span></p></body></html> + + + + + + + + + false + + + High Cut [MHz] + + + + + + + false + + + Low Cut [MHz] + + + + + + + false + + + Bandpass Enabled + + + + + + + false + + + + + + + false + + + 5.000000000000000 + + + + + + + false + + + + Off + + + + + On + + + + + + + + + + + diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui.autosave b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui.autosave new file mode 100644 index 0000000000..02666a19c6 --- /dev/null +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui.autosave @@ -0,0 +1,527 @@ + + + QmitkUSControlsCustomDiPhASDeviceWidget + + + + 0 + 0 + 579 + 903 + + + + Form + + + + + + + + + 0 + 50 + + + + QFrame::WinPanel + + + QFrame::Raised + + + Started + + + Qt::AlignCenter + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">General Settings</span></p></body></html> + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Use BMode Envelope Filter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 100 + 50 + + + + Start Recording + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + Qt::ScrollBarAlwaysOff + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Transmit Parameters</span></p></body></html> + + + + + + + + + 15.000000000000000 + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + 1 + + + 2 + + + + + + + Transmit Events + + + + + + + 1 + + + 0.100000000000000 + + + 10000.000000000000000 + + + 1.000000000000000 + + + + + + + Transmit Phase Length [us] + + + + + + + Excitation Frequency [MHz] + + + + + + + + Interleaved + + + + + Ultrasound only + + + + + + + + 5 + + + 75 + + + 70 + + + + + + + Voltage [V] + + + + + + + Mode + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Receive Parameters</span></p></body></html> + + + + + + + + + Scan Depth [mm] + + + + + + + 1 + + + 10000 + + + 1 + + + + + + + Averaging Count + + + + + + + 42 + + + 10 + + + + + + + TimeGainCompensationMin + + + + + + + 42 + + + 24 + + + + + + + TimeGainCompensationMax + + + + + + + false + + + + Image Data + + + + + Beamformed Data + + + + + + + + DataType + + + + + + + 1000.000000000000000 + + + 50.000000000000000 + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Beamforming Parameters</span></p></body></html> + + + + + + + + + 256 + + + 4096 + + + 256 + + + 2048 + + + + + + + Pitch of Transducer [mm] + + + + + + + 128 + + + 1024 + + + 128 + + + 128 + + + + + + + Reconstructed Samples per Line + + + + + + + 0.100000000000000 + + + 0.300000000000000 + + + + + + + Speed of Sound [m/s] + + + + + + + 1000000 + + + 1540 + + + + + + + Reconstructed Lines + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Bandpass Parameters</span></p></body></html> + + + + + + + + + High Cut [MHz] + + + + + + + Low Cut [MHz] + + + + + + + Bandpass Enabled + + + + + + + + + + 5.000000000000000 + + + + + + + + Off + + + + + On + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/Modules/USUI/files.cmake b/Modules/USUI/files.cmake index d88a79270d..697d196f7f 100644 --- a/Modules/USUI/files.cmake +++ b/Modules/USUI/files.cmake @@ -1,36 +1,39 @@ set(CPP_FILES mitkUSUIActivator.cpp mitkUSUICustomWidgetFactory.cpp Qmitk/QmitkUSDeviceManagerWidget.cpp Qmitk/QmitkUSNewVideoDeviceWidget.cpp Qmitk/QmitkUSControlsBModeWidget.cpp Qmitk/QmitkUSControlsDopplerWidget.cpp Qmitk/QmitkUSControlsProbesWidget.cpp Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp + Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp Qmitk/QmitkUSAbstractCustomWidget.cpp Qmitk/QmitkComboBoxStepThrough.cpp ) set(UI_FILES Qmitk/QmitkUSDeviceManagerWidgetControls.ui Qmitk/QmitkUSNewVideoDeviceWidgetControls.ui Qmitk/QmitkUSControlsBModeWidget.ui Qmitk/QmitkUSControlsDopplerWidget.ui Qmitk/QmitkUSControlsProbesWidget.ui Qmitk/QmitkUSControlsCustomVideoDeviceWidget.ui + Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui ) set(MOC_H_FILES Qmitk/QmitkUSDeviceManagerWidget.h Qmitk/QmitkUSNewVideoDeviceWidget.h Qmitk/QmitkUSControlsBModeWidget.h Qmitk/QmitkUSControlsDopplerWidget.h Qmitk/QmitkUSControlsProbesWidget.h Qmitk/QmitkUSControlsCustomVideoDeviceWidget.h + Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h Qmitk/QmitkUSAbstractCustomWidget.h Qmitk/QmitkComboBoxStepThrough.h ) set(QRC_FILES resources/USUI.qrc ) diff --git a/Modules/USUI/mitkUSUIActivator.cpp b/Modules/USUI/mitkUSUIActivator.cpp index ca510835fd..23317bf34d 100644 --- a/Modules/USUI/mitkUSUIActivator.cpp +++ b/Modules/USUI/mitkUSUIActivator.cpp @@ -1,64 +1,79 @@ /*=================================================================== 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 "mitkUSUIActivator.h" #include "mitkUSUICustomWidgetFactory.h" #include "QmitkUSControlsCustomVideoDeviceWidget.h" +#include "QmitkUSControlsCustomDiPhASDeviceWidget.h" mitk::USUIActivator::USUIActivator() - : m_CustomWidgetFactory(0), m_CustomVideoDeviceWidget(0) + : m_CustomWidgetFactory(0), m_CustomVideoDeviceWidget(0), m_CustomDiPhASDeviceWidget(0) { } mitk::USUIActivator::~USUIActivator() { - delete m_CustomWidgetFactory; + for(auto i : m_CustomWidgetFactory) + delete i; delete m_CustomVideoDeviceWidget; if ( m_ServiceRegistration ) { m_ServiceRegistration.Unregister(); } } void mitk::USUIActivator::Load(us::ModuleContext* context) { // create a custom video device widget, which will be used as // a prototype for the custom widget factory - if ( ! m_CustomVideoDeviceWidget ) + + if (!m_CustomVideoDeviceWidget) { m_CustomVideoDeviceWidget = new QmitkUSControlsCustomVideoDeviceWidget(); } - // create a factory for custom widgets, using the video device - // widget as a prototype - if ( ! m_CustomWidgetFactory ) + // create a custom DiPhAS device widget, which will be used as + // a prototype for the custom widget factory + + if (!m_CustomDiPhASDeviceWidget) { - m_CustomWidgetFactory = new mitk::USUICustomWidgetFactory(m_CustomVideoDeviceWidget); + m_CustomDiPhASDeviceWidget = new QmitkUSControlsCustomDiPhASDeviceWidget(); } - // register the custom widget factory as a microservice - m_ServiceRegistration = m_CustomWidgetFactory->RegisterService(context); + // create a factory for custom widgets, using the video device + // widget as a prototype + m_CustomWidgetFactory.push_back(new mitk::USUICustomWidgetFactory(m_CustomVideoDeviceWidget)); + + // create a factory for custom widgets, using the DiPhAS device + // widget as a prototype + m_CustomWidgetFactory.push_back(new mitk::USUICustomWidgetFactory(m_CustomDiPhASDeviceWidget)); + + // register the custom widget factories as a microservice + for (auto i : m_CustomWidgetFactory) + m_ServiceRegistration = i->RegisterService(context); } void mitk::USUIActivator::Unload(us::ModuleContext* /*context*/) { m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; - delete m_CustomWidgetFactory; - m_CustomWidgetFactory = 0; + for (auto i : m_CustomWidgetFactory) + delete i; + + m_CustomWidgetFactory.clear(); delete m_CustomVideoDeviceWidget; m_CustomVideoDeviceWidget = 0; } diff --git a/Modules/USUI/mitkUSUIActivator.h b/Modules/USUI/mitkUSUIActivator.h index 663871d4b0..d99d46b974 100644 --- a/Modules/USUI/mitkUSUIActivator.h +++ b/Modules/USUI/mitkUSUIActivator.h @@ -1,65 +1,67 @@ /*=================================================================== 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. ===================================================================*/ #ifndef __mitkUSUIActivator_h #define __mitkUSUIActivator_h #include "QmitkUSAbstractCustomWidget.h" // Microservices #include #include class QmitkUSControlsCustomVideoDeviceWidget; +class QmitkUSControlsCustomDiPhASDeviceWidget; namespace mitk { class USUICustomWidgetFactory; /** * \brief Module activator for the USUI module. * Registers custom widget for mitk::USVideoDevice as microservice. */ class USUIActivator : public us::ModuleActivator { public: USUIActivator(); virtual ~USUIActivator(); /** * Custom video device widget is registered as a micro service on module * load. A plugin can get this widget then when using a * mitk::USVideoDevice. */ void Load(us::ModuleContext* context) override; /** * Custom video device widget is deregistered from micro service on module * unload. */ void Unload(us::ModuleContext* context) override; protected: us::ServiceRegistration m_ServiceRegistration; - USUICustomWidgetFactory* m_CustomWidgetFactory; + std::vector m_CustomWidgetFactory; QmitkUSControlsCustomVideoDeviceWidget* m_CustomVideoDeviceWidget; + QmitkUSControlsCustomDiPhASDeviceWidget* m_CustomDiPhASDeviceWidget; }; } // namespace mitk US_EXPORT_MODULE_ACTIVATOR(mitk::USUIActivator) #endif // __mitkUSUIActivator_h diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 9193ed80c3..87a1707558 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,98 +1,100 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF #org.blueberry.test:ON #org.blueberry.uitest:ON #Testing/org.blueberry.core.runtime.tests:ON #Testing/org.blueberry.osgi.tests:ON org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.simulation:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.diffusionimaging.connectomics:OFF org.mitk.gui.qt.diffusionimaging.denoising:OFF org.mitk.gui.qt.diffusionimaging.fiberfox:OFF org.mitk.gui.qt.diffusionimaging.fiberprocessing:OFF org.mitk.gui.qt.diffusionimaging.ivim:OFF org.mitk.gui.qt.diffusionimaging.odfpeaks:OFF org.mitk.gui.qt.diffusionimaging.partialvolume:OFF org.mitk.gui.qt.diffusionimaging.preprocessing:OFF org.mitk.gui.qt.diffusionimaging.reconstruction:OFF org.mitk.gui.qt.diffusionimaging.registration:OFF org.mitk.gui.qt.diffusionimaging.tbss:OFF org.mitk.gui.qt.diffusionimaging.tractography:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF + org.mitk.gui.qt.lasercontrol:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.simulation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.echotrack:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.gui.qt.multilabelsegmentation:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.algorithm.batch:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF + org.mitk.gui.qt.photoacoustics.imageprocessing:OFF org.mitk.gui.qt.cest:OFF ) diff --git a/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorViewControls.ui b/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorViewControls.ui index 65e4d0d94b..e318fbc528 100644 --- a/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorViewControls.ui +++ b/Plugins/org.mitk.gui.qt.imagenavigator/src/internal/QmitkImageNavigatorViewControls.ui @@ -1,223 +1,250 @@ QmitkImageNavigatorViewControls 0 0 - 399 + 296 440 0 0 QmitkTemplate - - - - Location (mm) + + + + + 0 + 0 + - - + + - + 0 0 - - false - - - 2 - - - -100000.000000000000000 - - - 100000.000000000000000 + + + 0 + 0 + - - + + - + 0 0 - - false - - - 2 - - - -100000.000000000000000 - - - 100000.000000000000000 - - - + + - + 0 0 - - false - - - 2 - - - -100000.000000000000000 - - - 100000.000000000000000 - 0 0 Axial - - + + - + 0 0 - - - 0 - 0 - + + Sagittal - - + + 0 0 - - Sagittal + + + 7 + + + + false + + + 2 + + + -100000.000000000000000 + + + 100000.000000000000000 - - + + + + Qt::Vertical + + + + 20 + 413 + + + + + + - + 0 0 + + Time + 0 0 Coronal - - + + - + 0 0 + + + 50 + 16777215 + + + + Loc. (mm) + - - + + 0 0 - - Time + + + 7 + + + + false + + + 2 + + + -100000.000000000000000 + + + 100000.000000000000000 - - + + - + 0 0 - - - - - - Qt::Vertical + + + 7 + - - - 20 - 413 - + + false - + + 2 + + + -100000.000000000000000 + + + 100000.000000000000000 + + QmitkSliderNavigatorWidget QWidget
QmitkSliderNavigatorWidget.h
1
QmitkDataStorageComboBox.h
diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/CMakeLists.txt b/Plugins/org.mitk.gui.qt.lasercontrol/CMakeLists.txt new file mode 100644 index 0000000000..b9d5a1cf05 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/CMakeLists.txt @@ -0,0 +1,20 @@ +project(org_mitk_gui_qt_lasercontrol) + +IF(WIN32) + configure_file( ${MITK_GALIL_API_PATH}/dll/x64/gclib.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + configure_file( ${MITK_GALIL_API_PATH}/dll/x64/gclibo.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + configure_file( ${MITK_GALIL_API_PATH}/dll/x64/gclib.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) + configure_file( ${MITK_GALIL_API_PATH}/dll/x64/gclibo.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) + configure_file( ${MITK_OPHIR_API_PATH}/Debug/OphirPyroWrapper.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + configure_file( ${MITK_OPHIR_API_PATH}/Release/OphirPyroWrapper.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) + configure_file( ${MITK_OPHIR_API_PATH}/Debug/OphirLMMeasurement.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + configure_file( ${MITK_OPHIR_API_PATH}/Release/OphirLMMeasurement.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) + configure_file( ${MITK_OPHIR_API_PATH}/Debug/Interop.OphirLMMeasurementLib.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + configure_file( ${MITK_OPHIR_API_PATH}/Release/Interop.OphirLMMeasurementLib.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) +ENDIF(WIN32) + +mitk_create_plugin( + EXPORT_DIRECTIVE LASERCONTROL_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgetsExt MitkPhotoacousticsHardware +) diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.lasercontrol/documentation/UserManual/Manual.dox new file mode 100644 index 0000000000..69fb486784 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/documentation/UserManual/Manual.dox @@ -0,0 +1,17 @@ +/** +\page org_mitk_gui_qt_lasercontrol The Lasercontrol + +\imageMacro{icon.png,"Icon of Lasercontrol",2.00} + +\tableofcontents + +\section org_mitk_gui_qt_lasercontrolOverview Overview +Describe the features of your awesome plugin here +
    +
  • Increases productivity +
  • Creates beautiful images +
  • Generates PhD thesis +
  • Brings world peace +
+ +*/ diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/documentation/UserManual/icon.xpm b/Plugins/org.mitk.gui.qt.lasercontrol/documentation/UserManual/icon.xpm new file mode 100644 index 0000000000..9057c20bc6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/documentation/UserManual/icon.xpm @@ -0,0 +1,21 @@ +/* XPM */ +static const char * icon_xpm[] = { +"16 16 2 1", +" c #FF0000", +". c #000000", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.lasercontrol/documentation/doxygen/modules.dox new file mode 100644 index 0000000000..1ecfa33fe9 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/documentation/doxygen/modules.dox @@ -0,0 +1,16 @@ +/** + \defgroup org_mitk_gui_qt_lasercontrol org.mitk.gui.qt.lasercontrol + \ingroup MITKPlugins + + \brief Describe your plugin here. + +*/ + +/** + \defgroup org_mitk_gui_qt_lasercontrol_internal Internal + \ingroup org_mitk_gui_qt_lasercontrol + + \brief This subcategory includes the internal classes of the org.mitk.gui.qt.lasercontrol plugin. Other + plugins must not rely on these classes. They contain implementation details and their interface + may change at any time. We mean it. +*/ diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/files.cmake b/Plugins/org.mitk.gui.qt.lasercontrol/files.cmake new file mode 100644 index 0000000000..55ea3038dc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/files.cmake @@ -0,0 +1,37 @@ +set(SRC_CPP_FILES + +) + +set(INTERNAL_CPP_FILES + mitkLaserControlPluginActivator.cpp + QmitkLaserControl.cpp + +) + +set(UI_FILES + src/internal/QmitkLaserControlControls.ui +) + +set(MOC_H_FILES + src/internal/mitkLaserControlPluginActivator.h + src/internal/QmitkLaserControl.h +) + +set(CACHED_RESOURCE_FILES + resources/iconLaser.xpm + plugin.xml +) + +set(QRC_FILES + +) + +set(CPP_FILES) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.lasercontrol/manifest_headers.cmake new file mode 100644 index 0000000000..a0b4a00020 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "MITK OPO Laser Control") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.gui.qt.common.legacy) diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/plugin.xml b/Plugins/org.mitk.gui.qt.lasercontrol/plugin.xml new file mode 100644 index 0000000000..8bc554dbfe --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/plugin.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaser.xpm b/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaser.xpm new file mode 100644 index 0000000000..e2c5d7c620 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaser.xpm @@ -0,0 +1,133 @@ +/* XPM */ +static char * iconLaser_xpm[] = { +"128 128 2 1", +" c None", +". c #000000", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .......... ", +" .. .......... ", +" .... .......... ", +" ....... .......... ", +" ........ .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" .......... .......... ", +" ......... .......... ", +" .......... .......... ", +" ......... .......... ", +" .......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .......... ", +" ......... .............. ", +" ......... .................. ", +" ...... .................... ", +" .... ...................... ", +" .. ........................ ", +" ........................ ", +" .......................... ", +" ............................ ", +" ............................ ", +" ............................ ", +" .............................. .................. ", +" .............................. ........................................ ", +" .............................. ........................................ ", +" .............................. ........................................ ", +" .............................. ......................................... ", +" .............................. ................................. ", +" .............................. ..... ", +" ............................ ", +" ............................ ", +" ............................ ", +" .......................... ", +" . ........................ ", +" ... ........................ ", +" ...... ...................... ", +" ........ .................... ", +" ........... .................. .. ", +" ........... .............. .... ", +" .......... .......... ....... ", +" ......... ........ ", +" ........ . ........ ", +" ..... ... ........ ", +" ... ...... ........ ", +" ... ..... ....... ", +" ..... ...... ....... ", +" ..... ..... ....... ", +" ..... ...... ....... ", +" ...... ..... ....... ", +" ..... ...... ....... ", +" ..... ..... ....... ", +" ..... ...... ....... ", +" ...... ..... ....... ", +" ..... ...... ........ ", +" ..... ..... ........ ", +" ..... ...... ........ ", +" ...... ..... ........ ", +" ..... ...... ....... ", +" ..... ..... ....... ", +" ..... ...... ....... ", +" ...... ..... ....... ", +" ..... ...... ....... ", +" ..... ..... ....... ", +" ..... ...... ....... ", +" ...... ..... ....... ", +" ..... ...... ....... ", +" ..... ..... ....... ", +" ..... ...... ........ ", +" ...... ..... ........ ", +" ..... ...... ........ ", +" ..... ...... ........ ", +" ..... ...... ........ ", +" ...... ...... ..... ", +" ..... ...... ... ", +" ..... ...... . ", +" ..... ...... ", +" ...... ..... ", +" ..... ... ", +" . ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControl.cpp b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControl.cpp new file mode 100644 index 0000000000..0100d6b356 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControl.cpp @@ -0,0 +1,368 @@ +/*=================================================================== + +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. + +===================================================================*/ + +// Blueberry +#include +#include + +// Qmitk +#include "QmitkLaserControl.h" + +// Qt +#include +#include + +const std::string OPOLaserControl::VIEW_ID = "org.mitk.views.lasercontrol"; + +void OPOLaserControl::SetFocus() +{ +} + +void OPOLaserControl::CreateQtPartControl(QWidget *parent) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi(parent); + connect(m_Controls.buttonInitLaser, SIGNAL(clicked()), this, SLOT(InitLaser())); + connect(m_Controls.buttonTune, SIGNAL(clicked()), this, SLOT(TuneWavelength())); + connect(m_Controls.buttonFastTuning, SIGNAL(clicked()), this, SLOT(StartFastTuning())); + connect(m_Controls.buttonFlashlamp, SIGNAL(clicked()), this, SLOT(ToggleFlashlamp())); + connect(m_Controls.buttonQSwitch, SIGNAL(clicked()), this, SLOT(ToggleQSwitch())); + connect(m_Controls.sliderWavelength, SIGNAL(valueChanged(int)), this, SLOT(SyncWavelengthSetBySlider())); + connect(m_Controls.spinBoxWavelength, SIGNAL(valueChanged(double)), this, SLOT(SyncWavelengthSetBySpinBox())); + connect(&m_ShutterWatcher, SIGNAL(finished()), this, SLOT(EnableLaser())); + + m_SyncFromSpinBox = true; + m_SyncFromSlider = true; + + m_PumpLaserConnected = false; + m_OPOConnected = false; + m_PyroConnected = false; +} + +void OPOLaserControl::EnableLaser() +{ + m_Controls.buttonQSwitch->setEnabled(true); + m_Controls.buttonQSwitch->setText("Start Laser"); + this->GetState(); +} + +void OPOLaserControl::SyncWavelengthSetBySlider() +{ + if (m_SyncFromSlider) + { + m_SyncFromSpinBox = false; + m_Controls.spinBoxWavelength->setValue(m_Controls.sliderWavelength->value() / 10); + } + else + m_SyncFromSlider = true; +} + +void OPOLaserControl::SyncWavelengthSetBySpinBox() +{ + if (m_SyncFromSpinBox) + { + m_SyncFromSlider = false; + m_Controls.sliderWavelength->setValue(m_Controls.spinBoxWavelength->value() * 10); + } + else + m_SyncFromSpinBox = true; +} + +void OPOLaserControl::InitLaser() +{ + m_Controls.buttonInitLaser->setEnabled(false); + m_Controls.buttonInitLaser->setText("working ..."); + + if (!m_PumpLaserConnected) + { + m_PumpLaserController = mitk::QuantelLaser::New(); + + if (m_PumpLaserController->OpenConnection("OpotekPhocusMobile")) + { + m_Controls.buttonFlashlamp->setEnabled(true); + m_Controls.buttonQSwitch->setEnabled(false); + m_Controls.buttonInitLaser->setText("Reset and Release Laser"); + + std::string answer(""); + std::string triggerCommand("TRIG "); + if (m_Controls.checkBoxTriggerExternally->isChecked()) + { + triggerCommand.append("EE"); // set both Triggers external + m_PumpLaserController->SendAndReceiveLine(&triggerCommand, &answer); + MITK_INFO << answer; + } + else + { + triggerCommand.append("II"); // set both Triggers internal + m_PumpLaserController->SendAndReceiveLine(&triggerCommand, &answer); + MITK_INFO << answer; + std::string energyCommand("QDLY 30"); + m_PumpLaserController->SendAndReceiveLine(&energyCommand, &answer); + MITK_INFO << answer; + } + + m_PumpLaserConnected = true; + this->GetState(); + } + else + { + QMessageBox::warning(NULL, "Laser Control", "Opotek Pump Laser Initialization Failed."); + m_Controls.buttonInitLaser->setText("Init Laser"); + m_Controls.buttonInitLaser->setEnabled(true); + return; + } + } + else + { + // destroy and free + if (m_PumpLaserController->CloseConnection()) + { + m_Controls.buttonFlashlamp->setEnabled(false); + m_Controls.buttonQSwitch->setEnabled(false); + m_Controls.buttonInitLaser->setText("Init Laser"); + m_PumpLaserConnected = false; + } + else + { + QMessageBox::warning(NULL, "Laser Control", "Opotek Pump Laser Release Failed."); + m_Controls.buttonInitLaser->setText("Reset and Release Laser"); + } + } + + if (!m_OPOConnected) + { + m_OPOMotor = mitk::GalilMotor::New(); + if (m_OPOMotor->OpenConnection("OpotekPhocusMobile")) + { + m_Controls.buttonTune->setEnabled(true); + m_Controls.buttonFastTuning->setEnabled(true); + m_Controls.sliderWavelength->setMinimum(m_OPOMotor->GetMinWavelength() * 10); + m_Controls.sliderWavelength->setMaximum(m_OPOMotor->GetMaxWavelength() * 10); + m_Controls.spinBoxWavelength->setMinimum(m_OPOMotor->GetMinWavelength()); + m_Controls.spinBoxWavelength->setMaximum(m_OPOMotor->GetMaxWavelength()); + m_Controls.sliderWavelength->setValue(m_OPOMotor->GetCurrentWavelength() * 10); + m_Controls.spinBoxWavelength->setValue(m_OPOMotor->GetCurrentWavelength()); + m_OPOConnected = true; // not always right FIXME + } + else + { + QMessageBox::warning(NULL, "Laser Control", "OPO Initialization Failed."); + m_Controls.buttonInitLaser->setText("Init Laser"); + } + } + else + { + // destroy and free + if (m_OPOMotor->CloseConnection()) + { + m_Controls.buttonTune->setEnabled(false); + m_Controls.buttonFastTuning->setEnabled(false); + m_Controls.buttonInitLaser->setText("Init Laser"); + m_OPOConnected = false; + } + else + { + QMessageBox::warning(NULL, "Laser Control", "OPO Release Failed."); + m_Controls.buttonInitLaser->setText("Reset and Release Laser"); + } + } + m_Controls.buttonInitLaser->setEnabled(true); + this->GetState(); + /* + try + { + if (!m_PyroConnected) + { + m_Pyro = mitk::OphirPyro::New(); + MITK_INFO << "[Pyro Debug] OpenConnection: " << m_Pyro->OpenConnection(); + MITK_INFO << "[Pyro Debug] StartDataAcquisition: " << m_Pyro->StartDataAcquisition(); + m_CurrentPulseEnergy = 0; + m_PyroConnected = true; + //QFuture future = QtConcurrent::run(this, &OPOLaserControl::ShowEnergy); + //m_EnergyWatcher.setFuture(future); + } + else + { + m_PyroConnected = false; + } + } catch (...) { + MITK_INFO << " While trying to connect to the Pyro an exception was caught (this almost always happens on the first try after reboot - try again!)"; + m_PyroConnected = false; + }*/ +} + +void OPOLaserControl::TuneWavelength() +{ + if (m_Controls.checkBoxCalibration->isChecked()) + { + m_OPOMotor->TuneToWavelength(m_Controls.spinBoxPosition->value(), true); + } + else + { + m_OPOMotor->TuneToWavelength(m_Controls.spinBoxWavelength->value(), false); + } + QString wavelengthText = QString::number(m_OPOMotor->GetCurrentWavelength()); + wavelengthText.append("nm"); + m_Controls.labelWavelength->setText(wavelengthText); +} + +void OPOLaserControl::StartFastTuning() +{ + std::vector listOfWavelengths; + double tmpWavelength = 0; + int currentRow = 0; + bool success = false; + + do + { + if (currentRow != 0) listOfWavelengths.push_back(tmpWavelength); + if (m_Controls.tableFastTuningWavelengths->item(0, currentRow)) + { + QString test = m_Controls.tableFastTuningWavelengths->item(0, currentRow)->text(); + tmpWavelength = test.toDouble(&success); + currentRow++; + } + else + tmpWavelength = 0; + + if (success == 0) + tmpWavelength = 0; + } while (tmpWavelength<950.1 && tmpWavelength>689.9); + + m_OPOMotor->FastTuneWavelengths(listOfWavelengths); +} + +void OPOLaserControl::ShutterCountDown() +{ + m_Controls.buttonFlashlamp->setText("Stop Lamp"); + m_Controls.buttonQSwitch->setEnabled(false); + m_Controls.buttonQSwitch->setText("10s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + m_Controls.buttonQSwitch->setText("9s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + m_Controls.buttonQSwitch->setText("8s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + m_Controls.buttonQSwitch->setText("7s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + m_Controls.buttonQSwitch->setText("6s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + m_Controls.buttonQSwitch->setText("5s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + m_Controls.buttonQSwitch->setText("4s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + m_Controls.buttonQSwitch->setText("3s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + m_Controls.buttonQSwitch->setText("2s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + m_Controls.buttonQSwitch->setText("1s ..."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + return; +} + +void OPOLaserControl::ShowEnergy() +{ + /*forever + { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + MITK_INFO << "[Pyro Debug] ShowEnergy()"; + if (!m_PyroConnected) + { + MITK_INFO << "[Pyro Debug] StopDataAcquisition: " << m_Pyro->StopDataAcquisition(); + MITK_INFO << "[Pyro Debug] CloseConnection: " << m_Pyro->CloseConnection(); + m_CurrentPulseEnergy = 0; + return; + } + // m_Pyro->GetDataFromSensor(); + m_CurrentPulseEnergy = 60000 * m_Pyro->LookupCurrentPulseEnergy(); + m_Controls.labelEnergy->setText(std::to_string(m_CurrentPulseEnergy).append(" mJ").c_str()); + }*/ +} + +void OPOLaserControl::ToggleFlashlamp() +{ + m_Controls.buttonFlashlamp->setText("..."); + if (!m_PumpLaserController->IsFlashing()) + { + if (m_PumpLaserController->StartFlashing()) + { + QFuture future = QtConcurrent::run(this, &OPOLaserControl::ShutterCountDown); + m_ShutterWatcher.setFuture(future); + } + else + m_Controls.buttonFlashlamp->setText("Start Lamp"); + } + else + { + if (m_PumpLaserController->StopFlashing()) + { + m_Controls.buttonFlashlamp->setText("Start Lamp"); + m_Controls.buttonQSwitch->setText("Start Laser"); + m_Controls.buttonQSwitch->setEnabled(false); + } + else + m_Controls.buttonFlashlamp->setText("Stop Lamp"); + } + this->GetState(); +} + +void OPOLaserControl::ToggleQSwitch() +{ + m_Controls.buttonQSwitch->setText("..."); + if (!m_PumpLaserController->IsEmitting()) + { + if (m_PumpLaserController->StartQswitching()) + m_Controls.buttonQSwitch->setText("Stop Laser"); + else + m_Controls.buttonQSwitch->setText("Start Laser"); + } + else + { + if (m_PumpLaserController->StopQswitching()) + m_Controls.buttonQSwitch->setText("Start Laser"); + else + m_Controls.buttonQSwitch->setText("Stop Laser"); + } + this->GetState(); +} + +void OPOLaserControl::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, + const QList& nodes) +{ +} + +void OPOLaserControl::GetState() +{ + mitk::QuantelLaser::LaserState pumpLaserState = m_PumpLaserController->GetState(); + + if (pumpLaserState == mitk::QuantelLaser::STATE0) + m_Controls.labelStatus->setText("PL0: Boot Fault."); + else if (pumpLaserState == mitk::QuantelLaser::STATE1) + m_Controls.labelStatus->setText("PL1: Warm Up."); + else if (pumpLaserState == mitk::QuantelLaser::STATE2) + m_Controls.labelStatus->setText("PL2: Laser Ready."); + else if (pumpLaserState == mitk::QuantelLaser::STATE3) + m_Controls.labelStatus->setText("PL3: Flashing. Pulse Disabled."); + else if (pumpLaserState == mitk::QuantelLaser::STATE4) + m_Controls.labelStatus->setText("PL4: Flashing. Shutter Closed."); + else if (pumpLaserState == mitk::QuantelLaser::STATE5) + m_Controls.labelStatus->setText("PL5: Flashing. Shutter Open."); + else if (pumpLaserState == mitk::QuantelLaser::STATE6) + m_Controls.labelStatus->setText("PL6: Flashing. Pulse Enabled."); + else if (pumpLaserState == mitk::QuantelLaser::STATE7) + m_Controls.labelStatus->setText("PL7: Undefined State."); + else if (pumpLaserState == mitk::QuantelLaser::UNCONNECTED) + m_Controls.labelStatus->setText("PL Not Connected."); +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControl.h b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControl.h new file mode 100644 index 0000000000..abf6c1f227 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControl.h @@ -0,0 +1,100 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +#ifndef OPOLaserControl_h +#define OPOLaserControl_h + +#include + +#include + +#include "ui_QmitkLaserControlControls.h" + +#include +#include + +// Photoacoustics Hardware +#include +#include +//#include + +#include + +/** + \brief OPOLaserControl + + \warning This class is not yet documented. Use "git blame" and ask the author why he is a lazy fuck. + + \sa QmitkAbstractView + \ingroup ${plugin_target}_internal +*/ +class OPOLaserControl : public QmitkAbstractView +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + protected slots: + + /// \brief Called when the user clicks the GUI button + void GetState(); + + void InitLaser(); + void TuneWavelength(); + void StartFastTuning(); + + void ShutterCountDown(); + void EnableLaser(); + void ShowEnergy(); + + void ToggleFlashlamp(); + void ToggleQSwitch(); + void SyncWavelengthSetBySlider(); + void SyncWavelengthSetBySpinBox(); + + protected: + + virtual void CreateQtPartControl(QWidget *parent) override; + + virtual void SetFocus() override; + + /// \brief called by QmitkFunctionality when DataManager's selection has changed + virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, + const QList& nodes ) override; + + Ui::OPOLaserControlControls m_Controls; + bool m_PumpLaserConnected; + bool m_OPOConnected; + bool m_PyroConnected; + bool m_SyncFromSpinBox; + bool m_SyncFromSlider; + double m_CurrentPulseEnergy; + + QFutureWatcher m_ShutterWatcher; + QFutureWatcher m_EnergyWatcher; + + mitk::QuantelLaser::Pointer m_PumpLaserController; + mitk::GalilMotor::Pointer m_OPOMotor; + //mitk::OphirPyro::Pointer m_Pyro; + +}; + +#endif // OPOLaserControl_h diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControlControls.ui b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControlControls.ui new file mode 100644 index 0000000000..903c570711 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControlControls.ui @@ -0,0 +1,726 @@ + + + OPOLaserControlControls + + + + 0 + 0 + 309 + 433 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + + + OPOTEK Phocus Control + + + + + 10 + 20 + 271 + 332 + + + + + + + true + + + Trigger Externally + + + true + + + + + + + Init Laser + + + + + + + + + false + + + Start Lamp + + + + + + + false + + + Start Laser + + + + + + + + + + 9 + 75 + true + + + + Laser Status + + + + + + + + + Current Wavelength + + + + + + + + 9 + 75 + true + PreferDefault + true + + + + 750.0 nm + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Pulse Energy + + + + + + + + 9 + 75 + true + PreferDefault + true + + + + 0 mJ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + 6900 + + + 9500 + + + 5 + + + 100 + + + 7500 + + + Qt::Horizontal + + + QSlider::NoTicks + + + 10000 + + + + + + + + + 1 + + + 690.000000000000000 + + + 950.000000000000000 + + + 0.500000000000000 + + + 750.000000000000000 + + + + + + + nm + + + + + + + false + + + Tune + + + + + + + + + + 8 + 50 + false + + + + Fast Tuning Wavelengths + + + + + + + + 16777215 + 62 + + + + true + + + Qt::SolidLine + + + 42 + + + 50 + + + 20 + + + 20 + + + + λ/nm + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + 18 + + + + + 19 + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + 24 + + + + + 25 + + + + + 26 + + + + + 27 + + + + + 28 + + + + + 29 + + + + + 30 + + + + + 31 + + + + + 32 + + + + + 33 + + + + + 34 + + + + + 35 + + + + + 36 + + + + + 37 + + + + + 38 + + + + + 39 + + + + + 40 + + + + + 690 + + + + + 690 + + + + + 690 + + + + + 690 + + + + + 690 + + + + + 800 + + + + + 800 + + + + + 800 + + + + + 800 + + + + + 800 + + + + + 800 + + + + + 800 + + + + + 800 + + + + + 800 + + + + + 800 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + Start Fast Tuning + + + + + + + + + 10 + 350 + 191 + 31 + + + + + + + calibrate OPO + + + + + + + 50000 + + + 400 + + + 24400 + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/mitkLaserControlPluginActivator.cpp b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/mitkLaserControlPluginActivator.cpp new file mode 100644 index 0000000000..3b5a2c05f5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/mitkLaserControlPluginActivator.cpp @@ -0,0 +1,33 @@ +/*=================================================================== + +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 "mitkLaserControlPluginActivator.h" +#include "QmitkLaserControl.h" + +namespace mitk { + +void org_mitk_gui_qt_lasercontrol_Activator::start(ctkPluginContext* context) +{ + BERRY_REGISTER_EXTENSION_CLASS(OPOLaserControl, context) +} + +void org_mitk_gui_qt_lasercontrol_Activator::stop(ctkPluginContext* context) +{ + Q_UNUSED(context) +} + +} diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/mitkLaserControlPluginActivator.h b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/mitkLaserControlPluginActivator.h new file mode 100644 index 0000000000..65875a7f75 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/mitkLaserControlPluginActivator.h @@ -0,0 +1,41 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +#ifndef org_mitk_gui_qt_lasercontrol_Activator_h +#define org_mitk_gui_qt_lasercontrol_Activator_h + +#include + +namespace mitk { + +class org_mitk_gui_qt_lasercontrol_Activator : + public QObject, public ctkPluginActivator +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_lasercontrol") + Q_INTERFACES(ctkPluginActivator) + +public: + + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + +}; // org_mitk_gui_qt_lasercontrol_Activator + +} + +#endif // org_mitk_gui_qt_lasercontrol_Activator_h diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/CMakeLists.txt b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/CMakeLists.txt new file mode 100644 index 0000000000..ce750d05d7 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_photoacoustics_imageprocessing) + +mitk_create_plugin( + EXPORT_DIRECTIVE IMAGEPROCESSING_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgetsExt MitkPhotoacousticsAlgorithms +) diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/Manual.dox new file mode 100644 index 0000000000..d96263f413 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/Manual.dox @@ -0,0 +1,17 @@ +/** +\page org_mitk_gui_qt_photoacoustics_imageprocessing The Imageprocessing + +\imageMacro{icon.png,"Icon of Imageprocessing",2.00} + +\tableofcontents + +\section org_mitk_gui_qt_photoacoustics_imageprocessingOverview Overview +Describe the features of your awesome plugin here +
    +
  • Increases productivity +
  • Creates beautiful images +
  • Generates PhD thesis +
  • Brings world peace +
+ +*/ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/icon.xpm b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/icon.xpm new file mode 100644 index 0000000000..9057c20bc6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/UserManual/icon.xpm @@ -0,0 +1,21 @@ +/* XPM */ +static const char * icon_xpm[] = { +"16 16 2 1", +" c #FF0000", +". c #000000", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/doxygen/modules.dox new file mode 100644 index 0000000000..5bd6326234 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/documentation/doxygen/modules.dox @@ -0,0 +1,16 @@ +/** + \defgroup org_mitk_gui_qt_photoacoustics_imageprocessing org.mitk.gui.qt.photoacoustics.imageprocessing + \ingroup MITKPlugins + + \brief Describe your plugin here. + +*/ + +/** + \defgroup org_mitk_gui_qt_photoacoustics_imageprocessing_internal Internal + \ingroup org_mitk_gui_qt_photoacoustics_imageprocessing + + \brief This subcategory includes the internal classes of the org.mitk.gui.qt.photoacoustics.imageprocessing plugin. Other + plugins must not rely on these classes. They contain implementation details and their interface + may change at any time. We mean it. +*/ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/files.cmake b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/files.cmake new file mode 100644 index 0000000000..e4fe8ebf7d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/files.cmake @@ -0,0 +1,37 @@ +set(SRC_CPP_FILES + +) + +set(INTERNAL_CPP_FILES + org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.cpp + PAImageProcessing.cpp +) + +set(UI_FILES + src/internal/PAImageProcessingControls.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h + src/internal/PAImageProcessing.h +) + +set(CACHED_RESOURCE_FILES + resources/pai.svg + resources/photoacousticsIcon.png + plugin.xml +) + +set(QRC_FILES + +) + +set(CPP_FILES ) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/manifest_headers.cmake new file mode 100644 index 0000000000..948e85963d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "Imageprocessing") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ") +set(Plugin-ContactAddress "") +set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/plugin.xml b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/plugin.xml new file mode 100644 index 0000000000..a1de5fb967 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/plugin.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg new file mode 100644 index 0000000000..96fe24a43e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg @@ -0,0 +1,24 @@ + +image/svg+xml \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/photoacousticsIcon.png b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/photoacousticsIcon.png new file mode 100644 index 0000000000..7846083408 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/photoacousticsIcon.png differ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp new file mode 100644 index 0000000000..86b2a9703f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp @@ -0,0 +1,1076 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +// Blueberry +#include +#include + +// Qmitk +#include "PAImageProcessing.h" + +// Qt +#include +#include +#include +#include + +//mitk image +#include +#include "mitkPhotoacousticImage.h" +#include "mitkPhotoacousticBeamformingFilter.h" + +//other +#include +#include +#include + +const std::string PAImageProcessing::VIEW_ID = "org.mitk.views.paimageprocessing"; + +PAImageProcessing::PAImageProcessing() : m_ResampleSpacing(0), m_UseLogfilter(false) +{ + qRegisterMetaType(); + qRegisterMetaType(); +} + +void PAImageProcessing::SetFocus() +{ + m_Controls.buttonApplyBModeFilter->setFocus(); +} + +void PAImageProcessing::CreateQtPartControl(QWidget *parent) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi(parent); + connect(m_Controls.buttonApplyBModeFilter, SIGNAL(clicked()), this, SLOT(StartBmodeThread())); + connect(m_Controls.DoResampling, SIGNAL(clicked()), this, SLOT(UseResampling())); + connect(m_Controls.Logfilter, SIGNAL(clicked()), this, SLOT(UseLogfilter())); + connect(m_Controls.ResamplingValue, SIGNAL(valueChanged(double)), this, SLOT(SetResampling())); + connect(m_Controls.buttonApplyBeamforming, SIGNAL(clicked()), this, SLOT(StartBeamformingThread())); + connect(m_Controls.buttonApplyCropFilter, SIGNAL(clicked()), this, SLOT(StartCropThread())); + connect(m_Controls.buttonApplyBandpass, SIGNAL(clicked()), this, SLOT(StartBandpassThread())); + connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UseImageSpacing())); + connect(m_Controls.ScanDepth, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); + connect(m_Controls.SpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); + connect(m_Controls.Samples, SIGNAL(valueChanged(int)), this, SLOT(UpdateImageInfo())); + connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UpdateImageInfo())); + connect(m_Controls.boundLow, SIGNAL(valueChanged(int)), this, SLOT(UpdateBounds())); + connect(m_Controls.boundHigh, SIGNAL(valueChanged(int)), this, SLOT(UpdateBounds())); + connect(m_Controls.Partial, SIGNAL(clicked()), this, SLOT(UpdateBounds())); + connect(m_Controls.BatchProcessing, SIGNAL(clicked()), this, SLOT(BatchProcessing())); + connect(m_Controls.StepBeamforming, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); + connect(m_Controls.StepCropping, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); + connect(m_Controls.StepBandpass, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); + connect(m_Controls.StepBMode, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); + + UpdateSaveBoxes(); + m_Controls.DoResampling->setChecked(false); + m_Controls.ResamplingValue->setEnabled(false); + m_Controls.progressBar->setMinimum(0); + m_Controls.progressBar->setMaximum(100); + m_Controls.progressBar->setVisible(false); + m_Controls.UseImageSpacing->setToolTip("Image spacing of y-Axis must be in us, x-Axis in mm."); + m_Controls.UseImageSpacing->setToolTipDuration(5000); + m_Controls.ProgressInfo->setVisible(false); + m_Controls.UseBP->hide(); + + UseImageSpacing(); +} + +std::vector splitpath( + const std::string& str + , const std::set delimiters) +{ + std::vector result; + + char const* pch = str.c_str(); + char const* start = pch; + for (; *pch; ++pch) + { + if (delimiters.find(*pch) != delimiters.end()) + { + if (start != pch) + { + std::string str(start, pch); + result.push_back(str); + } + else + { + result.push_back(""); + } + start = pch + 1; + } + } + result.push_back(start); + + return result; +} + +void PAImageProcessing::UpdateSaveBoxes() +{ + if (m_Controls.StepBeamforming->isChecked()) + m_Controls.SaveBeamforming->setEnabled(true); + else + m_Controls.SaveBeamforming->setEnabled(false); + + if (m_Controls.StepCropping->isChecked()) + m_Controls.SaveCropping->setEnabled(true); + else + m_Controls.SaveCropping->setEnabled(false); + + if (m_Controls.StepBandpass->isChecked()) + m_Controls.SaveBandpass->setEnabled(true); + else + m_Controls.SaveBandpass->setEnabled(false); + + if (m_Controls.StepBMode->isChecked()) + m_Controls.SaveBMode->setEnabled(true); + else + m_Controls.SaveBMode->setEnabled(false); +} + +void PAImageProcessing::BatchProcessing() +{ + QFileDialog LoadDialog(nullptr, "Select Files to be processed"); + LoadDialog.setFileMode(QFileDialog::FileMode::ExistingFiles); + LoadDialog.setNameFilter(tr("Images (*.nrrd)")); + LoadDialog.setViewMode(QFileDialog::Detail); + + QStringList fileNames; + if (LoadDialog.exec()) + fileNames = LoadDialog.selectedFiles(); + + QString saveDir = QFileDialog::getExistingDirectory(nullptr, tr("Select Directory To Save To"), + "", + QFileDialog::ShowDirsOnly + | QFileDialog::DontResolveSymlinks); + + DisableControls(); + + std::set delims{ '/', '.'}; + + mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); + + bool doSteps[] = { m_Controls.StepBeamforming->isChecked(), m_Controls.StepCropping->isChecked() , m_Controls.StepBandpass->isChecked(), m_Controls.StepBMode->isChecked() }; + bool saveSteps[] = { m_Controls.SaveBeamforming->isChecked(), m_Controls.SaveCropping->isChecked() , m_Controls.SaveBandpass->isChecked(), m_Controls.SaveBMode->isChecked() }; + + for (int fileNumber = 0; fileNumber < fileNames.size(); ++fileNumber) + { + m_Controls.progressBar->setValue(0); + m_Controls.progressBar->setVisible(true); + m_Controls.ProgressInfo->setVisible(true); + m_Controls.ProgressInfo->setText("loading file"); + + QString filename = fileNames.at(fileNumber); + auto split = splitpath(filename.toStdString(), delims); + std::string imageName = split.at(split.size()-2); + mitk::Image::Pointer image = mitk::IOUtil::LoadImage(filename.toStdString().c_str()); + + UpdateBFSettings(image); + // Beamforming + if (doSteps[0]) + { + std::function progressHandle = [this](int progress, std::string progressInfo) { + this->UpdateProgress(progress, progressInfo); + }; + m_Controls.progressBar->setValue(100); + + image = filterbank->ApplyBeamforming(image, BFconfig, m_Controls.Cutoff->value(), progressHandle); + + if (saveSteps[0]) + { + std::string saveFileName = saveDir.toStdString() + "/" + imageName + " beamformed" + ".nrrd"; + mitk::IOUtil::Save(image, saveFileName); + } + } + + // Cropping + if (doSteps[1]) + { + m_Controls.ProgressInfo->setText("cropping image"); + + image = filterbank->ApplyCropping(image, m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, 0, 0, image->GetDimension(2) - 1); + + if (saveSteps[1]) + { + std::string saveFileName = saveDir.toStdString() + "/" + imageName + " cropped" + ".nrrd"; + mitk::IOUtil::Save(image, saveFileName); + } + } + + // Bandpass + if (doSteps[2]) + { + m_Controls.ProgressInfo->setText("applying bandpass"); + float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / m_Controls.BPSpeedOfSound->value(); + // add a safeguard so the program does not chrash when applying a Bandpass that reaches out of the bounds of the image + float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; + float BPHighPass = 1000000 * m_Controls.BPhigh->value(); // [Hz] + float BPLowPass = maxFrequency - 1000000 * m_Controls.BPlow->value(); // [Hz] + + if (BPLowPass > maxFrequency && m_Controls.UseBP->isChecked()) + { + QMessageBox Msgbox; + Msgbox.setText("LowPass too low, disabled it."); + Msgbox.exec(); + + BPLowPass = 0; + } + if (BPLowPass < 0 && m_Controls.UseBP->isChecked()) + { + QMessageBox Msgbox; + Msgbox.setText("LowPass too high, disabled it."); + Msgbox.exec(); + + BPLowPass = 0; + } + if (BPHighPass > maxFrequency && m_Controls.UseBP->isChecked()) + { + QMessageBox Msgbox; + Msgbox.setText("HighPass too high, disabled it."); + Msgbox.exec(); + + BPHighPass = 0; + } + if (BPHighPass > maxFrequency - BFconfig.BPLowPass) + { + QMessageBox Msgbox; + Msgbox.setText("HighPass higher than LowPass, disabled both."); + Msgbox.exec(); + + BPHighPass = 0; + BPLowPass = 0; + } + + image = filterbank->BandpassFilter(image, recordTime, BPHighPass, BPLowPass, m_Controls.BPFalloff->value()); + + if (saveSteps[2]) + { + std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bandpassed" + ".nrrd"; + mitk::IOUtil::Save(image, saveFileName); + } + } + // Bmode + if (doSteps[3]) + { + m_Controls.ProgressInfo->setText("applying bmode filter"); + + if (m_Controls.BModeMethod->currentText() == "Simple Abs Filter") + image = filterbank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::Abs, m_UseLogfilter, m_ResampleSpacing); + else if (m_Controls.BModeMethod->currentText() == "Shape Detection") + image = filterbank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::ShapeDetection, m_UseLogfilter, m_ResampleSpacing); + if (saveSteps[3]) + { + std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bmode" + ".nrrd"; + mitk::IOUtil::Save(image, saveFileName); + } + } + m_Controls.progressBar->setVisible(false); + } + + EnableControls(); +} + +void PAImageProcessing::StartBeamformingThread() +{ + QList nodes = this->GetDataManagerSelection(); + if (nodes.empty()) return; + + mitk::DataStorage::Pointer storage = this->GetDataStorage(); + + mitk::DataNode::Pointer node = nodes.front(); + + if (!node) + { + // Nothing selected. Inform the user and return + QMessageBox::information(NULL, "Template", "Please load and select an image before starting image processing."); + return; + } + + mitk::BaseData* data = node->GetData(); + if (data) + { + // test if this data item is an image or not (could also be a surface or something totally different) + mitk::Image* image = dynamic_cast(data); + if (image) + { + UpdateBFSettings(image); + std::stringstream message; + std::string name; + message << "Performing beamforming for image "; + if (node->GetName(name)) + { + // a property called "name" was found for this DataNode + message << "'" << name << "'"; + m_OldNodeName = name; + } + else + m_OldNodeName = " "; + + message << "."; + MITK_INFO << message.str(); + + m_Controls.progressBar->setValue(0); + m_Controls.progressBar->setVisible(true); + m_Controls.ProgressInfo->setVisible(true); + m_Controls.ProgressInfo->setText("started"); + m_Controls.buttonApplyBeamforming->setText("working..."); + DisableControls(); + + BeamformingThread *thread = new BeamformingThread(); + connect(thread, &BeamformingThread::result, this, &PAImageProcessing::HandleBeamformingResults); + connect(thread, &BeamformingThread::updateProgress, this, &PAImageProcessing::UpdateProgress); + connect(thread, &BeamformingThread::finished, thread, &QObject::deleteLater); + + thread->setConfig(BFconfig); + thread->setCutoff(m_Controls.Cutoff->value()); + thread->setInputImage(image); + + MITK_INFO << "Started new thread for Beamforming"; + thread->start(); + } + } +} + +void PAImageProcessing::HandleBeamformingResults(mitk::Image::Pointer image) +{ + auto newNode = mitk::DataNode::New(); + newNode->SetData(image); + + // name the new Data node + std::stringstream newNodeName; + + newNodeName << m_OldNodeName << " "; + + if (BFconfig.Algorithm == mitk::BeamformingFilter::beamformingSettings::BeamformingAlgorithm::DAS) + newNodeName << "DAS bf, "; + else if (BFconfig.Algorithm == mitk::BeamformingFilter::beamformingSettings::BeamformingAlgorithm::DMAS) + newNodeName << "DMAS bf, "; + + if (BFconfig.DelayCalculationMethod == mitk::BeamformingFilter::beamformingSettings::DelayCalc::QuadApprox) + newNodeName << "q. delay"; + if (BFconfig.DelayCalculationMethod == mitk::BeamformingFilter::beamformingSettings::DelayCalc::Spherical) + newNodeName << "s. delay"; + + newNode->SetName(newNodeName.str()); + + // update level window for the current dynamic range + mitk::LevelWindow levelWindow; + newNode->GetLevelWindow(levelWindow); + auto data = newNode->GetData(); + levelWindow.SetAuto(dynamic_cast(data), true, true); + newNode->SetLevelWindow(levelWindow); + + // add new node to data storage + this->GetDataStorage()->Add(newNode); + + // disable progress bar + m_Controls.progressBar->setVisible(false); + m_Controls.ProgressInfo->setVisible(false); + m_Controls.buttonApplyBeamforming->setText("Apply Beamforming"); + EnableControls(); + + // update rendering + mitk::RenderingManager::GetInstance()->InitializeViews( + dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void PAImageProcessing::StartBmodeThread() +{ + QList nodes = this->GetDataManagerSelection(); + if (nodes.empty()) return; + + mitk::DataStorage::Pointer storage = this->GetDataStorage(); + + mitk::DataNode::Pointer node = nodes.front(); + + if (!node) + { + // Nothing selected. Inform the user and return + QMessageBox::information(NULL, "Template", "Please load and select an image before starting image processing."); + return; + } + + mitk::BaseData* data = node->GetData(); + if (data) + { + // test if this data item is an image or not (could also be a surface or something totally different) + mitk::Image* image = dynamic_cast(data); + if (image) + { + UpdateBFSettings(image); + std::stringstream message; + std::string name; + message << "Performing image processing for image "; + if (node->GetName(name)) + { + // a property called "name" was found for this DataNode + message << "'" << name << "'"; + m_OldNodeName = name; + } + else + m_OldNodeName = " "; + + message << "."; + MITK_INFO << message.str(); + + m_Controls.buttonApplyBModeFilter->setText("working..."); + DisableControls(); + + BmodeThread *thread = new BmodeThread(); + connect(thread, &BmodeThread::result, this, &PAImageProcessing::HandleBmodeResults); + connect(thread, &BmodeThread::finished, thread, &QObject::deleteLater); + + if(m_Controls.BModeMethod->currentText() == "Simple Abs Filter") + thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::Abs); + else if(m_Controls.BModeMethod->currentText() == "Shape Detection") + thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::ShapeDetection); + + thread->setInputImage(image); + + MITK_INFO << "Started new thread for Image Processing"; + thread->start(); + } + } +} + +void PAImageProcessing::HandleBmodeResults(mitk::Image::Pointer image) +{ + auto newNode = mitk::DataNode::New(); + newNode->SetData(image); + + // name the new Data node + std::stringstream newNodeName; + newNodeName << m_OldNodeName << " "; + newNodeName << "B-Mode"; + + newNode->SetName(newNodeName.str()); + + // update level window for the current dynamic range + mitk::LevelWindow levelWindow; + newNode->GetLevelWindow(levelWindow); + auto data = newNode->GetData(); + levelWindow.SetAuto(dynamic_cast(data), true, true); + newNode->SetLevelWindow(levelWindow); + + // add new node to data storage + this->GetDataStorage()->Add(newNode); + + // disable progress bar + m_Controls.progressBar->setVisible(false); + m_Controls.buttonApplyBModeFilter->setText("Apply B-mode Filter"); + EnableControls(); + + // update rendering + mitk::RenderingManager::GetInstance()->InitializeViews( + dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void PAImageProcessing::StartCropThread() +{ + QList nodes = this->GetDataManagerSelection(); + if (nodes.empty()) return; + + mitk::DataStorage::Pointer storage = this->GetDataStorage(); + + mitk::DataNode::Pointer node = nodes.front(); + + if (!node) + { + // Nothing selected. Inform the user and return + QMessageBox::information(NULL, "Template", "Please load and select an image before starting image cropping."); + return; + } + + mitk::BaseData* data = node->GetData(); + if (data) + { + // test if this data item is an image or not (could also be a surface or something totally different) + mitk::Image* image = dynamic_cast(data); + if (image) + { + UpdateBFSettings(image); + std::stringstream message; + std::string name; + message << "Performing image cropping for image "; + if (node->GetName(name)) + { + // a property called "name" was found for this DataNode + message << "'" << name << "'"; + m_OldNodeName = name; + } + else + m_OldNodeName = " "; + + message << "."; + MITK_INFO << message.str(); + + m_Controls.buttonApplyCropFilter->setText("working..."); + DisableControls(); + + CropThread *thread = new CropThread(); + connect(thread, &CropThread::result, this, &PAImageProcessing::HandleCropResults); + connect(thread, &CropThread::finished, thread, &QObject::deleteLater); + + thread->setConfig(m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value()); + thread->setInputImage(image); + + MITK_INFO << "Started new thread for Image Cropping"; + thread->start(); + } + } +} + +void PAImageProcessing::HandleCropResults(mitk::Image::Pointer image) +{ + auto newNode = mitk::DataNode::New(); + newNode->SetData(image); + + // name the new Data node + std::stringstream newNodeName; + newNodeName << m_OldNodeName << " "; + newNodeName << "Cropped"; + + newNode->SetName(newNodeName.str()); + + // update level window for the current dynamic range + mitk::LevelWindow levelWindow; + newNode->GetLevelWindow(levelWindow); + auto data = newNode->GetData(); + levelWindow.SetAuto(dynamic_cast(data), true, true); + newNode->SetLevelWindow(levelWindow); + + // add new node to data storage + this->GetDataStorage()->Add(newNode); + + m_Controls.buttonApplyCropFilter->setText("Apply Crop Filter"); + EnableControls(); + + // update rendering + mitk::RenderingManager::GetInstance()->InitializeViews( + dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void PAImageProcessing::StartBandpassThread() +{ + QList nodes = this->GetDataManagerSelection(); + if (nodes.empty()) return; + + mitk::DataStorage::Pointer storage = this->GetDataStorage(); + + mitk::DataNode::Pointer node = nodes.front(); + + if (!node) + { + // Nothing selected. Inform the user and return + QMessageBox::information(NULL, "Template", "Please load and select an image before starting image cropping."); + return; + } + + mitk::BaseData* data = node->GetData(); + if (data) + { + // test if this data item is an image or not (could also be a surface or something totally different) + mitk::Image* image = dynamic_cast(data); + if (image) + { + UpdateBFSettings(image); + std::stringstream message; + std::string name; + message << "Performing Bandpass filter on image "; + if (node->GetName(name)) + { + // a property called "name" was found for this DataNode + message << "'" << name << "'"; + m_OldNodeName = name; + } + else + m_OldNodeName = " "; + + message << "."; + MITK_INFO << message.str(); + + m_Controls.buttonApplyBandpass->setText("working..."); + DisableControls(); + + BandpassThread *thread = new BandpassThread(); + connect(thread, &BandpassThread::result, this, &PAImageProcessing::HandleBandpassResults); + connect(thread, &BandpassThread::finished, thread, &QObject::deleteLater); + + float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / m_Controls.BPSpeedOfSound->value(); + + // add a safeguard so the program does not chrash when applying a Bandpass that reaches out of the bounds of the image + float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; + float BPHighPass = 1000000 * m_Controls.BPhigh->value(); // [Hz] + float BPLowPass = maxFrequency - 1000000 * m_Controls.BPlow->value(); // [Hz] + + if (BPLowPass > maxFrequency && m_Controls.UseBP->isChecked()) + { + QMessageBox Msgbox; + Msgbox.setText("LowPass too low, disabled it."); + Msgbox.exec(); + + BPLowPass = 0; + } + if (BPLowPass < 0 && m_Controls.UseBP->isChecked()) + { + QMessageBox Msgbox; + Msgbox.setText("LowPass too high, disabled it."); + Msgbox.exec(); + + BPLowPass = 0; + } + if (BPHighPass > maxFrequency && m_Controls.UseBP->isChecked()) + { + QMessageBox Msgbox; + Msgbox.setText("HighPass too high, disabled it."); + Msgbox.exec(); + + BPHighPass = 0; + } + if (BPHighPass > maxFrequency - BFconfig.BPLowPass) + { + QMessageBox Msgbox; + Msgbox.setText("HighPass higher than LowPass, disabled both."); + Msgbox.exec(); + + BPHighPass = 0; + BPLowPass = 0; + } + + thread->setConfig(BPHighPass, BPLowPass, m_Controls.BPFalloff->value(), recordTime); + thread->setInputImage(image); + + MITK_INFO << "Started new thread for Bandpass filter"; + thread->start(); + } + } +} + +void PAImageProcessing::HandleBandpassResults(mitk::Image::Pointer image) +{ + auto newNode = mitk::DataNode::New(); + newNode->SetData(image); + + // name the new Data node + std::stringstream newNodeName; + newNodeName << m_OldNodeName << " "; + newNodeName << "Bandpassed"; + + newNode->SetName(newNodeName.str()); + + // update level window for the current dynamic range + mitk::LevelWindow levelWindow; + newNode->GetLevelWindow(levelWindow); + auto data = newNode->GetData(); + levelWindow.SetAuto(dynamic_cast(data), true, true); + newNode->SetLevelWindow(levelWindow); + + // add new node to data storage + this->GetDataStorage()->Add(newNode); + + m_Controls.buttonApplyBandpass->setText("Apply Bandpass"); + EnableControls(); + + // update rendering + mitk::RenderingManager::GetInstance()->InitializeViews( + dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void PAImageProcessing::UpdateBounds() +{ + if (!m_Controls.Partial->isChecked()) + { + m_Controls.boundLow->setEnabled(false); + m_Controls.boundHigh->setEnabled(false); + BFconfig.partial = false; + return; + } + else + { + m_Controls.boundLow->setEnabled(true); + m_Controls.boundHigh->setEnabled(true); + BFconfig.partial = true; + } + + if(m_Controls.boundLow->value()>m_Controls.boundHigh->value()) + { + MITK_INFO << "high bound < low bound -> setting both to beamform only first slice"; + m_Controls.boundLow->setValue(0); + m_Controls.boundHigh->setValue(0); + BFconfig.CropBounds[0] = 0; + BFconfig.CropBounds[1] = 0; + } + else + { + BFconfig.CropBounds[0] = m_Controls.boundLow->value(); + BFconfig.CropBounds[1] = m_Controls.boundHigh->value(); + } +} + +void PAImageProcessing::UpdateProgress(int progress, std::string progressInfo) +{ + if (progress < 100) + m_Controls.progressBar->setValue(progress); + else + m_Controls.progressBar->setValue(100); + m_Controls.ProgressInfo->setText(progressInfo.c_str()); + qApp->processEvents(); +} + +void PAImageProcessing::UpdateImageInfo() +{ + QList nodes = this->GetDataManagerSelection(); + if (nodes.empty()) return; + + mitk::DataNode::Pointer node = nodes.front(); + + if (!node) + { + // Nothing selected + return; + } + + mitk::BaseData* data = node->GetData(); + if (data) + { + // test if this data item is an image or not (could also be a surface or something totally different) + mitk::Image* image = dynamic_cast(data); + + if (image) + { + // beamforming configs + if (m_Controls.UseImageSpacing->isChecked()) + { + m_Controls.ElementCount->setValue(image->GetDimension(0)); + m_Controls.Pitch->setValue(image->GetGeometry()->GetSpacing()[0]); + m_Controls.boundLow->setMaximum(image->GetDimension(2) - 1); + } + UpdateRecordTime(image); + + // bandpass configs + float speedOfSound = m_Controls.BPSpeedOfSound->value(); // [m/s] + float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / speedOfSound; + + std::stringstream frequency; + float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; + frequency << maxFrequency / 1000000; //[MHz] + frequency << "MHz"; + + m_Controls.BPhigh->setMaximum(maxFrequency / 1000000); + m_Controls.BPlow->setMaximum(maxFrequency / 1000000); + + frequency << " is the maximal allowed frequency for the selected image."; + m_Controls.BPhigh->setToolTip(frequency.str().c_str()); + m_Controls.BPlow->setToolTip(frequency.str().c_str()); + m_Controls.BPhigh->setToolTipDuration(5000); + m_Controls.BPlow->setToolTipDuration(5000); + } + } +} + +void PAImageProcessing::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, + const QList& nodes ) +{ + // iterate all selected objects, adjust warning visibility + foreach( mitk::DataNode::Pointer node, nodes ) + { + if( node.IsNotNull() && dynamic_cast(node->GetData()) ) + { + m_Controls.labelWarning->setVisible( false ); + m_Controls.buttonApplyBModeFilter->setEnabled( true ); + m_Controls.labelWarning2->setVisible(false); + m_Controls.buttonApplyCropFilter->setEnabled(true); + m_Controls.labelWarning3->setVisible(false); + m_Controls.buttonApplyBandpass->setEnabled(true); + UpdateImageInfo(); + return; + } + } + m_Controls.labelWarning->setVisible( true ); + m_Controls.buttonApplyBModeFilter->setEnabled( false ); + m_Controls.labelWarning2->setVisible(true); + m_Controls.buttonApplyCropFilter->setEnabled(false); + m_Controls.labelWarning3->setVisible(true); + m_Controls.buttonApplyBandpass->setEnabled(false); +} + +void PAImageProcessing::UseResampling() +{ + if (m_Controls.DoResampling->isChecked()) + { + m_Controls.ResamplingValue->setEnabled(true); + m_ResampleSpacing = m_Controls.ResamplingValue->value(); + } + else + { + m_Controls.ResamplingValue->setEnabled(false); + m_ResampleSpacing = 0; + } +} + +void PAImageProcessing::UseLogfilter() +{ + m_UseLogfilter = m_Controls.Logfilter->isChecked(); +} + +void PAImageProcessing::SetResampling() +{ + m_ResampleSpacing = m_Controls.ResamplingValue->value(); +} + +void PAImageProcessing::UpdateBFSettings(mitk::Image::Pointer image) +{ + if ("DAS" == m_Controls.BFAlgorithm->currentText()) + BFconfig.Algorithm = mitk::BeamformingFilter::beamformingSettings::BeamformingAlgorithm::DAS; + else if ("DMAS" == m_Controls.BFAlgorithm->currentText()) + BFconfig.Algorithm = mitk::BeamformingFilter::beamformingSettings::BeamformingAlgorithm::DMAS; + + if ("Quad. Approx." == m_Controls.DelayCalculation->currentText()) + { + BFconfig.DelayCalculationMethod = mitk::BeamformingFilter::beamformingSettings::DelayCalc::QuadApprox; + } + else if ("Spherical Wave" == m_Controls.DelayCalculation->currentText()) + { + BFconfig.DelayCalculationMethod = mitk::BeamformingFilter::beamformingSettings::DelayCalc::Spherical; + } + + if ("Von Hann" == m_Controls.Apodization->currentText()) + { + BFconfig.Apod = mitk::BeamformingFilter::beamformingSettings::Apodization::Hann; + } + else if ("Hamming" == m_Controls.Apodization->currentText()) + { + BFconfig.Apod = mitk::BeamformingFilter::beamformingSettings::Apodization::Hamm; + } + else if ("Box" == m_Controls.Apodization->currentText()) + { + BFconfig.Apod = mitk::BeamformingFilter::beamformingSettings::Apodization::Box; + } + + BFconfig.Pitch = m_Controls.Pitch->value() / 1000; // [m] + BFconfig.SpeedOfSound = m_Controls.SpeedOfSound->value(); // [m/s] + BFconfig.SamplesPerLine = m_Controls.Samples->value(); + BFconfig.ReconstructionLines = m_Controls.Lines->value(); + BFconfig.TransducerElements = m_Controls.ElementCount->value(); + BFconfig.Angle = m_Controls.Angle->value(); // [deg] + BFconfig.UseBP = m_Controls.UseBP->isChecked(); + BFconfig.UseGPU = m_Controls.UseGPU->isChecked(); + + UpdateRecordTime(image); + UpdateBounds(); +} + +void PAImageProcessing::UpdateRecordTime(mitk::Image::Pointer image) +{ + if (m_Controls.UseImageSpacing->isChecked()) + { + BFconfig.RecordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000000; // [s] + BFconfig.TimeSpacing = image->GetGeometry()->GetSpacing()[1] / 1000000; + MITK_INFO << "Calculated Scan Depth of " << BFconfig.RecordTime * BFconfig.SpeedOfSound * 100 << "cm"; + } + else + { + BFconfig.RecordTime = 2 * m_Controls.ScanDepth->value() / 1000 / BFconfig.SpeedOfSound; // [s] + BFconfig.TimeSpacing = BFconfig.RecordTime / image->GetDimension(1); + } + + if ("US Image" == m_Controls.ImageType->currentText()) + { + BFconfig.Photoacoustic = false; + } + else if ("PA Image" == m_Controls.ImageType->currentText()) + { + BFconfig.Photoacoustic = true; + } +} + +void PAImageProcessing::EnableControls() +{ + m_Controls.DoResampling->setEnabled(true); + UseResampling(); + m_Controls.Logfilter->setEnabled(true); + m_Controls.buttonApplyBModeFilter->setEnabled(true); + + m_Controls.CutoffAbove->setEnabled(true); + m_Controls.CutoffBelow->setEnabled(true); + m_Controls.Cutoff->setEnabled(true); + m_Controls.buttonApplyCropFilter->setEnabled(true); + + m_Controls.buttonApplyBandpass->setEnabled(true); + + m_Controls.BFAlgorithm->setEnabled(true); + m_Controls.DelayCalculation->setEnabled(true); + m_Controls.ImageType->setEnabled(true); + m_Controls.Apodization->setEnabled(true); + m_Controls.UseBP->setEnabled(true); + m_Controls.UseGPU->setEnabled(true); + m_Controls.BPhigh->setEnabled(true); + m_Controls.BPlow->setEnabled(true); + m_Controls.BPFalloff->setEnabled(true); + m_Controls.UseImageSpacing->setEnabled(true); + UseImageSpacing(); + m_Controls.Pitch->setEnabled(true); + m_Controls.ElementCount->setEnabled(true); + m_Controls.SpeedOfSound->setEnabled(true); + m_Controls.Samples->setEnabled(true); + m_Controls.Lines->setEnabled(true); + m_Controls.Angle->setEnabled(true); + m_Controls.buttonApplyBeamforming->setEnabled(true); +} + +void PAImageProcessing::DisableControls() +{ + m_Controls.DoResampling->setEnabled(false); + m_Controls.ResamplingValue->setEnabled(false); + m_Controls.Logfilter->setEnabled(false); + m_Controls.buttonApplyBModeFilter->setEnabled(false); + + m_Controls.CutoffAbove->setEnabled(false); + m_Controls.CutoffBelow->setEnabled(false); + m_Controls.Cutoff->setEnabled(false); + m_Controls.buttonApplyCropFilter->setEnabled(false); + + m_Controls.buttonApplyBandpass->setEnabled(false); + + m_Controls.BFAlgorithm->setEnabled(false); + m_Controls.DelayCalculation->setEnabled(false); + m_Controls.ImageType->setEnabled(false); + m_Controls.Apodization->setEnabled(false); + m_Controls.UseBP->setEnabled(false); + m_Controls.UseGPU->setEnabled(false); + m_Controls.BPhigh->setEnabled(false); + m_Controls.BPlow->setEnabled(false); + m_Controls.BPFalloff->setEnabled(false); + m_Controls.UseImageSpacing->setEnabled(false); + m_Controls.ScanDepth->setEnabled(false); + m_Controls.Pitch->setEnabled(false); + m_Controls.ElementCount->setEnabled(false); + m_Controls.SpeedOfSound->setEnabled(false); + m_Controls.Samples->setEnabled(false); + m_Controls.Lines->setEnabled(false); + m_Controls.Angle->setEnabled(false); + m_Controls.buttonApplyBeamforming->setEnabled(false); +} + +void PAImageProcessing::UseImageSpacing() +{ + if (m_Controls.UseImageSpacing->isChecked()) + { + m_Controls.ScanDepth->setDisabled(true); + } + else + { + m_Controls.ScanDepth->setEnabled(true); + } +} + +void BeamformingThread::run() +{ + mitk::Image::Pointer resultImage; + mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); + std::function progressHandle = [this](int progress, std::string progressInfo) { + emit updateProgress(progress, progressInfo); + }; + + resultImage = filterbank->ApplyBeamforming(m_InputImage, m_BFconfig, m_Cutoff, progressHandle); + + emit result(resultImage); +} + +void BeamformingThread::setConfig(mitk::BeamformingFilter::beamformingSettings BFconfig) +{ + m_BFconfig = BFconfig; +} + +void BeamformingThread::setInputImage(mitk::Image::Pointer image) +{ + m_InputImage = image; +} + +void BeamformingThread::setCutoff(int cutoff) +{ + m_Cutoff = cutoff; +} + +void BmodeThread::run() +{ + mitk::Image::Pointer resultImage; + mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); + + resultImage = filterbank->ApplyBmodeFilter(m_InputImage, m_Method, m_UseLogfilter, m_ResampleSpacing); + + emit result(resultImage); +} + +void BmodeThread::setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method) +{ + m_UseLogfilter = useLogfilter; + m_ResampleSpacing = resampleSpacing; + m_Method = method; +} + +void BmodeThread::setInputImage(mitk::Image::Pointer image) +{ + m_InputImage = image; +} + +void CropThread::run() +{ + mitk::Image::Pointer resultImage; + mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); + + resultImage = filterbank->ApplyCropping(m_InputImage, m_CutAbove, m_CutBelow, 0, 0, 0, m_InputImage->GetDimension(2) - 1); + + emit result(resultImage); +} + +void CropThread::setConfig(unsigned int CutAbove, unsigned int CutBelow) +{ + m_CutAbove = CutAbove; + m_CutBelow = CutBelow; +} + +void CropThread::setInputImage(mitk::Image::Pointer image) +{ + m_InputImage = image; +} + +void BandpassThread::run() +{ + mitk::Image::Pointer resultImage; + mitk::PhotoacousticImage::Pointer filterbank = mitk::PhotoacousticImage::New(); + + resultImage = filterbank->BandpassFilter(m_InputImage, m_RecordTime, m_BPHighPass, m_BPLowPass, m_TukeyAlpha); + emit result(resultImage); +} + +void BandpassThread::setConfig(float BPHighPass, float BPLowPass, float TukeyAlpha, float recordTime) +{ + m_BPHighPass = BPHighPass; + m_BPLowPass = BPLowPass; + m_TukeyAlpha = TukeyAlpha; + m_RecordTime = recordTime; +} + +void BandpassThread::setInputImage(mitk::Image::Pointer image) +{ + m_InputImage = image; +} diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h new file mode 100644 index 0000000000..42270dd4c7 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h @@ -0,0 +1,182 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +#ifndef PAImageProcessing_h +#define PAImageProcessing_h + +#include +#include + +#include +#include + +#include "ui_PAImageProcessingControls.h" + +#include "mitkPhotoacousticBeamformingFilter.h" + +Q_DECLARE_METATYPE(mitk::Image::Pointer) +Q_DECLARE_METATYPE(std::string) + +class PAImageProcessing : public QmitkAbstractView +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + + public: + + static const std::string VIEW_ID; + + PAImageProcessing(); + + protected slots: + + /// \brief Called when the user clicks the GUI button + + void UpdateBounds(); + + void UseResampling(); + void UseLogfilter(); + void SetResampling(); + void UseImageSpacing(); + void UpdateImageInfo(); + void UpdateRecordTime(mitk::Image::Pointer image); + + void HandleBeamformingResults(mitk::Image::Pointer image); + void StartBeamformingThread(); + + void HandleBmodeResults(mitk::Image::Pointer image); + void StartBmodeThread(); + + void HandleCropResults(mitk::Image::Pointer image); + void StartCropThread(); + + void HandleBandpassResults(mitk::Image::Pointer image); + void StartBandpassThread(); + + void UpdateProgress(int progress, std::string progressInfo); + + void BatchProcessing(); + void UpdateSaveBoxes(); + + protected: + virtual void CreateQtPartControl(QWidget *parent) override; + + virtual void SetFocus() override; + + /// \brief called by QmitkFunctionality when DataManager's selection has changed + virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, + const QList& nodes ) override; + + Ui::PAImageProcessingControls m_Controls; + + float m_ResampleSpacing; + bool m_UseLogfilter; + std::string m_OldNodeName; + + mitk::BeamformingFilter::beamformingSettings BFconfig; + + void UpdateBFSettings(mitk::Image::Pointer image); + + void EnableControls(); + void DisableControls(); +}; + +class BeamformingThread : public QThread +{ + Q_OBJECT + void run() Q_DECL_OVERRIDE; + + signals: + void result(mitk::Image::Pointer); + void updateProgress(int, std::string); + + public: + void setConfig(mitk::BeamformingFilter::beamformingSettings BFconfig); + void setInputImage(mitk::Image::Pointer image); + void setCutoff(int cutoff); + + protected: + mitk::BeamformingFilter::beamformingSettings m_BFconfig; + mitk::Image::Pointer m_InputImage; + int m_Cutoff; +}; + +class BmodeThread : public QThread +{ + Q_OBJECT + void run() Q_DECL_OVERRIDE; + + signals: + void result(mitk::Image::Pointer); + + public: + enum BModeMethod { ShapeDetection, Abs }; + + void setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method); + void setInputImage(mitk::Image::Pointer image); + + protected: + mitk::Image::Pointer m_InputImage; + + mitk::PhotoacousticImage::BModeMethod m_Method; + bool m_UseLogfilter; + double m_ResampleSpacing; +}; + +class CropThread : public QThread +{ + Q_OBJECT + void run() Q_DECL_OVERRIDE; + +signals: + void result(mitk::Image::Pointer); + +public: + void setConfig(unsigned int CutAbove, unsigned int CutBelow); + void setInputImage(mitk::Image::Pointer image); + +protected: + mitk::Image::Pointer m_InputImage; + + unsigned int m_CutAbove; + unsigned int m_CutBelow; +}; + + +class BandpassThread : public QThread +{ + Q_OBJECT + void run() Q_DECL_OVERRIDE; + +signals: + void result(mitk::Image::Pointer); + +public: + void setConfig(float BPHighPass, float BPLowPass, float TukeyAlpha, float recordTime); + void setInputImage(mitk::Image::Pointer image); + +protected: + mitk::Image::Pointer m_InputImage; + + float m_BPHighPass; + float m_BPLowPass; + float m_TukeyAlpha; + float m_RecordTime; +}; + +#endif // PAImageProcessing_h diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui new file mode 100644 index 0000000000..bbc2c814b3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui @@ -0,0 +1,960 @@ + + + PAImageProcessingControls + + + + 0 + 0 + 382 + 1217 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Batch Processing</span></p></body></html> + + + + + + + Start Batch Processing + + + + + + + + + Bandpass + + + true + + + + + + + Crop + + + true + + + + + + + Save + + + true + + + + + + + Save + + + true + + + + + + + Save + + + + + + + Beamform + + + true + + + + + + + BMode + + + true + + + + + + + Save + + + true + + + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">B-mode Filter Settings</span></p></body></html> + + + + + + + + + Do Resampling + + + + + + + + Absolute Filter + + + + + Envelope Detection + + + + + + + + + + + 0 + 0 + + + + + 13 + 0 + + + + + 11 + + + + 0.010000000000000 + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + [mm] Depth Spacing + + + + + + + + + + + Add Logfilter + + + + + + + QLabel { color: rgb(255, 0, 0) } + + + <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600;">Please select an image!</span></p></body></html> + + + + + + + + 0 + 0 + + + + Do image processing + + + Apply B-mode Filter + + + + + + + + + Qt::Horizontal + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Bandpass Filter Settings</span></p></body></html> + + + + + + + QLayout::SetDefaultConstraint + + + 0 + + + + + + 0 + 0 + + + + 3 + + + 0.010000000000000 + + + 200.000000000000000 + + + 15.000000000000000 + + + + + + + [MHz] f High Pass + + + + + + + [MHz] f Low Pass + + + + + + + + 0 + 0 + + + + 3 + + + 200.000000000000000 + + + + + + + Thukey window alpha + + + + + + + 1 + + + 200.000000000000000 + + + 3000.000000000000000 + + + 5.000000000000000 + + + 1480.000000000000000 + + + + + + + [m/s] Speed of Sound + + + + + + + 2 + + + 1.000000000000000 + + + 0.100000000000000 + + + 0.500000000000000 + + + + + + + + + <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> + + + + + + + Apply Bandpass + + + + + + + + + Qt::Horizontal + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Crop Filter Settings</span></p></body></html> + + + + + + + + + 99999 + + + 5 + + + 165 + + + + + + + Cut Top + + + + + + + 99999 + + + 10 + + + + + + + Cut Bottom + + + + + + + + + <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> + + + + + + + Apply Crop Filer + + + + + + + + + Qt::Horizontal + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Beamforming Filter Settings</span></p></body></html> + + + + + + + 5 + + + 2 + + + + + Delay Calculation + + + + + + + Auto Get Depth + + + true + + + + + + + Apply Beamforming + + + + + + + + + + + + + + Beamforming Method + + + + + + + [mm] Scan Depth + + + + + + + + 0 + 0 + + + + 2 + + + 0.010000000000000 + + + 9.000000000000000 + + + 0.050000000000000 + + + 0.300000000000000 + + + + + + + Transducer Elements + + + + + + + + 0 + 0 + + + + 4 + + + 300.000000000000000 + + + 0.100000000000000 + + + 50.000000000000000 + + + + + + + [mm] Transducer Pitch + + + + + + + + 0 + 0 + + + + 64 + + + 1024 + + + 128 + + + 128 + + + + + + + + 0 + 0 + + + + 256 + + + 16384 + + + 256 + + + 2048 + + + + + + + + 0 + 0 + + + + 64 + + + 2048 + + + 128 + + + 256 + + + + + + + Samples + + + + + + + Reconstruction Lines + + + + + + + true + + + + 0 + 0 + + + + 100 + + + 0 + + + + + + + + 0 + 0 + + + + 900 + + + 10 + + + 0 + + + + + + + Cutoff Upper Voxels + + + + + + + + 0 + 0 + + + + + DAS + + + + + DMAS + + + + + + + + + 0 + 0 + + + + + Quad. Approx. + + + + + Spherical Wave + + + + + + + + + 0 + 0 + + + + + PA Image + + + + + US Image + + + + + + + + Image Type + + + + + + + + 0 + 0 + + + + + Von Hann + + + + + Hamming + + + + + Box + + + + + + + + Apodization + + + + + + + + 0 + 0 + + + + 1 + + + 200.000000000000000 + + + 3000.000000000000000 + + + 5.000000000000000 + + + 1480.000000000000000 + + + + + + + [m/s] Speed of Sound + + + + + + + + + false + + + 99999 + + + + + + + minimal beamformed slice + + + min + + + + + + + + + + + false + + + 99999 + + + 10 + + + + + + + Maximal beamformed slice + + + max + + + + + + + + + + + + + + + + select slices + + + + + + + Compute On GPU + + + true + + + + + + + true + + + Auto Use Bandpass + + + + + + + + 0 + 0 + + + + 1 + + + 1.000000000000000 + + + 180.000000000000000 + + + 27.000000000000000 + + + + + + + [°] Element Angle + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.cpp new file mode 100644 index 0000000000..9b447585f8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.cpp @@ -0,0 +1,40 @@ +/*=================================================================== + +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 "org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h" + +#include + +#include "PAImageProcessing.h" + +namespace mitk { + +void org_mitk_gui_qt_photoacoustics_imageprocessing_Activator::start(ctkPluginContext* context) +{ + BERRY_REGISTER_EXTENSION_CLASS(PAImageProcessing, context) +} + +void org_mitk_gui_qt_photoacoustics_imageprocessing_Activator::stop(ctkPluginContext* context) +{ + Q_UNUSED(context) +} + +} + +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + Q_EXPORT_PLUGIN2(org_mitk_gui_qt_photoacoustics_imageprocessing, mitk::org_mitk_gui_qt_photoacoustics_imageprocessing_Activator) +#endif diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h new file mode 100644 index 0000000000..ef25444bcd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h @@ -0,0 +1,43 @@ +/*=================================================================== + +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. + +===================================================================*/ + + +#ifndef org_mitk_gui_qt_photoacoustics_imageprocessing_Activator_h +#define org_mitk_gui_qt_photoacoustics_imageprocessing_Activator_h + +#include + +namespace mitk { + +class org_mitk_gui_qt_photoacoustics_imageprocessing_Activator : + public QObject, public ctkPluginActivator +{ + Q_OBJECT +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_photoacoustics_imageprocessing") +#endif + Q_INTERFACES(ctkPluginActivator) + +public: + + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + +}; // org_mitk_gui_qt_photoacoustics_imageprocessing_Activator + +} + +#endif // org_mitk_gui_qt_photoacoustics_imageprocessing_Activator_h diff --git a/Plugins/org.mitk.gui.qt.ultrasound/CMakeLists.txt b/Plugins/org.mitk.gui.qt.ultrasound/CMakeLists.txt index bd69a27e0c..b7b4f50565 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.ultrasound/CMakeLists.txt @@ -1,9 +1,25 @@ project(org_mitk_gui_qt_ultrasound) include_directories(${CTK_INCLUDE_DIRS}) +IF(WIN32) + IF(MITK_USE_US_DiPhAS_SDK) + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Debug/Framework.IBMT.US.Core.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Debug/Framework.IBMT.US.CWrapper.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Debug/Framework.IBMT.US.OpenCL.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Debug/Framework.IBMT.US.PCIeInterface.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Debug/openclext.dll ${MITK_BINARY_DIR}/bin/Debug/ COPYONLY ) + + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Release/Framework.IBMT.US.Core.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Release/Framework.IBMT.US.CWrapper.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Release/Framework.IBMT.US.OpenCL.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Release/Framework.IBMT.US.PCIeInterface.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) + configure_file( ${MITK_US_DiPhAS_SDK_PATH}/Release/openclext.dll ${MITK_BINARY_DIR}/bin/Release/ COPYONLY ) + ENDIF(MITK_USE_US_DiPhAS_SDK) +ENDIF(WIN32) + mitk_create_plugin( EXPORT_DIRECTIVE ULTRASOUND_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDS MitkQtWidgetsExt MitkUS MitkUSUI ) diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp index aedc05bc57..ff276f7c79 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp @@ -1,497 +1,637 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include //Mitk #include #include #include #include #include +#include +#include // Qmitk #include "UltrasoundSupport.h" // Qt #include #include #include // Ultrasound #include "mitkUSDevice.h" #include "QmitkUSAbstractCustomWidget.h" #include #include #include "usServiceReference.h" #include "internal/org_mitk_gui_qt_ultrasound_Activator.h" const std::string UltrasoundSupport::VIEW_ID = "org.mitk.views.ultrasoundsupport"; void UltrasoundSupport::SetFocus() { } void UltrasoundSupport::CreateQtPartControl(QWidget *parent) { //initialize timers m_UpdateTimer = new QTimer(this); m_RenderingTimer2d = new QTimer(this); m_RenderingTimer3d = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); //load persistence data before connecting slots (so no slots are called in this phase...) LoadUISettings(); //connect signals and slots... connect(m_Controls.m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this, SLOT(OnClickedAddNewDevice())); // Change Widget Visibilities connect(m_Controls.m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this->m_Controls.m_NewVideoDeviceWidget, SLOT(CreateNewDevice())); // Init NewDeviceWidget connect(m_Controls.m_ActiveVideoDevices, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnChangedActiveDevice())); connect(m_Controls.m_RunImageTimer, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice())); connect(m_Controls.m_ShowImageStream, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice())); connect(m_Controls.m_NewVideoDeviceWidget, SIGNAL(Finished()), this, SLOT(OnNewDeviceWidgetDone())); // After NewDeviceWidget finished editing connect(m_Controls.m_FrameRatePipeline, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls.m_FrameRate2d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls.m_FrameRate3d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls.m_FreezeButton, SIGNAL(clicked()), this, SLOT(OnClickedFreezeButton())); connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(UpdateImage())); connect(m_RenderingTimer2d, SIGNAL(timeout()), this, SLOT(RenderImage2d())); connect(m_RenderingTimer3d, SIGNAL(timeout()), this, SLOT(RenderImage3d())); connect(m_Controls.m_Update2DView, SIGNAL(clicked()), this, SLOT(StartTimers())); connect(m_Controls.m_Update3DView, SIGNAL(clicked()), this, SLOT(StartTimers())); connect(m_Controls.m_DeviceManagerWidget, SIGNAL(EditDeviceButtonClicked(mitk::USDevice::Pointer)), this, SLOT(OnClickedEditDevice())); //Change Widget Visibilities connect(m_Controls.m_DeviceManagerWidget, SIGNAL(EditDeviceButtonClicked(mitk::USDevice::Pointer)), this->m_Controls.m_NewVideoDeviceWidget, SLOT(EditDevice(mitk::USDevice::Pointer))); // Initializations m_Controls.m_NewVideoDeviceWidget->setVisible(false); std::string filter = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE + "=true))"; m_Controls.m_ActiveVideoDevices->Initialize( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, filter); m_Controls.m_ActiveVideoDevices->SetAutomaticallySelectFirstEntry(true); m_FrameCounterPipeline = 0; m_FrameCounter2d = 0; m_FrameCounter3d = 0; - // Create Node for US Stream - if (m_Node.IsNull()) + m_Controls.tabWidget->setTabEnabled(1, false); +} + +#include + +void UltrasoundSupport::InitNewNode() +{ + m_Node.push_back(nullptr); + auto& Node = m_Node.back(); + Node = mitk::DataNode::New(); + Node->SetName("No Data received yet ..."); + //create a dummy image (gray values 0..255) for correct initialization of level window, etc. + mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); + Node->SetData(dummyImage); + m_OldGeometry = dynamic_cast(dummyImage->GetGeometry()); + UpdateColormaps(); + + this->GetDataStorage()->Add(Node); +} + +void UltrasoundSupport::DestroyLastNode() +{ + auto& Node = m_Node.back(); + this->GetDataStorage()->Remove(Node); + Node->ReleaseData(); + m_Node.pop_back(); + UpdateColormaps(); +} + + +void UltrasoundSupport::UpdateColormaps() +{ + // we update here both the colormaps of the nodes, as well as the + // level window for the current dynamic range + mitk::LevelWindow levelWindow; + + if (m_Node.size() > 1) + { + for (int index = 0; index < m_AmountOfOutputs - 1; ++index) + { + SetColormap(m_Node.at(index), mitk::LookupTable::LookupTableType::GRAYSCALE); + m_Node.at(index)->GetLevelWindow(levelWindow); + if (!m_Image->IsEmpty()) + levelWindow.SetAuto(m_Image, true, true); + m_Node.at(index)->SetLevelWindow(levelWindow); + } + SetColormap(m_Node.back(), mitk::LookupTable::LookupTableType::JET_TRANSPARENT); + m_Node.back()->GetLevelWindow(levelWindow); + levelWindow.SetWindowBounds(10, 150, true); + m_Node.back()->SetLevelWindow(levelWindow); + } + else if (m_Node.size() == 1) { - m_Node = mitk::DataNode::New(); - m_Node->SetName("US Support Viewing Stream"); - //create a dummy image (gray values 0..255) for correct initialization of level window, etc. - mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); - m_Node->SetData(dummyImage); - m_OldGeometry = dynamic_cast(dummyImage->GetGeometry()); + SetColormap(m_Node.back(), mitk::LookupTable::LookupTableType::GRAYSCALE); + m_Node.back()->GetLevelWindow(levelWindow); + if (!m_Image->IsEmpty()) + levelWindow.SetAuto(m_Image, true, true); + m_Node.back()->SetLevelWindow(levelWindow); } - - m_Controls.tabWidget->setTabEnabled(1, false); + +} +void UltrasoundSupport::SetColormap(mitk::DataNode::Pointer node, mitk::LookupTable::LookupTableType type) +{ + mitk::LookupTable::Pointer lookupTable = mitk::LookupTable::New(); + mitk::LookupTableProperty::Pointer lookupTableProperty = mitk::LookupTableProperty::New(); + lookupTable->SetType(type); + lookupTableProperty->SetLookupTable(lookupTable); + node->SetProperty("LookupTable", lookupTableProperty); + + mitk::RenderingModeProperty::Pointer renderingMode = + dynamic_cast(node->GetProperty("Image Rendering.Mode")); + renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); } void UltrasoundSupport::OnClickedAddNewDevice() { m_Controls.m_NewVideoDeviceWidget->setVisible(true); m_Controls.m_DeviceManagerWidget->setVisible(false); m_Controls.m_Headline->setText("Add New Video Device:"); m_Controls.m_WidgetActiveDevices->setVisible(false); } void UltrasoundSupport::OnClickedEditDevice() { m_Controls.m_NewVideoDeviceWidget->setVisible(true); m_Controls.m_DeviceManagerWidget->setVisible(false); m_Controls.m_WidgetActiveDevices->setVisible(false); m_Controls.m_Headline->setText("Edit Video Device:"); } -void UltrasoundSupport::UpdateImage() +void UltrasoundSupport::UpdateAmountOfOutputs() { - //Update device - m_Device->Modified(); - m_Device->Update(); + // Update the amount of Nodes; there should be one Node for every slide that is set. Note that we must check whether the slices are set, + // just using the m_Image->dimension(3) will produce nulltpointers on slices of the image that were not set + bool isSet = true; + m_AmountOfOutputs = 0; + while (isSet) { + isSet = m_Image->IsSliceSet(m_AmountOfOutputs); + if (isSet) + ++m_AmountOfOutputs; + } - //Only update the view if the image is shown - if (m_Controls.m_ShowImageStream->isChecked()) + // correct the amount of Nodes to display data + while (m_Node.size() < m_AmountOfOutputs) { + InitNewNode(); + } + while (m_Node.size() > m_AmountOfOutputs) { + DestroyLastNode(); + } + + // correct the amount of image outputs that we feed the nodes with + while (m_curOutput.size() < m_AmountOfOutputs) { + m_curOutput.push_back(mitk::Image::New()); + + // initialize the slice images as 2d images with the size of m_Images + unsigned int* dimOld = m_Image->GetDimensions(); + unsigned int dim[2] = { dimOld[0], dimOld[1] }; + m_curOutput.back()->Initialize(m_Image->GetPixelType(), 2, dim); + } + while (m_curOutput.size() > m_AmountOfOutputs) { + m_curOutput.pop_back(); + } +} + +void UltrasoundSupport::UpdateImage() +{ + if(m_Controls.m_ShowImageStream->isChecked()) { - //Update data node - mitk::Image::Pointer curOutput = m_Device->GetOutput(); - if (curOutput->IsEmpty()) - { - m_Node->SetName("No Data received yet ..."); - //create a noise image for correct initialization of level window, etc. - mitk::Image::Pointer randomImage = mitk::ImageGenerator::GenerateRandomImage(32, 32, 1, 1, 1, 1, 1, 255, 0); - m_Node->SetData(randomImage); - curOutput->SetGeometry(randomImage->GetGeometry()); - } - else + m_Device->Modified(); + m_Device->Update(); + // Update device + + m_Image = m_Device->GetOutput(); + // get the Image data to display + UpdateAmountOfOutputs(); + // create as many Nodes and Outputs as there are slices in m_Image + + if (m_AmountOfOutputs == 0) + return; + // if there is no image to be displayed, skip the rest of this method + + for (int index = 0; index < m_AmountOfOutputs; ++index) { - m_Node->SetName("US Support Viewing Stream"); - m_Node->SetData(curOutput); + if (m_curOutput.at(index)->GetDimension(0) != m_Image->GetDimension(0) || + m_curOutput.at(index)->GetDimension(1) != m_Image->GetDimension(1) || + m_curOutput.at(index)->GetDimension(2) != m_Image->GetDimension(2) || + m_curOutput.at(index)->GetPixelType() != m_Image->GetPixelType()) + { + unsigned int* dimOld = m_Image->GetDimensions(); + unsigned int dim[2] = { dimOld[0], dimOld[1]}; + m_curOutput.at(index)->Initialize(m_Image->GetPixelType(), 2, dim); + // if we switched image resolution or type the outputs must be reinitialized! + } + + if (!m_Image->IsEmpty()) + { + mitk::ImageReadAccessor inputReadAccessor(m_Image, m_Image->GetSliceData(m_AmountOfOutputs-index-1,0,0,nullptr,mitk::Image::ReferenceMemory)); + // just reference the slices, to get a small performance gain + m_curOutput.at(index)->SetSlice(inputReadAccessor.GetData()); + m_curOutput.at(index)->GetGeometry()->SetIndexToWorldTransform(m_Image->GetSlicedGeometry()->GetIndexToWorldTransform()); + // Update the image Output with seperate slices + } + + if (m_curOutput.at(index)->IsEmpty()) + { + m_Node.at(index)->SetName("No Data received yet ..."); + // create a noise image for correct initialization of level window, etc. + mitk::Image::Pointer randomImage = mitk::ImageGenerator::GenerateRandomImage(32, 32, 1, 1, 1, 1, 1, 255, 0); + m_Node.at(index)->SetData(randomImage); + m_curOutput.at(index)->SetGeometry(randomImage->GetGeometry()); + } + else + { + char name[30]; + sprintf(name, "US Viewing Stream - Image %d", index); + m_Node.at(index)->SetName(name); + m_Node.at(index)->SetData(m_curOutput.at(index)); + // set the name of the Output + } } - // if the geometry changed: reinitialize the ultrasound image + + // if the geometry changed: reinitialize the ultrasound image. we use the m_curOutput.at(0) to readjust the geometry if ((m_OldGeometry.IsNotNull()) && - (curOutput->GetGeometry() != nullptr) && - (!mitk::Equal(*m_OldGeometry, *curOutput->GetGeometry(), 0.0001, false)) + (m_curOutput.at(0)->GetGeometry() != nullptr) && + (!mitk::Equal(m_OldGeometry.GetPointer(), m_curOutput.at(0)->GetGeometry(), 0.0001, false)) ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); - if ((renderWindow != nullptr) && (curOutput->GetTimeGeometry()->IsValid()) && (m_Controls.m_ShowImageStream->isChecked())) + if ((renderWindow != nullptr) && (m_curOutput.at(0)->GetTimeGeometry()->IsValid()) && (m_Controls.m_ShowImageStream->isChecked())) { renderWindow->GetRenderingManager()->InitializeViews( - curOutput->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + m_curOutput.at(0)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); renderWindow->GetRenderingManager()->RequestUpdateAll(); } - m_CurrentImageWidth = curOutput->GetDimension(0); - m_CurrentImageHeight = curOutput->GetDimension(1); - m_OldGeometry = dynamic_cast(curOutput->GetGeometry()); + m_CurrentImageWidth = m_curOutput.at(0)->GetDimension(0); + m_CurrentImageHeight = m_curOutput.at(0)->GetDimension(1); + m_OldGeometry = dynamic_cast(m_curOutput.at(0)->GetGeometry()); } } //Update frame counter m_FrameCounterPipeline++; if (m_FrameCounterPipeline >= 10) { - //compute framerate of pipeline update + // compute framerate of pipeline update int nMilliseconds = m_Clock.restart(); int fps = 10000.0f / (nMilliseconds); m_FPSPipeline = fps; m_FrameCounterPipeline = 0; - //display lowest framerate in UI + // display lowest framerate in UI int lowestFPS = m_FPSPipeline; if (m_Controls.m_Update2DView->isChecked() && (m_FPS2d < lowestFPS)) { lowestFPS = m_FPS2d; } if (m_Controls.m_Update3DView->isChecked() && (m_FPS3d < lowestFPS)) { lowestFPS = m_FPS3d; } m_Controls.m_FramerateLabel->setText("Current Framerate: " + QString::number(lowestFPS) + " FPS"); } } void UltrasoundSupport::RenderImage2d() { - this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); + if (!m_Controls.m_Update2DView->isChecked()) + return; + mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); + renderWindow->GetRenderingManager()->RequestUpdate(mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))->GetRenderWindow()); + //this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); m_FrameCounter2d++; if (m_FrameCounter2d >= 10) { - //compute framerate of 2d render window update + // compute framerate of 2d render window update int nMilliseconds = m_Clock2d.restart(); int fps = 10000.0f / (nMilliseconds); m_FPS2d = fps; m_FrameCounter2d = 0; } } void UltrasoundSupport::RenderImage3d() { + if (!m_Controls.m_Update3DView->isChecked()) + return; + this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); m_FrameCounter3d++; if (m_FrameCounter3d >= 10) { - //compute framerate of 2d render window update + // compute framerate of 2d render window update int nMilliseconds = m_Clock3d.restart(); int fps = 10000.0f / (nMilliseconds); m_FPS3d = fps; m_FrameCounter3d = 0; } } void UltrasoundSupport::OnChangedFramerateLimit() { StopTimers(); int intervalPipeline = (1000 / m_Controls.m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls.m_FrameRate2d->value()); int interval3D = (1000 / m_Controls.m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline, interval2D, interval3D); StartTimers(); } void UltrasoundSupport::OnClickedFreezeButton() { if (m_Device.IsNull()) { MITK_WARN("UltrasoundSupport") << "Freeze button clicked though no device is selected."; return; } if (m_Device->GetIsFreezed()) { m_Device->SetIsFreezed(false); m_Controls.m_FreezeButton->setText("Freeze"); } else { m_Device->SetIsFreezed(true); m_Controls.m_FreezeButton->setText("Start Viewing Again"); } } void UltrasoundSupport::OnChangedActiveDevice() { - //clean up and stop timer + //clean up, delete nodes and stop timer StopTimers(); this->RemoveControlWidgets(); - this->GetDataStorage()->Remove(m_Node); - m_Node->ReleaseData(); + for (auto& Node : m_Node) + { + this->GetDataStorage()->Remove(Node); + Node->ReleaseData(); + } + m_Node.clear(); //get current device, abort if it is invalid m_Device = m_Controls.m_ActiveVideoDevices->GetSelectedService(); if (m_Device.IsNull()) { m_Controls.tabWidget->setTabEnabled(1, false); return; } //create the widgets for this device and enable the widget tab this->CreateControlWidgets(); m_Controls.tabWidget->setTabEnabled(1, true); - //show node if the option is enabled - if (m_Controls.m_ShowImageStream->isChecked()) - { - this->GetDataStorage()->Add(m_Node); - } - //start timer if (m_Controls.m_RunImageTimer->isChecked()) { int intervalPipeline = (1000 / m_Controls.m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls.m_FrameRate2d->value()); int interval3D = (1000 / m_Controls.m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline, interval2D, interval3D); StartTimers(); m_Controls.m_TimerWidget->setEnabled(true); } else { m_Controls.m_TimerWidget->setEnabled(false); } } void UltrasoundSupport::OnNewDeviceWidgetDone() { m_Controls.m_NewVideoDeviceWidget->setVisible(false); m_Controls.m_DeviceManagerWidget->setVisible(true); m_Controls.m_Headline->setText("Ultrasound Devices:"); m_Controls.m_WidgetActiveDevices->setVisible(true); } void UltrasoundSupport::CreateControlWidgets() { m_ControlProbesWidget = new QmitkUSControlsProbesWidget(m_Device->GetControlInterfaceProbes(), m_Controls.m_ToolBoxControlWidgets); m_Controls.probesWidgetContainer->addWidget(m_ControlProbesWidget); // create b mode widget for current device m_ControlBModeWidget = new QmitkUSControlsBModeWidget(m_Device->GetControlInterfaceBMode(), m_Controls.m_ToolBoxControlWidgets); - m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlBModeWidget, "B Mode Controls"); - if (!m_Device->GetControlInterfaceBMode()) + + if (m_Device->GetControlInterfaceBMode()) { - m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); + m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlBModeWidget, "B Mode Controls"); + //m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); } // create doppler widget for current device m_ControlDopplerWidget = new QmitkUSControlsDopplerWidget(m_Device->GetControlInterfaceDoppler(), m_Controls.m_ToolBoxControlWidgets); - m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlDopplerWidget, "Doppler Controls"); - if (!m_Device->GetControlInterfaceDoppler()) + + if (m_Device->GetControlInterfaceDoppler()) { - m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); + m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlDopplerWidget, "Doppler Controls"); + //m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); } ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { std::string filter = "(ork.mitk.services.UltrasoundCustomWidget.deviceClass=" + m_Device->GetDeviceClass() + ")"; QString interfaceName = QString::fromStdString(us_service_interface_iid()); m_CustomWidgetServiceReference = pluginContext->getServiceReferences(interfaceName, QString::fromStdString(filter)); if (m_CustomWidgetServiceReference.size() > 0) { m_ControlCustomWidget = pluginContext->getService (m_CustomWidgetServiceReference.at(0))->CloneForQt(m_Controls.tab2); m_ControlCustomWidget->SetDevice(m_Device); m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlCustomWidget, "Custom Controls"); } else { m_Controls.m_ToolBoxControlWidgets->addItem(new QWidget(m_Controls.m_ToolBoxControlWidgets), "Custom Controls"); m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); } } // select first enabled control widget for (int n = 0; n < m_Controls.m_ToolBoxControlWidgets->count(); ++n) { if (m_Controls.m_ToolBoxControlWidgets->isItemEnabled(n)) { m_Controls.m_ToolBoxControlWidgets->setCurrentIndex(n); break; } } } void UltrasoundSupport::RemoveControlWidgets() { if (!m_ControlProbesWidget) { return; } //widgets do not exist... nothing to do // remove all control widgets from the tool box widget while (m_Controls.m_ToolBoxControlWidgets->count() > 0) { m_Controls.m_ToolBoxControlWidgets->removeItem(0); } // remove probes widget (which is not part of the tool box widget) m_Controls.probesWidgetContainer->removeWidget(m_ControlProbesWidget); delete m_ControlProbesWidget; m_ControlProbesWidget = 0; delete m_ControlBModeWidget; m_ControlBModeWidget = 0; delete m_ControlDopplerWidget; m_ControlDopplerWidget = 0; // delete custom widget if it is present if (m_ControlCustomWidget) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); delete m_ControlCustomWidget; m_ControlCustomWidget = 0; if (m_CustomWidgetServiceReference.size() > 0) { pluginContext->ungetService(m_CustomWidgetServiceReference.at(0)); } } } void UltrasoundSupport::OnDeciveServiceEvent(const ctkServiceEvent event) { if (m_Device.IsNull() || event.getType() != static_cast(us::ServiceEvent::MODIFIED)) { return; } ctkServiceReference service = event.getServiceReference(); if (m_Device->GetManufacturer() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER)).toString().toStdString() && m_Device->GetName() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME)).toString().toStdString()) { return; } if (!m_Device->GetIsActive() && m_UpdateTimer->isActive()) { StopTimers(); } if (m_CurrentDynamicRange != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble()) { m_CurrentDynamicRange = service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble(); // update level window for the current dynamic range mitk::LevelWindow levelWindow; - m_Node->GetLevelWindow(levelWindow); - levelWindow.SetAuto(m_Image, true, true); - m_Node->SetLevelWindow(levelWindow); + for (auto& Node : m_Node) + { + Node->GetLevelWindow(levelWindow); + levelWindow.SetAuto(m_Image, true, true); + levelWindow.SetWindowBounds(55, 125,true); + Node->SetLevelWindow(levelWindow); + } } } UltrasoundSupport::UltrasoundSupport() : m_ControlCustomWidget(0), m_ControlBModeWidget(0), m_ControlProbesWidget(0), m_ImageAlreadySetToNode(false), - m_CurrentImageWidth(0), m_CurrentImageHeight(0) + m_CurrentImageWidth(0), m_CurrentImageHeight(0), m_AmountOfOutputs(0) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { // to be notified about service event of an USDevice pluginContext->connectServiceListener(this, "OnDeciveServiceEvent", QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")")); } } UltrasoundSupport::~UltrasoundSupport() { try { StoreUISettings(); StopTimers(); // Get all active devicesand deactivate them to prevent freeze for (auto device : this->m_Controls.m_ActiveVideoDevices->GetAllServices()) { if (device != nullptr && device->GetIsActive()) { device->Deactivate(); device->Disconnect(); } } } catch (std::exception &e) { MITK_ERROR << "Exception during call of destructor! Message: " << e.what(); } } void UltrasoundSupport::StoreUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); settings.setValue("DisplayImage", QVariant(m_Controls.m_ShowImageStream->isChecked())); settings.setValue("RunImageTimer", QVariant(m_Controls.m_RunImageTimer->isChecked())); settings.setValue("Update2DView", QVariant(m_Controls.m_Update2DView->isChecked())); settings.setValue("Update3DView", QVariant(m_Controls.m_Update3DView->isChecked())); settings.setValue("UpdateRatePipeline", QVariant(m_Controls.m_FrameRatePipeline->value())); settings.setValue("UpdateRate2d", QVariant(m_Controls.m_FrameRate2d->value())); settings.setValue("UpdateRate3d", QVariant(m_Controls.m_FrameRate3d->value())); settings.endGroup(); } void UltrasoundSupport::LoadUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); m_Controls.m_ShowImageStream->setChecked(settings.value("DisplayImage", true).toBool()); m_Controls.m_RunImageTimer->setChecked(settings.value("RunImageTimer", true).toBool()); m_Controls.m_Update2DView->setChecked(settings.value("Update2DView", true).toBool()); m_Controls.m_Update3DView->setChecked(settings.value("Update3DView", true).toBool()); m_Controls.m_FrameRatePipeline->setValue(settings.value("UpdateRatePipeline", 50).toInt()); m_Controls.m_FrameRate2d->setValue(settings.value("UpdateRate2d", 20).toInt()); m_Controls.m_FrameRate3d->setValue(settings.value("UpdateRate3d", 5).toInt()); settings.endGroup(); } void UltrasoundSupport::StartTimers() { m_UpdateTimer->start(); if (m_Controls.m_Update2DView->isChecked()) { m_RenderingTimer2d->start(); } if (m_Controls.m_Update3DView->isChecked()) { m_RenderingTimer3d->start(); } } void UltrasoundSupport::StopTimers() { m_UpdateTimer->stop(); m_RenderingTimer2d->stop(); m_RenderingTimer3d->stop(); } void UltrasoundSupport::SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D) { m_UpdateTimer->setInterval(intervalPipeline); m_RenderingTimer2d->setInterval(interval2D); m_RenderingTimer3d->setInterval(interval3D); } diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h index 9e712a3f0c..a85abcc9df 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h @@ -1,149 +1,166 @@ /*=================================================================== 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. ===================================================================*/ #ifndef UltrasoundSupport_h #define UltrasoundSupport_h +#include +#include + #include #include #include "ui_UltrasoundSupportControls.h" #include "QmitkUSAbstractCustomWidget.h" #include "QmitkUSControlsBModeWidget.h" #include "QmitkUSControlsDopplerWidget.h" #include "QmitkUSControlsProbesWidget.h" #include #include /*! \brief UltrasoundSupport This plugin provides functionality to manage Ultrasound devices, create video devices and to view device images. \ingroup ${plugin_target}_internal */ class UltrasoundSupport : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: virtual void SetFocus() override; static const std::string VIEW_ID; virtual void CreateQtPartControl(QWidget *parent) override; UltrasoundSupport(); virtual ~UltrasoundSupport(); public slots: /* * \brief This is called when the newDeviceWidget is closed */ void OnNewDeviceWidgetDone(); protected slots: void OnClickedAddNewDevice(); void OnChangedFramerateLimit(); void OnClickedEditDevice(); /* *\brief Called, when the selection in the list of the active devices changes. */ void OnChangedActiveDevice(); void OnClickedFreezeButton(); void OnDeciveServiceEvent(const ctkServiceEvent event); /* * \brief This is the main imaging loop that updates the image and is called regularily during the imaging process */ void UpdateImage(); void RenderImage2d(); void RenderImage3d(); void StartTimers(); void StopTimers(); protected: void CreateControlWidgets(); void RemoveControlWidgets(); /** The device that is currently used to aquire images */ mitk::USDevice::Pointer m_Device; void SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D); /** This timer triggers periodic updates to the pipeline */ QTimer* m_UpdateTimer; QTimer* m_RenderingTimer2d; QTimer* m_RenderingTimer3d; /** These clocks are used to compute the framerate in the methods DisplayImage(),RenderImage2d() and RenderImage3d(). */ QTime m_Clock; QTime m_Clock2d; QTime m_Clock3d; /** A counter to comute the framerate. */ int m_FrameCounterPipeline; int m_FrameCounter2d; int m_FrameCounter3d; int m_FPSPipeline, m_FPS2d, m_FPS3d; /** Stores the properties of some QWidgets (and the tool storage file name) to QSettings.*/ void StoreUISettings(); /** Loads the properties of some QWidgets (and the tool storage file name) from QSettings.*/ void LoadUISettings(); - /** The node that we feed images into.*/ - mitk::DataNode::Pointer m_Node; - - /** The image that is hold by the node above.*/ - mitk::Image::Pointer m_Image; + /** The nodes that we feed images into.*/ + std::vector m_Node; + /** Adds a new node to the m_Nodes vector*/ + void InitNewNode(); + /** Destroys the last node in the m_Nodes vector */ + void DestroyLastNode(); + /** Checks the amount of slices in the image from the USDevice and creates as many Nodes as there are slices */ + void UpdateAmountOfOutputs(); + + /** This function just checks how many nodes there are currently and sets the laser image to a jet transparent colormap. */ + void UpdateColormaps(); + void SetColormap(mitk::DataNode::Pointer node, mitk::LookupTable::LookupTableType type); + + /** The image that holds all data given by the USDevice.*/ + mitk::Image::Pointer m_Image; + /** The seperated slices from m_Image */ + std::vector m_curOutput; + /** Keeps track of the amount of output Nodes*/ + int m_AmountOfOutputs; /** The old geometry of m_Image. It is needed to check if the geometry changed (e.g. because * the zoom factor was modified) and the image needs to be reinitialized. */ mitk::SlicedGeometry3D::Pointer m_OldGeometry; Ui::UltrasoundSupportControls m_Controls; QmitkUSAbstractCustomWidget* m_ControlCustomWidget; QmitkUSControlsBModeWidget* m_ControlBModeWidget; QmitkUSControlsDopplerWidget* m_ControlDopplerWidget; QmitkUSControlsProbesWidget* m_ControlProbesWidget; QList m_CustomWidgetServiceReference; bool m_ImageAlreadySetToNode; unsigned int m_CurrentImageWidth; unsigned int m_CurrentImageHeight; double m_CurrentDynamicRange; }; #endif // UltrasoundSupport_h diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupportControls.ui b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupportControls.ui index 0043b03043..82f7fa1f3d 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupportControls.ui +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupportControls.ui @@ -1,391 +1,412 @@ UltrasoundSupportControls 0 0 407 820 0 0 QmitkTemplate - + + 2 + + + 2 + + + 2 + + 2 - 0 + 1 true false false :/USUI/ultrasound01-probe-300ppi.png :/USUI/ultrasound01-probe-300ppi.png:/USUI/ultrasound01-probe-300ppi.png Device Management - + + 0 + + + 0 + + + 0 + + 0 10 75 true Ultrasound Devices: 10 75 true Active Devices: 0 0 Show US image in MITK true Qt::Vertical 20 40 false :/USUI/ultrasound02-scan-300ppi.png :/USUI/ultrasound02-scan-72ppi-deactivated.png :/USUI/ultrasound02-scan-300ppi.png:/USUI/ultrasound02-scan-300ppi.png US Imaging Qt::Vertical 20 40 Qt::Horizontal Update Image Data Automatically true Freeze :/USUI/system-lock-screen.png:/USUI/system-lock-screen.png <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Framrate Settings:</span></p></body></html> Current overall Framerate: 0 FPS Image Pipeline Framerate Limit [FPS]: Qt::Horizontal 40 20 1 500 50 Update 2D View - true + false + + + false Qt::Horizontal 40 20 Framerate Limit [FPS]: 1 100 20 Update 3D View - true + false Qt::Horizontal 18 20 Framerate Limit [FPS]: 1 100 5 QmitkUSDeviceManagerWidget QWidget
QmitkUSDeviceManagerWidget.h
1
QmitkUSNewVideoDeviceWidget QWidget
QmitkUSNewVideoDeviceWidget.h
1
QmitkServiceListWidget QWidget
QmitkServiceListWidget.h
1