34 #include <visp3/ustk_core/usPreScanToPostScan3DConverter.h>
36 #ifdef VISP_HAVE_OPENMP
41 extern void GPUDirectConversionWrapper(
unsigned char *dataPost,
const unsigned char *dataPre,
unsigned int m_nbX,
unsigned int m_nbY,
unsigned int m_nbZ,
int X,
int Y,
int Z,
double m_resolution,
double xmax,
double ymin,
double zmax,
unsigned int frameNumber,
unsigned int scanLineNumber,
double transducerRadius,
double motorRadius,
double scanLinePitch,
double axialResolution,
double framePitch,
bool sweepInZdirection);
48 : m_converterOptimizationMethod(SINGLE_THREAD_REDUCED_LOOKUP_TABLE),
49 m_conversionOptimizationMethodUsedAtInit(SINGLE_THREAD_DIRECT_CONVERSION), m_GPULookupTables{NULL, NULL}, m_GPULookupTablesSize{0,0}, m_VpreScan(), m_downSamplingFactor(1),
50 m_resolution(), m_SweepInZdirection(true), m_initDone(false)
61 : m_VpreScan(), m_downSamplingFactor(1), m_resolution(), m_SweepInZdirection(true), m_initDone(false)
63 this->
init(preScanImage, down);
74 throw(vpException(vpException::functionNotImplementedError,
75 "3D scan-conversion available only for convex transducer and tilting motor"));
78 throw(vpException(vpException::badValue,
"downsampling factor should b positive"));
104 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord(0.0, X, Z, &ymin, NULL, NULL);
105 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord((
double)Y, X / 2.0, Z / 2.0, &ymax, NULL, NULL);
106 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord((
double)Y, (
double)X, Z / 2.0, NULL, &xmax, NULL);
107 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord((
double)Y, X / 2.0, Z, NULL, NULL, &zmax);
114 unsigned int XY = X * Y;
125 #ifdef USTK_HAVE_CUDA
126 this->GPUFreeLookupTables();
141 long int LUTmaxSize = (
long int)
m_nbX * (
long int)
m_nbY * (
long int)
m_nbZ;
145 }
catch (std::exception &e) {
146 throw vpException(vpException::ioError,
"usPreScanToPostScan3DConverter::init: using method "
147 "SINGLE_THREAD_FULL_LOOKUP_TABLE leads to %s \n Use another optimization "
148 "method or downsample the volume",
151 for (
unsigned int sweepingDirection = 0; sweepingDirection < 2; sweepingDirection++) {
152 for (
unsigned int x = 0; x <
m_nbX; x++) {
154 for (
unsigned int y = 0; y <
m_nbY; y++) {
156 for (
unsigned int z = 0; z <
m_nbZ; z++) {
159 usPreScanToPostScan3DConverter::convertPostScanCoordToPreScanCoord(yy, xx, zz, &j, &i, &k,
160 sweepingDirection == 0);
162 double ii = floor(i);
163 double jj = floor(j);
164 double kk = floor(k);
166 if (ii >= 0 && jj >= 0 && kk >= 0 && ii + 1 < X && jj + 1 < Y && kk + 1 < Z) {
167 usVoxelWeightAndIndex m;
169 m.m_outputIndex = x +
m_nbX * y + nbXY * z;
178 double v1w1 = v1 * w1;
183 m.m_W[0] = u1 * v1w1;
193 double Xjj1 = X * (jj + 1);
194 double XYKK = XY * kk;
195 double XYKK1 = XY * (kk + 1);
197 m.m_inputIndex[0] = (
unsigned int)(ii + Xjj + XYKK);
198 m.m_inputIndex[1] = (
unsigned int)(ii + 1 + Xjj + XYKK);
199 m.m_inputIndex[2] = (
unsigned int)(ii + Xjj1 + XYKK);
200 m.m_inputIndex[3] = (
unsigned int)(ii + 1 + Xjj1 + XYKK);
201 m.m_inputIndex[4] = (
unsigned int)(ii + Xjj + XYKK1);
202 m.m_inputIndex[5] = (
unsigned int)(ii + 1 + Xjj + XYKK1);
203 m.m_inputIndex[6] = (
unsigned int)(ii + Xjj1 + XYKK1);
204 m.m_inputIndex[7] = (
unsigned int)(ii + 1 + Xjj1 + XYKK1);
212 std::cout <<
"LUT 1 size (bytes) : " <<
sizeof(usVoxelWeightAndIndex) *
m_lookupTables[0].size() << std::endl;
213 std::cout <<
"LUT 2 size (bytes) : " <<
sizeof(usVoxelWeightAndIndex) *
m_lookupTables[1].size() << std::endl;
218 long int LUTmaxSize = (
long int)
m_nbX * (
long int)
m_nbY * (
long int)
m_nbZ;
222 }
catch (std::exception &e) {
223 throw vpException(vpException::ioError,
"usPreScanToPostScan3DConverter::init: using method "
224 "MULTI_THREAD_FULL_LOOKUP_TABLE leads to %s \n Use another optimization "
225 "method or downsample the volume",
229 for (
unsigned int sweepingDirection = 0 ; sweepingDirection < 2 ; sweepingDirection++) {
230 #ifdef VISP_HAVE_OPENMP
231 #pragma omp parallel for
233 for (
int x = 0; x < (int)
m_nbX; x++) {
235 for (
unsigned int y = 0; y <
m_nbY; y++) {
237 for (
unsigned int z = 0; z <
m_nbZ; z++) {
240 usPreScanToPostScan3DConverter::convertPostScanCoordToPreScanCoord(yy, xx, zz, &j, &i, &k,
241 sweepingDirection == 0);
243 double ii = floor(i);
244 double jj = floor(j);
245 double kk = floor(k);
247 if (ii >= 0 && jj >= 0 && kk >= 0 && ii + 1 < X && jj + 1 < Y && kk + 1 < Z) {
248 usVoxelWeightAndIndex m;
250 m.m_outputIndex = x +
m_nbX * y + nbXY * z;
259 double v1w1 = v1 * w1;
264 m.m_W[0] = u1 * v1w1;
274 double Xjj1 = X * (jj + 1);
275 double XYKK = XY * kk;
276 double XYKK1 = XY * (kk + 1);
278 m.m_inputIndex[0] = (
unsigned int)(ii + Xjj + XYKK);
279 m.m_inputIndex[1] = (
unsigned int)(ii + 1 + Xjj + XYKK);
280 m.m_inputIndex[2] = (
unsigned int)(ii + Xjj1 + XYKK);
281 m.m_inputIndex[3] = (
unsigned int)(ii + 1 + Xjj1 + XYKK);
282 m.m_inputIndex[4] = (
unsigned int)(ii + Xjj + XYKK1);
283 m.m_inputIndex[5] = (
unsigned int)(ii + 1 + Xjj + XYKK1);
284 m.m_inputIndex[6] = (
unsigned int)(ii + Xjj1 + XYKK1);
285 m.m_inputIndex[7] = (
unsigned int)(ii + 1 + Xjj1 + XYKK1);
286 #ifdef VISP_HAVE_OPENMP
295 std::cout <<
"LUT 1 size (bytes) : " <<
sizeof(usVoxelWeightAndIndex) *
m_lookupTables[0].size() << std::endl;
296 std::cout <<
"LUT 2 size (bytes) : " <<
sizeof(usVoxelWeightAndIndex) *
m_lookupTables[1].size() << std::endl;
300 #ifdef USTK_HAVE_CUDA
301 this->GPUAllocateFullLookupTables();
302 this->GPUFillFullLookupTables();
303 std::cout <<
"LUT 1 size (bytes) : " <<
sizeof(usVoxelWeightAndIndex) *
m_GPULookupTablesSize[0] << std::endl;
304 std::cout <<
"LUT 2 size (bytes) : " <<
sizeof(usVoxelWeightAndIndex) *
m_GPULookupTablesSize[1] << std::endl;
307 vpException::notImplementedError,
308 "usPreScanToPostScan3DConverter::init: using method GPU_FULL_LOOKUP_TABLE is not implemented yet");
314 long int LUTmaxSize = (
long int)
m_nbX * (
long int)
m_nbY * (
long int)
m_nbZ;
318 }
catch (std::exception &e) {
319 throw vpException(vpException::ioError,
"usPreScanToPostScan3DConverter::init: using method "
320 "SINGLE_THREAD_REDUCED_LOOKUP_TABLE leads to %s \n Use another "
321 "optimization method or downsample the volume",
324 for (
unsigned int sweepingDirection = 0; sweepingDirection < 2; sweepingDirection++) {
325 for (
unsigned int x = 0; x <
m_nbX; x++) {
327 for (
unsigned int y = 0; y <
m_nbY; y++) {
329 for (
unsigned int z = 0; z <
m_nbZ; z++) {
332 usPreScanToPostScan3DConverter::convertPostScanCoordToPreScanCoord(yy, xx, zz, &j, &i, &k,
333 sweepingDirection == 0);
335 double ii = floor(i);
336 double jj = floor(j);
337 double kk = floor(k);
339 if (ii >= 0 && jj >= 0 && kk >= 0 && ii + 1 < X && jj + 1 < Y && kk + 1 < Z) {
340 usVoxelWeightAndIndexReducedMemory m;
342 m.m_outputIndex = x +
m_nbX * y + nbXY * z;
348 m.m_inputIndex = (
unsigned int)(ii + X * jj + XY * kk);
356 std::cout <<
"LUT 1 size (bytes) : " <<
sizeof(usVoxelWeightAndIndexReducedMemory) *
m_reducedLookupTables[0].size()
358 std::cout <<
"LUT 2 size (bytes) : " <<
sizeof(usVoxelWeightAndIndexReducedMemory) *
m_reducedLookupTables[1].size()
364 long int LUTmaxSize = (
long int)
m_nbX * (
long int)
m_nbY * (
long int)
m_nbZ;
368 }
catch (std::exception &e) {
369 throw vpException(vpException::ioError,
"usPreScanToPostScan3DConverter::init: using method "
370 "MULTI_THREAD_REDUCED_LOOKUP_TABLE leads to %s \n Use another "
371 "optimization method or downsample the volume",
374 for (
unsigned int sweepingDirection = 0; sweepingDirection < 2; sweepingDirection++) {
375 #ifdef VISP_HAVE_OPENMP
376 #pragma omp parallel for
378 for (
int x = 0; x < (int)
m_nbX; x++) {
380 for (
unsigned int y = 0; y <
m_nbY; y++) {
382 for (
unsigned int z = 0; z <
m_nbZ; z++) {
385 usPreScanToPostScan3DConverter::convertPostScanCoordToPreScanCoord(yy, xx, zz, &j, &i, &k,
386 sweepingDirection == 0);
388 double ii = floor(i);
389 double jj = floor(j);
390 double kk = floor(k);
392 if (ii >= 0 && jj >= 0 && kk >= 0 && ii + 1 < X && jj + 1 < Y && kk + 1 < Z) {
393 usVoxelWeightAndIndexReducedMemory m;
395 m.m_outputIndex = x +
m_nbX * y + nbXY * z;
401 m.m_inputIndex = (
unsigned int)(ii + X * jj + XY * kk);
402 #ifdef VISP_HAVE_OPENMP
411 std::cout <<
"LUT 1 size (bytes) : " <<
sizeof(usVoxelWeightAndIndexReducedMemory) *
m_reducedLookupTables[0].size()
413 std::cout <<
"LUT 2 size (bytes) : " <<
sizeof(usVoxelWeightAndIndexReducedMemory) *
m_reducedLookupTables[1].size()
418 #ifdef USTK_HAVE_CUDA
419 this->GPUAllocateReducedLookupTables();
420 this->GPUFillReducedLookupTables();
421 std::cout <<
"LUT 1 size (bytes) : " <<
sizeof(usVoxelWeightAndIndexReducedMemory) *
m_GPULookupTablesSize[0] << std::endl;
422 std::cout <<
"LUT 2 size (bytes) : " <<
sizeof(usVoxelWeightAndIndexReducedMemory) *
m_GPULookupTablesSize[1] << std::endl;
425 vpException::notImplementedError,
426 "usPreScanToPostScan3DConverter::init: using method GPU_REDUCED_LOOKUP_TABLE is not implemented yet");
456 unsigned char *dataPost = postScanImage.
getData();
457 const unsigned char *dataPre = preScanImage.
getConstData();
470 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord(0.0, X, Z, &ymin, NULL, NULL);
471 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord((
double)Y, X / 2.0, Z / 2.0, &ymax, NULL, NULL);
472 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord((
double)Y, (
double)X, Z / 2.0, NULL, &xmax,
474 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord((
double)Y, X / 2.0, Z, NULL, NULL, &zmax);
477 unsigned int XY = X * Y;
479 for (
unsigned int x = 0; x <
m_nbX; x++) {
481 for (
unsigned int y = 0; y <
m_nbY; y++) {
483 for (
unsigned int z = 0; z <
m_nbZ; z++) {
486 usPreScanToPostScan3DConverter::convertPostScanCoordToPreScanCoord(yy, xx, zz, &j, &i, &k,
489 double ii = floor(i);
490 double jj = floor(j);
491 double kk = floor(k);
493 if (ii >= 0 && jj >= 0 && kk >= 0 && ii + 1 < X && jj + 1 < Y && kk + 1 < Z) {
502 double v1w1 = v1 * w1;
507 double W[8] = {u1 * v1w1, u * v1w1, u1 * vw1, u * vw1, u1 * v1w, u * v1w, u1 * vw, u * vw};
510 double Xjj1 = X * (jj + 1);
511 double XYKK = XY * kk;
512 double XYKK1 = XY * (kk + 1);
514 unsigned int index[8] = {(
unsigned int)(ii + Xjj + XYKK), (
unsigned int)(ii + 1 + Xjj + XYKK),
515 (
unsigned int)(ii + Xjj1 + XYKK), (
unsigned int)(ii + 1 + Xjj1 + XYKK),
516 (
unsigned int)(ii + Xjj + XYKK1), (
unsigned int)(ii + 1 + Xjj + XYKK1),
517 (
unsigned int)(ii + Xjj1 + XYKK1), (
unsigned int)(ii + 1 + Xjj1 + XYKK1)};
520 for (
int n = 0; n < 8; n++)
521 val += W[n] * dataPre[index[n]];
523 dataPost[x +
m_nbX * y + nbXY * z] = (
unsigned char)val;
540 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord(0.0, X, Z, &ymin, NULL, NULL);
541 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord((
double)Y, X / 2.0, Z / 2.0, &ymax, NULL, NULL);
542 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord((
double)Y, (
double)X, Z / 2.0, NULL, &xmax,
544 usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord((
double)Y, X / 2.0, Z, NULL, NULL, &zmax);
547 unsigned int XY = X * Y;
549 #ifdef VISP_HAVE_OPENMP
550 #pragma omp parallel for
552 for (
int x = 0; x < (int)
m_nbX; x++) {
554 for (
unsigned int y = 0; y <
m_nbY; y++) {
556 for (
unsigned int z = 0; z <
m_nbZ; z++) {
559 usPreScanToPostScan3DConverter::convertPostScanCoordToPreScanCoord(yy, xx, zz, &j, &i, &k,
562 double ii = floor(i);
563 double jj = floor(j);
564 double kk = floor(k);
566 if (ii >= 0 && jj >= 0 && kk >= 0 && ii + 1 < X && jj + 1 < Y && kk + 1 < Z) {
575 double v1w1 = v1 * w1;
580 double W[8] = {u1 * v1w1, u * v1w1, u1 * vw1, u * vw1, u1 * v1w, u * v1w, u1 * vw, u * vw};
583 double Xjj1 = X * (jj + 1);
584 double XYKK = XY * kk;
585 double XYKK1 = XY * (kk + 1);
587 unsigned int index[8] = {(
unsigned int)(ii + Xjj + XYKK), (
unsigned int)(ii + 1 + Xjj + XYKK),
588 (
unsigned int)(ii + Xjj1 + XYKK), (
unsigned int)(ii + 1 + Xjj1 + XYKK),
589 (
unsigned int)(ii + Xjj + XYKK1), (
unsigned int)(ii + 1 + Xjj + XYKK1),
590 (
unsigned int)(ii + Xjj1 + XYKK1), (
unsigned int)(ii + 1 + Xjj1 + XYKK1)};
593 for (
int n = 0; n < 8; n++)
594 val += W[n] * dataPre[index[n]];
595 #ifdef VISP_HAVE_OPENMP
598 dataPost[x +
m_nbX * y + nbXY * z] = (
unsigned char)val;
606 #ifdef USTK_HAVE_CUDA
607 this->GPUDirectConversion(dataPost, dataPre);
610 vpException::notImplementedError,
611 "usPreScanToPostScan3DConverter::convert: using method GPU_DIRECT_CONVERSION is not implemented yet");
619 for (
int j = 0; j < 8; j++)
627 #ifdef VISP_HAVE_OPENMP
628 #pragma omp parallel for
632 for (
int j = 0; j < 8; j++)
639 #ifdef USTK_HAVE_CUDA
640 this->GPUFullLookupTableConversion(dataPost, dataPre);
643 vpException::notImplementedError,
644 "usPreScanToPostScan3DConverter::convert: using method GPU_FULL_LOOKUP_TABLE is not implemented yet");
652 unsigned int XY = X * Y;
662 double v1w1 = v1 * w1;
667 double W[8] = {u1 * v1w1, u * v1w1, u1 * vw1, u * vw1, u1 * v1w, u * v1w, u1 * vw, u * vw};
669 unsigned int index[8] = {m.m_inputIndex, m.m_inputIndex + 1, m.m_inputIndex + X,
670 m.m_inputIndex + 1 + X, m.m_inputIndex + XY, m.m_inputIndex + 1 + XY,
671 m.m_inputIndex + X + XY, m.m_inputIndex + 1 + X + XY};
674 for (
int j = 0; j < 8; j++)
675 val += W[j] * dataPre[index[j]];
676 dataPost[m.m_outputIndex] = (
unsigned char)val;
684 unsigned int XY = X * Y;
685 #ifdef VISP_HAVE_OPENMP
686 #pragma omp parallel for
697 double v1w1 = v1 * w1;
702 double W[8] = {u1 * v1w1, u * v1w1, u1 * vw1, u * vw1, u1 * v1w, u * v1w, u1 * vw, u * vw};
704 unsigned int index[8] = {m.m_inputIndex, m.m_inputIndex + 1, m.m_inputIndex + X,
705 m.m_inputIndex + 1 + X, m.m_inputIndex + XY, m.m_inputIndex + 1 + XY,
706 m.m_inputIndex + X + XY, m.m_inputIndex + 1 + X + XY};
709 for (
int j = 0; j < 8; j++)
710 val += W[j] * dataPre[index[j]];
711 dataPost[m.m_outputIndex] = (
unsigned char)val;
716 #ifdef USTK_HAVE_CUDA
717 this->GPUReducedLookupTableConversion(dataPost, dataPre);
720 vpException::notImplementedError,
721 "usPreScanToPostScan3DConverter::convert: using method GPU_REDUCED_LOOKUP_TABLE is not implemented yet");
753 #ifndef VISP_HAVE_OPENMP
754 std::cout <<
"Warning in usPreScanToPostScan3DConverter::setConverterOptimizationMethod: OpenMP is not available "
755 "to use multi-thread optimization, will use single thread implementation instead."
763 #ifndef USTK_HAVE_CUDA
764 throw vpException(vpException::notImplementedError,
"usPreScanToPostScan3DConverter::"
765 "setConverterOptimizationMethod: cannot use "
766 "GPU conversion without CUDA");
784 void usPreScanToPostScan3DConverter::convertPreScanCoordToPostScanCoord(
double i_preScan,
double j_preScan,
785 double k_preScan,
double *i_postScan,
786 double *j_postScan,
double *k_postScan,
787 bool sweepInZdirection)
801 ((sweepInZdirection ? j_preScan : Nline - 1 - j_preScan) + Nline * k_preScan) / (Nframe * Nline - 1) -
804 const double cPhi = cos(phi);
807 *j_postScan = r * sin(phi);
810 *i_postScan = (r * cPhi - radiusOffset) * cos(theta);
812 *k_postScan = (r * cPhi - radiusOffset) * sin(theta);
826 void usPreScanToPostScan3DConverter::convertPostScanCoordToPreScanCoord(
double i_postScan,
double j_postScan,
827 double k_postScan,
double *i_preScan,
828 double *j_preScan,
double *k_preScan,
829 bool sweepInZdirection)
834 const double rProbe = radiusOffset + sqrt(i_postScan * i_postScan + k_postScan * k_postScan);
835 const double r = sqrt(rProbe * rProbe + j_postScan * j_postScan);
836 const double phi = atan(j_postScan / rProbe);
837 const double theta = atan(k_postScan / i_postScan);
852 (sweepInZdirection ? jtmp : Nline - 1 - jtmp) / Nline;
unsigned int getNumberOfFrames() const
void resize(unsigned int height, unsigned int width, unsigned int numberOfFrames)
Type * getConstData() const
void initData(Type value)
unsigned int getHeight() const
unsigned int getWidth() const
void setElementSpacingZ(double elementSpacingZ)
void setScanLineDepth(double scanLineDepth)
void setElementSpacingX(double elementSpacingX)
void setElementSpacingY(double elementSpacingY)
unsigned int getBModeSampleNumber() const
Settings associated to ultrasound pre-scan images implemented in usImageRF2D, usImageRF3D,...
double getAxialResolution() const
Generic class for 3D ultrasound motor settings associated to the 3D probe used during acquisition.
void setMotorSettings(const usMotorSettings &other)
unsigned int getFrameNumber() const
double getMotorRadius() const
double getFramePitch() const
usMotorType getMotorType() const
std::vector< usVoxelWeightAndIndex > m_lookupTables[2]
usImagePreScan3D< unsigned char > m_VpreScan
void init(const usImagePreScan3D< unsigned char > &preScanImage, double down=1)
usConverterOptimizationMethod m_converterOptimizationMethod
void convert(usImagePostScan3D< unsigned char > &postScanImage, const usImagePreScan3D< unsigned char > &preScanImage)
std::vector< usVoxelWeightAndIndexReducedMemory > m_reducedLookupTables[2]
usConverterOptimizationMethod
@ GPU_REDUCED_LOOKUP_TABLE
@ SINGLE_THREAD_REDUCED_LOOKUP_TABLE
@ MULTI_THREAD_FULL_LOOKUP_TABLE
@ MULTI_THREAD_DIRECT_CONVERSION
@ MULTI_THREAD_REDUCED_LOOKUP_TABLE
@ SINGLE_THREAD_DIRECT_CONVERSION
@ SINGLE_THREAD_FULL_LOOKUP_TABLE
virtual ~usPreScanToPostScan3DConverter()
long int m_GPULookupTablesSize[2]
usConverterOptimizationMethod m_conversionOptimizationMethodUsedAtInit
double m_downSamplingFactor
usPreScanToPostScan3DConverter()
usConverterOptimizationMethod setConverterOptimizationMethod() const
Generic class for 2D ultrasound data common settings associated to the type of probe transducer used ...
double getScanLinePitch() const
bool isTransducerConvex() const
double getTransducerRadius() const
void setTransducerSettings(const usTransducerSettings &other)
unsigned int getScanLineNumber() const