UsTK : Ultrasound ToolKit  version 2.0.1 under development (2023-12-07)
usPostScanToPreScan2DConverter.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  * Pierre Chatelain
30  *
31  *****************************************************************************/
32 
33 #include <visp3/ustk_core/usPostScanToPreScan2DConverter.h>
34 
35 //#include <visp/vpMath.h>
40 
48  const int BModeSampleNumber, const int scanLineNumber)
49 {
50  init(inputSettings, BModeSampleNumber, scanLineNumber);
51 }
52 
57  const int BModeSampleNumber, const int scanLineNumber,
58  const double xResolution, const double yResolution)
59 {
60  init(transducerSettings, BModeSampleNumber, scanLineNumber, xResolution, yResolution);
61 }
62 
67 
75  const int BModeSampleNumber, const int scanLineNumber)
76 {
77  // check if init is necessary
78  if (m_initSettings == (usTransducerSettings)inputSettings && m_xResolution == inputSettings.getWidthResolution() &&
79  m_yResolution == inputSettings.getHeightResolution() && m_scanLineNumber == scanLineNumber &&
80  m_BModeSampleNumber == BModeSampleNumber) {
81  return;
82  }
83 
84  // check resolution to avoir errors
85  if (inputSettings.getHeightResolution() == 0.0 || inputSettings.getWidthResolution() == 0.0)
86  throw(vpException(vpException::notInitialized, "Please fill the post-scan resplution before init the conversion."));
87 
88  // convex transducer scan conversion
89  if (inputSettings.isTransducerConvex()) {
90  double APitch = inputSettings.getDepth() / (double)(BModeSampleNumber);
91  double LPitch = inputSettings.getScanLinePitch() * inputSettings.getTransducerRadius();
92 
93  double r_min = inputSettings.getTransducerRadius();
94  double r_max = (inputSettings.getTransducerRadius() + APitch * BModeSampleNumber);
95  double t_min = -inputSettings.getFieldOfView() / 2.0;
96  // double t_max = - t_min;
97  double x_min = r_min * cos(t_min);
98  // double x_max = r_max;
99  double y_min = r_max * sin(t_min);
100  // double y_max = r_max * sin(t_max);
101 
102  m_iMap.resize(BModeSampleNumber, scanLineNumber);
103  m_jMap.resize(BModeSampleNumber, scanLineNumber);
104 
105  double r, t;
106  for (int u = 0; u < BModeSampleNumber; ++u) {
107  for (int v = 0; v < scanLineNumber; ++v) {
108  r = inputSettings.getTransducerRadius() + APitch * u;
109  t = (v - (scanLineNumber - 1) / 2.0) * LPitch / inputSettings.getTransducerRadius();
110  m_iMap[u][v] = (r * cos(t) - x_min) / inputSettings.getHeightResolution(); // resolution to check
111  m_jMap[u][v] = (r * sin(t) - y_min) / inputSettings.getWidthResolution(); // resolution to check
112  }
113  }
114  m_isInit = true;
115  }
116  // linear transducer scan-conversion
117  else {
118  throw(vpException(vpException::notImplementedError,
119  "Back-scan conversion is not implemented for linear transducer."));
120  }
121  // saving settings
122  m_initSettings = inputSettings;
123  m_xResolution = inputSettings.getWidthResolution();
124  m_yResolution = inputSettings.getHeightResolution();
125  m_scanLineNumber = scanLineNumber;
126  m_BModeSampleNumber = BModeSampleNumber;
127 }
128 
137 void usPostScanToPreScan2DConverter::init(const usTransducerSettings &transducerSettings, const int BModeSampleNumber,
138  const int scanLineNumber, const double xResolution, const double yResolution)
139 {
140  // check if init is necessary
141  if (m_initSettings == transducerSettings && m_xResolution == xResolution && m_yResolution == yResolution &&
142  m_scanLineNumber == scanLineNumber && m_BModeSampleNumber == BModeSampleNumber) {
143  return;
144  }
145 
146  // convex transducer scan conversion
147  if (transducerSettings.isTransducerConvex()) {
148  double APitch = transducerSettings.getDepth() / BModeSampleNumber;
149  double LPitch =
150  transducerSettings.getFieldOfView() * transducerSettings.getTransducerRadius() / (scanLineNumber - 1);
151 
152  double r_min = transducerSettings.getTransducerRadius();
153  double r_max = (transducerSettings.getTransducerRadius() + APitch * BModeSampleNumber);
154  double t_min = -transducerSettings.getFieldOfView() / 2.0;
155  // double t_max = - t_min;
156  double x_min = r_min * cos(t_min);
157  // double x_max = r_max;
158  double y_min = r_max * sin(t_min);
159  // double y_max = r_max * sin(t_max);
160  m_iMap.resize(BModeSampleNumber, scanLineNumber);
161  m_jMap.resize(BModeSampleNumber, scanLineNumber);
162 
163  double r, t;
164  for (int u = 0; u < BModeSampleNumber; ++u) {
165  for (int v = 0; v < scanLineNumber; ++v) {
166  r = transducerSettings.getTransducerRadius() + APitch * u;
167  t = (v - (scanLineNumber - 1) / 2.0) * LPitch / transducerSettings.getTransducerRadius();
168  m_iMap[u][v] = (r * cos(t) - x_min) / yResolution; // to check
169  m_jMap[u][v] = (r * sin(t) - y_min) / xResolution; // to check
170  }
171  }
172  m_isInit = true;
173  }
174  // linear transducer scan-conversion
175  else {
176  // not implemented
177  }
178  // saving settings
179  m_initSettings = transducerSettings;
180  m_xResolution = xResolution;
181  m_yResolution = yResolution;
182  m_scanLineNumber = scanLineNumber;
183  m_BModeSampleNumber = BModeSampleNumber;
184 }
185 
193  usImagePreScan2D<unsigned char> &imageConverted, int preScanSamples)
194 {
195  if (!m_isInit) {
196  init(imageToConvert, preScanSamples, imageToConvert.getScanLineNumber());
197  }
198 
199  imageConverted.setImagePreScanSettings(usImagePreScanSettings(m_initSettings, m_yResolution));
200 
201  imageConverted.setScanLineNumber(m_scanLineNumber);
202  imageConverted.setFieldOfView(m_initSettings.getFieldOfView());
203  imageConverted.setAxialResolution(m_initSettings.getDepth() / m_BModeSampleNumber);
204  imageConverted.setTransducerConvexity(m_initSettings.isTransducerConvex());
205  imageConverted.setTransducerRadius(m_initSettings.getTransducerRadius());
206 
207  imageConverted.resize(m_BModeSampleNumber, m_scanLineNumber);
208  double i, j;
209  for (unsigned int u = 0; u < imageConverted.getBModeSampleNumber(); ++u)
210  for (unsigned int v = 0; v < imageConverted.getScanLineNumber(); ++v) {
211  i = m_iMap[u][v];
212  j = m_jMap[u][v];
213  imageConverted[u][v] = static_cast<unsigned char>(interpolateLinear(imageToConvert, i, j));
214  }
215 }
216 
217 double usPostScanToPreScan2DConverter::interpolateLinear(const vpImage<unsigned char> &I, double x, double y)
218 {
219  int x1 = (int)floor(x);
220  int x2 = (int)ceil(x);
221  int y1 = (int)floor(y);
222  int y2 = (int)ceil(y);
223 
224  if ((0 <= x) && (x < I.getHeight()) && (0 <= y) && (y < I.getWidth())) {
225  double val1, val2;
226  // Check whether the indices are within the image extent
227  if (x1 < 0)
228  ++x1;
229  if (y1 < 0)
230  ++y1;
231  if (x2 >= static_cast<int>(I.getHeight()))
232  --x2;
233  if (y2 >= static_cast<int>(I.getWidth()))
234  --y2;
235 
236  // Check whether the target is on the grid
237  if (x1 == x2) {
238  val1 = I(x1, y1);
239  val2 = I(x1, y2);
240  } else {
241  val1 = (x2 - x) * I(x1, y1) + (x - x1) * I(x2, y1);
242  val2 = (x2 - x) * I(x1, y2) + (x - x1) * I(x2, y2);
243  }
244  if (y1 == y2)
245  return val1;
246  else
247  return (y2 - y) * val1 + (y - y1) * val2;
248  }
249  return 0.0;
250 }
double getHeightResolution() const
double getWidthResolution() const
void resize(const unsigned int h, const unsigned int w)
unsigned int getBModeSampleNumber() const
void setScanLineNumber(unsigned int scanLineNumber)
Settings associated to ultrasound pre-scan images implemented in usImageRF2D, usImageRF3D,...
void setImagePreScanSettings(const usImagePreScanSettings &preScanSettings)
void setAxialResolution(const double axialResolution)
void init(const usImagePostScan2D< unsigned char > &inputSettings, const int BModeSampleNumber, const int scanLineNumber)
void convert(const usImagePostScan2D< unsigned char > &imageToConvert, usImagePreScan2D< unsigned char > &imageConverted, int preScanSamples)
Generic class for 2D ultrasound data common settings associated to the type of probe transducer used ...
void setFieldOfView(double fieldOfView)
void setTransducerConvexity(const bool isTransducerConvex)
void setTransducerRadius(const double transducerRadius)
double getTransducerRadius() const
unsigned int getScanLineNumber() const