UsTK : Ultrasound ToolKit  version 2.0.1 under development (2023-12-07)
usNetworkGrabberPostScanBiPlan.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/usNetworkGrabberPostScanBiPlan.h>
35 
36 #if defined(USTK_HAVE_QT5) || defined(USTK_HAVE_VTK_QT)
37 
38 #include <QtCore/QDataStream>
39 #include <QtCore/QEventLoop>
40 
45 {
46  // 2 buffers of size 3
47  m_outputBuffer1.push_back(new usFrameGrabbedInfo<usImagePostScan2D<unsigned char> >);
48  m_outputBuffer1.push_back(new usFrameGrabbedInfo<usImagePostScan2D<unsigned char> >);
49  m_outputBuffer1.push_back(new usFrameGrabbedInfo<usImagePostScan2D<unsigned char> >);
50  m_outputBuffer2.push_back(new usFrameGrabbedInfo<usImagePostScan2D<unsigned char> >);
51  m_outputBuffer2.push_back(new usFrameGrabbedInfo<usImagePostScan2D<unsigned char> >);
52  m_outputBuffer2.push_back(new usFrameGrabbedInfo<usImagePostScan2D<unsigned char> >);
53 
54  m_bufferToFill = 1;
55 
56  m_firstFrameAvailable = false;
57 
58  connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(dataArrived()));
59 }
60 
65 
71 {
73  QDataStream in;
74  in.setDevice(m_tcpSocket);
75 #if (defined(USTK_HAVE_QT5) || defined(USTK_HAVE_VTK_QT5))
76  in.setVersion(QDataStream::Qt_5_0);
77 #elif defined(USTK_HAVE_VTK_QT4)
78  in.setVersion(QDataStream::Qt_4_8);
79 #else
80  throw(vpException(vpException::fatalError, "your Qt version is not managed in ustk"));
81 #endif
82 
83  int headerType;
84 
85  // select buffer to write in
86  std::vector<usFrameGrabbedInfo<usImagePostScan2D<unsigned char> > *> *refOnBufferToFill;
87  if (m_bufferToFill == 1) {
88  refOnBufferToFill = &m_outputBuffer1;
89  } else {
90  refOnBufferToFill = &m_outputBuffer2;
91  }
92 
93  if (m_bytesLeftToRead == 0) { // do not try to read a header if last frame was not complete
94  in >> headerType;
95  if (m_verbose)
96  std::cout << "header received, type = " << headerType << std::endl;
97  } else {
98  headerType = 0; // not a header received, but a part of a frame
99  }
100  // init confirm header received
101  if (headerType == m_confirmHeader.headerId) {
102  // read whole header
103  in >> m_confirmHeader.initOk;
104  in >> m_confirmHeader.probeId;
105 
106  if (m_confirmHeader.initOk == 0) {
107  m_tcpSocket->close();
108  throw(vpException(vpException::fatalError, "porta initialisation error, closing connection."));
109  }
110  if (m_verbose)
111  std::cout << "porta init sucess, detected probe id = " << m_confirmHeader.probeId << std::endl;
112 
113  // read all acquisition parameters received
115 
117  }
118 
119  // image header received
120  else if (headerType == m_imageHeader.headerId) {
121  // read whole header
123  quint64 timestamp;
124  in >> timestamp;
125  m_imageHeader.timeStamp = timestamp;
126  in >> m_imageHeader.dataRate;
128  in >> m_imageHeader.ss;
129  in >> m_imageHeader.imageType;
136 
144  in >> m_imageHeader.motorType;
145 
146  if (m_verbose) {
147  std::cout << "frameCount = " << m_imageHeader.frameCount << std::endl;
148  std::cout << "timeStamp = " << m_imageHeader.timeStamp << std::endl;
149  std::cout << "dataRate = " << m_imageHeader.dataRate << std::endl;
150  std::cout << "dataLength = " << m_imageHeader.dataLength << std::endl;
151  std::cout << "ss = " << m_imageHeader.ss << std::endl;
152  std::cout << "imageType = " << m_imageHeader.imageType << std::endl;
153  std::cout << "frameWidth = " << m_imageHeader.frameWidth << std::endl;
154  std::cout << "frameHeight = " << m_imageHeader.frameHeight << std::endl;
155  std::cout << "pixelWidth = " << m_imageHeader.pixelWidth << std::endl;
156  std::cout << "pixelHeight = " << m_imageHeader.pixelHeight << std::endl;
157  std::cout << "transmitFrequency = " << m_imageHeader.transmitFrequency << std::endl;
158  std::cout << "samplingFrequency = " << m_imageHeader.samplingFrequency << std::endl;
159  std::cout << "transducerRadius = " << m_imageHeader.transducerRadius << std::endl;
160  std::cout << "scanLinePitch = " << m_imageHeader.scanLinePitch << std::endl;
161  std::cout << "scanLineNumber = " << m_imageHeader.scanLineNumber << std::endl;
162  std::cout << "imageDepth = " << m_imageHeader.imageDepth << std::endl;
163  std::cout << "anglePerFr = " << m_imageHeader.anglePerFr << std::endl;
164  std::cout << "framesPerVolume = " << m_imageHeader.framesPerVolume << std::endl;
165  std::cout << "motorRadius = " << m_imageHeader.motorRadius << std::endl;
166  std::cout << "motorType = " << m_imageHeader.motorType << std::endl;
167  }
168 
169  // update transducer settings with image header received
170  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setTransducerRadius(m_imageHeader.transducerRadius);
171  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setScanLinePitch(m_imageHeader.scanLinePitch);
172  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setScanLineNumber(m_imageHeader.scanLineNumber);
173  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setDepth(m_imageHeader.imageDepth / 1000.0);
174  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setTransmitFrequency(m_imageHeader.transmitFrequency);
175  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setSamplingFrequency(m_imageHeader.samplingFrequency);
176 
177  // set data info
178  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setFrameCount(m_imageHeader.frameCount);
179  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setFramesPerVolume(m_imageHeader.framesPerVolume);
180  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setTimeStamp(m_imageHeader.timeStamp);
181 
182  // warning if timestamps are close (< 1 ms)
183  if (refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->getTimeStamp() -
184  refOnBufferToFill->at(MOST_RECENT_FRAME_POSITION_IN_VEC)->getTimeStamp() <
185  1) {
186  std::cout << "WARNING : new image received with an acquisition timestamp close to previous image" << std::endl;
187  }
188 
189  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)
191 
192  // pixel size
193  if (refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->getTransducerRadius() > 0) { // convex probe
194  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setWidthResolution(m_imageHeader.pixelWidth);
195 
196  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->setHeightResolution(m_imageHeader.pixelHeight);
197  } else { // linear probe
198  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)
199  ->setWidthResolution(refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->getScanLinePitch() /
200  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->getWidth());
201 
202  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)
203  ->setHeightResolution(refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->getDepth() /
204  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->getHeight());
205  }
206  // read image content
208 
209  m_bytesLeftToRead -= in.readRawData((char *)refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->bitmap,
211 
212  if (m_bytesLeftToRead == 0) { // we've read all the frame in 1 packet.
213  // Now CURRENT_FILLED_FRAME_POSITION_IN_VEC has become the last frame received
214  // So we switch pointers beween MOST_RECENT_FRAME_POSITION_IN_VEC and CURRENT_FILLED_FRAME_POSITION_IN_VEC
215  {
217  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC);
218  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC) =
219  refOnBufferToFill->at(MOST_RECENT_FRAME_POSITION_IN_VEC);
220  refOnBufferToFill->at(MOST_RECENT_FRAME_POSITION_IN_VEC) = savePtr;
221  }
222  m_bufferToFill = (m_bufferToFill == 1) ? 2 : 1;
223  if (m_bufferToFill == 1) { // we just read image 2
224  m_firstFrameAvailable = true;
225  emit(newFrameAvailable());
226  }
227  }
228  if (m_verbose)
229  std::cout << "Bytes left to read for whole frame = " << m_bytesLeftToRead << std::endl;
230 
231  }
232 
233  // we have a part of the image still not read (arrived with next tcp packet)
234  else {
235  if (m_verbose) {
236  std::cout << "reading following part of the frame, left to read = " << m_bytesLeftToRead << std::endl;
237  std::cout << "local image size = " << refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->getSize()
238  << std::endl;
239  }
241  in.readRawData((char *)refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->bitmap +
242  (refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC)->getSize() - m_bytesLeftToRead),
244 
245  if (m_bytesLeftToRead == 0) { // we've read the last part of the frame.
246  // Now CURRENT_FILLED_FRAME_POSITION_IN_VEC has become the last frame received
247  // So we switch pointers beween MOST_RECENT_FRAME_POSITION_IN_VEC and CURRENT_FILLED_FRAME_POSITION_IN_VEC
249  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC);
250  refOnBufferToFill->at(CURRENT_FILLED_FRAME_POSITION_IN_VEC) =
251  refOnBufferToFill->at(MOST_RECENT_FRAME_POSITION_IN_VEC);
252  refOnBufferToFill->at(MOST_RECENT_FRAME_POSITION_IN_VEC) = savePtr;
253  m_bufferToFill = (m_bufferToFill == 1) ? 2 : 1;
254  if (m_bufferToFill == 1) { // we just read image 2
255  m_firstFrameAvailable = true;
256  emit(newFrameAvailable());
257  }
258  }
259  }
260 }
261 
268 std::vector<usFrameGrabbedInfo<usImagePostScan2D<unsigned char> > *> usNetworkGrabberPostScanBiPlan::acquire()
269 {
270  // manage first frame or if user grabs too fast
271  if (!m_firstFrameAvailable ||
272  (m_outputBuffer1.at(OUTPUT_FRAME_POSITION_IN_VEC)->getFrameCount() >=
273  m_outputBuffer1.at(MOST_RECENT_FRAME_POSITION_IN_VEC)->getFrameCount() &&
274  m_outputBuffer2.at(OUTPUT_FRAME_POSITION_IN_VEC)->getFrameCount() >=
275  m_outputBuffer2.at(MOST_RECENT_FRAME_POSITION_IN_VEC)->getFrameCount())) {
276  // we wait until a new frame is available
277  QEventLoop loop;
278  loop.connect(this, SIGNAL(newFrameAvailable()), SLOT(quit()));
279  loop.exec();
280  }
281 
282  // switch pointers
284  m_outputBuffer1.at(OUTPUT_FRAME_POSITION_IN_VEC) = m_outputBuffer1.at(MOST_RECENT_FRAME_POSITION_IN_VEC);
285  m_outputBuffer1.at(MOST_RECENT_FRAME_POSITION_IN_VEC) = savePtr;
286 
287  savePtr = m_outputBuffer2.at(OUTPUT_FRAME_POSITION_IN_VEC);
288  m_outputBuffer2.at(OUTPUT_FRAME_POSITION_IN_VEC) = m_outputBuffer2.at(MOST_RECENT_FRAME_POSITION_IN_VEC);
289  m_outputBuffer2.at(MOST_RECENT_FRAME_POSITION_IN_VEC) = savePtr;
290 
291  // return the pointers on the two images
292  std::vector<usFrameGrabbedInfo<usImagePostScan2D<unsigned char> > *> ret;
293  ret.push_back(m_outputBuffer1.at(OUTPUT_FRAME_POSITION_IN_VEC));
294  ret.push_back(m_outputBuffer2.at(OUTPUT_FRAME_POSITION_IN_VEC));
295 
296  return ret;
297 }
298 
299 #endif
Class to store additionnal informations arriving on the network with ultrasound images grabbed,...
std::vector< usFrameGrabbedInfo< usImagePostScan2D< unsigned char > > * > acquire()
usNetworkGrabberPostScanBiPlan(usNetworkGrabber *parent=0)
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
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