diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.cpp index eb99f61ac7..0d04c6376a 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.cpp +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.cpp @@ -1,301 +1,304 @@ /*=================================================================== 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, channelDataSamplesPerChannel, 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); SetInterleaved(m_Interleaved); // update the beamforming parameters... 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; + float tiltStrength = ((m_ScanMode.transmitEventsCount - 1) / 2 - ev) * 10e-9f; 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].BurstCountPerChannel[i] = 3; // Burst with 1 cycle m_ScanMode.TransmitEvents[ev].BurstUseNegativePolarityPerChannel[i] = true; - m_ScanMode.TransmitEvents[ev].transmitEventDelays[i] = 0; + m_ScanMode.TransmitEvents[ev].transmitEventDelays[i] = 2e-6f + (i - numChannels / 2) * tiltStrength; } } 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 = true; // configure reconstruction processing: m_ScanMode.averageSpeedOfSound = 1540; m_ScanMode.computeBeamforming = true; // setup beamforming parameters: SetInterleaved(true); m_ScanMode.reconstructedLinePitchMmOrAngleDegree = 0.3f; m_ScanMode.reconstructionLines = 128; 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 = 75; 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 = false; // 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/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui index 3e803e283d..f45bef1372 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui @@ -1,648 +1,663 @@ QmitkUSControlsCustomDiPhASDeviceWidget 0 0 351 903 Form 0 25 16777215 25 QFrame::WinPanel QFrame::Raised Started Qt::AlignCenter <html><head/><body><p><span style=" font-weight:600;">Record Images</span></p></body></html> Save Beamformed Save Raw 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 16777215 16777215 42 + + 10 + Qt::Horizontal 42 + + 20 + Qt::Horizontal 0 Scan Depth [mm] 1 100 1 Averaging Count false Beamformed Data Image Data 3.000000000000000 200.000000000000000 - 45.000000000000000 + 50.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.010000000000000 0.050000000000000 0.300000000000000 Qt::PreventContextMenu 128 1024 128 128 Samples per Line Reconstructed Lines 1000 1000000 + + 5 + - 1540 + 1480 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 Compensate Energy Values 0.010000000000000 1.200000000000000 0.050000000000000 0.300000000000000 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 + + 11 + + + 2 + 1 Transmit Events true false 1 1.000000000000000 10000.000000000000000 - 1.000000000000000 + 4.000000000000000 Transmit Phase Length [us] Excitation Frequency [MHz] false Interleaved Ultrasound only false - 5 + 6 75 - 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 Qt::Vertical 20 40