UsTK : Ultrasound ToolKit  version 2.0.1 under development (2024-05-20)
usConvolution2d.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 Rosales
30  * Marc Pouliquen
31  *
32  *****************************************************************************/
33 
34 #include <visp3/ustk_elastography/usConvolution2d.h>
35 
36 #if defined(USTK_HAVE_FFTW)
37 
43  : outa(NULL), outb(NULL), outc(NULL), out(NULL), ad(NULL), bd(NULL), p1(), p2(), p3(), m_init(false)
44 {
45 }
46 
52 {
53  fftw_destroy_plan(p1);
54  fftw_destroy_plan(p2);
55  fftw_destroy_plan(p3);
56  delete[] outa;
57  delete[] outb;
58  delete[] outc;
59  delete[] out;
60  delete[] ad;
61  delete[] bd;
62 }
63 
71 void usConvolution2d::init(const vpMatrix &matrix1, const vpMatrix &matrix2)
72 {
73  // check matrix dimentions
74  if (Am != matrix1.getRows() || An != matrix1.getCols() || Bm != matrix2.getRows() || Bn != matrix2.getCols()) {
75 
76  // memory de-allocation to avoid leak
77  delete[] outa;
78  delete[] outb;
79  delete[] outc;
80  delete[] out;
81  delete[] ad;
82  delete[] bd;
83 
84  fftw_destroy_plan(p1);
85  fftw_destroy_plan(p2);
86  fftw_destroy_plan(p3);
87 
88  // re-allocation with new matrices dimentions
89  Am = matrix1.getRows();
90  An = matrix1.getCols();
91  Bm = matrix2.getRows();
92  Bn = matrix2.getCols();
93 
94  h_dst = Am - Bm + 1; // Valid convolution
95  w_dst = An - Bn + 1;
96  hf = Am + Bm - 1; // Full convolution
97  wf = An + Bn - 1;
98 
99  m_R.resize(h_dst, w_dst);
100  m_M1 = matrix1;
101  m_M2 = matrix2;
102 
103  // fftw inputs/outputs arrays
104  ad = new fftw_complex[hf * wf];
105  bd = new fftw_complex[hf * wf];
106  outa = new fftw_complex[hf * wf];
107  outb = new fftw_complex[hf * wf];
108  outc = new fftw_complex[hf * wf];
109  out = new fftw_complex[hf * wf];
110 
111  // fftw plans
112  p1 = fftw_plan_dft_2d(wf, hf, ad, outa, FFTW_FORWARD, FFTW_ESTIMATE);
113  p2 = fftw_plan_dft_2d(wf, hf, bd, outb, FFTW_FORWARD, FFTW_ESTIMATE);
114  p3 = fftw_plan_dft_2d(wf, hf, outc, out, FFTW_BACKWARD, FFTW_ESTIMATE);
115  } else { // init already done with correct matrix dimentions
116  m_M1 = matrix1;
117  m_M2 = matrix2;
118  }
119 
120  padding_zeros();
121  m_init = true;
122 }
123 
130 vpMatrix usConvolution2d::run(const vpMatrix &matrix1, const vpMatrix &matrix2)
131 {
132  init(matrix1, matrix2);
133 
134  fftw_execute(p1);
135  fftw_execute(p2);
136  // Complex product
137  for (unsigned int i = 0; i < wf * hf; ++i) {
138  outc[i][0] = (outa[i][0] * outb[i][0]) - (outa[i][1] * outb[i][1]);
139  outc[i][1] = (outa[i][0] * outb[i][1]) + (outa[i][1] * outb[i][0]);
140  }
141  fftw_execute(p3);
142  // Storing only the valid convolution
143  int startX = vpMath::round((double)(wf - w_dst) / 2.0);
144  int startY = vpMath::round((double)(hf - h_dst) / 2.0);
145  int endX = startX + w_dst;
146  int endY = startY + h_dst;
147  int k = 0;
148  int l;
149  for (int i = startX; i < endX; ++i) {
150  l = 0;
151  for (int j = startY; j < endY; ++j) {
152  // the output of the convolution array (out) is extracted column by column.
153  m_R[l][k] = out[j + i * hf][0] / (double)(wf * hf);
154  l++;
155  }
156  k++;
157  }
158 
159  return m_R;
160 }
161 
162 void usConvolution2d::padding_zeros()
163 {
164  // Padding the two arrays with zeros
165  for (unsigned int i = 0; i < wf; ++i) {
166  for (unsigned int j = 0; j < hf; ++j) {
167  // fftw intput arrays (ad, bd) are filled scanline per scanline (column by column)
168  ad[j + i * hf][0] = ((j < Am) && (i < An)) ? m_M1[j][i] : 0.0;
169  ad[j + i * hf][1] = 0.0;
170  bd[j + i * hf][0] = ((j < Bm) && (i < Bn)) ? m_M2[j][i] : 0.0;
171  bd[j + i * hf][1] = 0.0;
172  }
173  }
174 }
175 #endif // USTK_HAVE_FFTW
vpMatrix run(const vpMatrix &matrix1, const vpMatrix &matrix2)
virtual ~usConvolution2d()
void init(const vpMatrix &matrix1, const vpMatrix &matrix2)