UsTK : Ultrasound ToolKit  version 2.0.1 under development (2023-12-07)
usNetworkGrabberPreScan2D.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ustk software.
4  * Copyright (C) 2016 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ustk with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * This software was developed at:
17  * Inria Rennes - Bretagne Atlantique
18  * Campus Universitaire de Beaulieu
19  * 35042 Rennes Cedex
20  * France
21  *
22  * If you have questions regarding the use of this file, please contact
23  * Inria at ustk@inria.fr
24  *
25  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27  *
28  * Authors:
29  * Pedro Patlan
30  * Marc Pouliquen
31  *
32  *****************************************************************************/
33 
34 #include <visp3/ustk_grabber/usNetworkGrabberPreScan2D.h>
35 
36 #if defined(USTK_HAVE_QT5) || defined(USTK_HAVE_VTK_QT)
37 
38 #include <QtCore/QDataStream>
39 #include <QtCore/QEventLoop>
40 #include <visp3/ustk_core/usImageIo.h>
41 
46 {
47  m_grabbedImage.init(0, 0);
48 
49  // buffer of size 3
50  m_outputBuffer.push_back(new usFrameGrabbedInfo<usImagePreScan2D<unsigned char> >);
51  m_outputBuffer.push_back(new usFrameGrabbedInfo<usImagePreScan2D<unsigned char> >);
52  m_outputBuffer.push_back(new usFrameGrabbedInfo<usImagePreScan2D<unsigned char> >);
53 
54  m_firstFrameAvailable = false;
55 
56  m_recordingOn = false;
57  m_firstImageTimestamp = 0;
58 
59  connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(dataArrived()));
60 }
61 
66 
72 {
74  QDataStream in;
75  in.setDevice(m_tcpSocket);
76 #if (defined(USTK_HAVE_QT5) || defined(USTK_HAVE_VTK_QT5))
77  in.setVersion(QDataStream::Qt_5_0);
78 #elif defined(USTK_HAVE_VTK_QT4)
79  in.setVersion(QDataStream::Qt_4_8);
80 #else
81  throw(vpException(vpException::fatalError, "your Qt version is not managed in ustk"));
82 #endif
83 
84  int headerType;
85  if (m_bytesLeftToRead == 0) { // do not try to read a header if last frame was not complete
86  in >> headerType;
87  if (m_verbose)
88  std::cout << "header received, type = " << headerType << std::endl;
89  } else {
90  headerType = 0; // not a header received, but a part of a frame
91  }
92  // init confirm header received
93  if (headerType == m_confirmHeader.headerId) {
94  // read whole header
95  in >> m_confirmHeader.initOk;
97 
98  if (m_confirmHeader.initOk == 0) {
99  m_tcpSocket->close();
100  throw(vpException(vpException::fatalError, "porta initialisation error closing connection."));
101  }
102  if (m_verbose)
103  std::cout << "porta init sucess, detected probe id = " << m_confirmHeader.probeId << std::endl;
104 
105  // read all acquisition parameters received
107 
109  }
110 
111  // image header received
112  else if (headerType == m_imageHeader.headerId) {
113  // read whole header
115  quint64 timestamp;
116  in >> timestamp;
117  m_imageHeader.timeStamp = timestamp;
118 
119  if (m_imageHeader.frameCount == 0) // used to save the sequence
120  m_firstImageTimestamp = timestamp;
121 
122  in >> m_imageHeader.dataRate;
124  in >> m_imageHeader.ss;
125  in >> m_imageHeader.imageType;
132 
140  in >> m_imageHeader.motorType;
141 
142  if (m_verbose) {
143  std::cout << "frameCount = " << m_imageHeader.frameCount << std::endl;
144  std::cout << "timeStamp = " << m_imageHeader.timeStamp << std::endl;
145  std::cout << "dataRate = " << m_imageHeader.dataRate << std::endl;
146  std::cout << "dataLength = " << m_imageHeader.dataLength << std::endl;
147  std::cout << "ss = " << m_imageHeader.ss << std::endl;
148  std::cout << "imageType = " << m_imageHeader.imageType << std::endl;
149  std::cout << "frameWidth = " << m_imageHeader.frameWidth << std::endl;
150  std::cout << "frameHeight = " << m_imageHeader.frameHeight << std::endl;
151  std::cout << "pixelWidth = " << m_imageHeader.pixelWidth << std::endl;
152  std::cout << "pixelHeight = " << m_imageHeader.pixelHeight << std::endl;
153  std::cout << "transmitFrequency = " << m_imageHeader.transmitFrequency << std::endl;
154  std::cout << "samplingFrequency = " << m_imageHeader.samplingFrequency << std::endl;
155  std::cout << "transducerRadius = " << m_imageHeader.transducerRadius << std::endl;
156  std::cout << "scanLinePitch = " << m_imageHeader.scanLinePitch << std::endl;
157  std::cout << "scanLineNumber = " << m_imageHeader.scanLineNumber << std::endl;
158  std::cout << "imageDepth = " << m_imageHeader.imageDepth << std::endl;
159  std::cout << "anglePerFr = " << m_imageHeader.anglePerFr << std::endl;
160  std::cout << "framesPerVolume = " << m_imageHeader.framesPerVolume << std::endl;
161  std::cout << "motorRadius = " << m_imageHeader.motorRadius << std::endl;
162  std::cout << "motorType = " << m_imageHeader.motorType << std::endl;
163  }
164 
165  // update transducer settings with image header received
168  m_grabbedImage.setDepth(m_imageHeader.imageDepth / 1000.0);
169  m_grabbedImage.setAxialResolution(m_grabbedImage.getDepth() / m_imageHeader.frameHeight);
173 
174  // set data info
175  m_grabbedImage.setFrameCount(m_imageHeader.frameCount);
177  m_grabbedImage.setTimeStamp(m_imageHeader.timeStamp);
178 
179  // warning if timestamps are close (< 1 ms)
180  if (m_outputBuffer.at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->getTimeStamp() -
181  m_outputBuffer.at(MOST_RECENT_FRAME_POSITION_IN_VEC)->getTimeStamp() <
182  1) {
183  std::cout << "WARNING : new image received with an acquisition timestamp close to previous image" << std::endl;
184  }
185 
187 
189 
190  m_bytesLeftToRead -= in.readRawData((char *)m_grabbedImage.bitmap, m_imageHeader.dataLength);
191 
192  if (m_bytesLeftToRead == 0) { // we've read all the frame in 1 packet.
193  invertRowsCols();
194  }
195  if (m_verbose)
196  std::cout << "Bytes left to read for whole frame = " << m_bytesLeftToRead << std::endl;
197 
198  }
199 
200  // we have a part of the image still not read (arrived with next tcp packet)
201  else {
202  if (m_verbose) {
203  std::cout << "reading following part of the frame" << std::endl;
204  std::cout << "local image size = " << m_grabbedImage.getSize() << std::endl;
205  }
206  m_bytesLeftToRead -= in.readRawData((char *)m_grabbedImage.bitmap + (m_grabbedImage.getSize() - m_bytesLeftToRead),
208 
209  if (m_bytesLeftToRead == 0) { // we've read the last part of the frame.
210  invertRowsCols();
211  }
212  }
213 }
214 
219 {
220  // At this point, CURRENT_FILLED_FRAME_POSITION_IN_VEC is going to be filled
221  m_outputBuffer.at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setImagePreScanSettings(m_grabbedImage);
222 
223  m_outputBuffer.at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setFrameCount(m_grabbedImage.getFrameCount());
224  m_outputBuffer.at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setFramesPerVolume(m_grabbedImage.getFramesPerVolume());
225  m_outputBuffer.at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setTimeStamp(m_grabbedImage.getTimeStamp());
226 
227  m_outputBuffer.at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)
228  ->resize(m_grabbedImage.getWidth(), m_grabbedImage.getHeight());
229 
230  for (unsigned int i = 0; i < m_grabbedImage.getHeight(); i++)
231  for (unsigned int j = 0; j < m_grabbedImage.getWidth(); j++)
232  (*m_outputBuffer.at(CURRENT_FILLED_FRAME_POSITION_IN_VEC))(j, i, m_grabbedImage(i, j));
233 
234  // Now CURRENT_FILLED_FRAME_POSITION_IN_VEC has become the last frame received
235  // So we switch pointers beween MOST_RECENT_FRAME_POSITION_IN_VEC and CURRENT_FILLED_FRAME_POSITION_IN_VEC
237  m_outputBuffer.at(CURRENT_FILLED_FRAME_POSITION_IN_VEC);
238  m_outputBuffer.at(CURRENT_FILLED_FRAME_POSITION_IN_VEC) = m_outputBuffer.at(MOST_RECENT_FRAME_POSITION_IN_VEC);
239  m_outputBuffer.at(MOST_RECENT_FRAME_POSITION_IN_VEC) = savePtr;
240  if (m_recordingOn)
241  m_sequenceWriter.write(*m_outputBuffer.at(MOST_RECENT_FRAME_POSITION_IN_VEC),
242  m_outputBuffer.at(MOST_RECENT_FRAME_POSITION_IN_VEC)->getTimeStamp() -
243  m_firstImageTimestamp);
244 
245  m_firstFrameAvailable = true;
246  emit(newFrameAvailable());
247  emit(newFrame(*m_outputBuffer.at(MOST_RECENT_FRAME_POSITION_IN_VEC)));
248 }
249 
257 {
258  // manage first frame or if user grabs too fast
259  if (!m_firstFrameAvailable ||
260  m_outputBuffer.at(OUTPUT_FRAME_POSITION_IN_VEC)->getFrameCount() >=
261  m_outputBuffer.at(MOST_RECENT_FRAME_POSITION_IN_VEC)->getFrameCount()) {
262  // we wait until a new frame is available
263  QEventLoop loop;
264  loop.connect(this, SIGNAL(newFrameAvailable()), SLOT(quit()));
265  loop.exec();
266  }
267 
268  // switch pointers
270  m_outputBuffer.at(OUTPUT_FRAME_POSITION_IN_VEC) = m_outputBuffer.at(MOST_RECENT_FRAME_POSITION_IN_VEC);
271  m_outputBuffer.at(MOST_RECENT_FRAME_POSITION_IN_VEC) = savePtr;
272 
273  return m_outputBuffer.at(OUTPUT_FRAME_POSITION_IN_VEC);
274 }
275 
282 {
283  for (unsigned int i = 0; i < m_outputBuffer.size(); i++)
284  m_outputBuffer.at(i)->display = display;
285 }
286 
292 {
293  m_recordingOn = true;
294  m_sequenceWriter.setSequenceDirectory(path);
295 }
296 
300 void usNetworkGrabberPreScan2D::stopRecording() { m_recordingOn = false; }
301 
302 #endif
Class to store additionnal informations arriving on the network with ultrasound images grabbed,...
quint64 getTimeStamp() const
quint32 getFrameCount() const
void setFramesPerVolume(int framesPerVolume)
int getFramesPerVolume() const
void setTimeStamp(quint64 timeStamp)
void setFrameCount(quint32 frameCount)
void resize(const unsigned int h, const unsigned int w)
void setAxialResolution(const double axialResolution)
void setSequenceDirectory(const std::string sequenceDirectory)
void write(const usImageRF2D< short int > &image, const uint64_t timestamp)
void activateRecording(std::string path)
usNetworkGrabberPreScan2D(usNetworkGrabber *parent=0)
usFrameGrabbedInfo< usImagePreScan2D< unsigned char > > * acquire()
void useVpDisplay(vpDisplay *display)
void newFrame(usImagePreScan2D< unsigned char > image)
Generic abstract class to manage tcp connection to grab ultrasound frames (on port 8080).
usInitHeaderConfirmation m_confirmHeader
@ CURRENT_FILLED_FRAME_POSITION_IN_VEC
void readAcquisitionParameters(QDataStream &stream)
void serverUpdateEnded(bool success)
us::usImageHeader m_imageHeader
QTcpSocket * m_tcpSocket
void setTransducerConvexity(const bool isTransducerConvex)
void setDepth(double depth)
void setScanLinePitch(const double scanLinePitch)
void setTransmitFrequency(const int transmitFrequency)
void setSamplingFrequency(const int samplingFrequency)
void setTransducerRadius(const double transducerRadius)
int motorType
Definition: us.h:120
double anglePerFr
Definition: us.h:117
int dataLength
Definition: us.h:89
int frameWidth
Definition: us.h:94
double dataRate
Definition: us.h:87
unsigned int scanLineNumber
Definition: us.h:109
int imageDepth
Definition: us.h:110
uint32_t frameCount
Definition: us.h:84
int samplingFrequency
Definition: us.h:101
int framesPerVolume
Definition: us.h:118
double pixelHeight
Definition: us.h:98
double motorRadius
Definition: us.h:119
int transmitFrequency
Definition: us.h:100
int frameHeight
Definition: us.h:95
int imageType
Definition: us.h:92
double pixelWidth
Definition: us.h:97
int headerId
Definition: us.h:81
uint64_t timeStamp
Definition: us.h:85
double transducerRadius
Definition: us.h:107
double scanLinePitch
Definition: us.h:108