ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ChamferDistanceTransform.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 // system
11 #include <algorithm>
12 #include <cassert>
13 #include <cstring>
14 
15 using namespace cloudViewer;
16 
18 const signed char ForwardNeighbours345[14 * 4] = {
19  -1, -1, -1, 5, 0, -1, -1, 4, 1, -1, -1, 5, -1, 0, -1, 4, 0, 0, -1,
20  3, 1, 0, -1, 4, -1, 1, -1, 5, 0, 1, -1, 4, 1, 1, -1, 5, -1, -1,
21  0, 4, 0, -1, 0, 3, 1, -1, 0, 4, -1, 0, 0, 3, 0, 0, 0, 0};
22 
24 const signed char BackwardNeighbours345[14 * 4] = {
25  0, 0, 0, 0, 1, 0, 0, 3, -1, 1, 0, 4, 0, 1, 0, 3, 1, 1, 0,
26  4, -1, -1, 1, 5, 0, -1, 1, 4, 1, -1, 1, 5, -1, 0, 1, 4, 0, 0,
27  1, 3, 1, 0, 1, 4, -1, 1, 1, 5, 0, 1, 1, 4, 1, 1, 1, 5};
28 
30 const signed char ForwardNeighbours111[14 * 4] = {
31  -1, -1, -1, 1, 0, -1, -1, 1, 1, -1, -1, 1, -1, 0, -1, 1, 0, 0, -1,
32  1, 1, 0, -1, 1, -1, 1, -1, 1, 0, 1, -1, 1, 1, 1, -1, 1, -1, -1,
33  0, 1, 0, -1, 0, 1, 1, -1, 0, 1, -1, 0, 0, 1, 0, 0, 0, 0};
34 
36 const signed char BackwardNeighbours111[14 * 4] = {
37  0, 0, 0, 0, 1, 0, 0, 1, -1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0,
38  1, -1, -1, 1, 1, 0, -1, 1, 1, 1, -1, 1, 1, -1, 0, 1, 1, 0, 0,
39  1, 1, 1, 0, 1, 1, -1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1};
40 
41 // ChamferDistanceTransform::GridElement
42 // ChamferDistanceTransform::propagateDistance( unsigned iStart,
43 // unsigned
44 // jStart,
45 // unsigned kStart,
46 // bool forward,
47 // const signed char neighbours[14][4],
48 // NormalizedProgress* normProgress/*=0*/)
49 //{
50 // assert(!m_grid.empty());
51 //
52 // GridElement* _grid = &(m_grid[pos2index(iStart, jStart, kStart)]);
53 //
54 // //accelerating structure
55 // int neighborShift[14];
56 // {
57 // for (unsigned char v=0; v<14; ++v)
58 // {
59 // neighborShift[v] =
60 // static_cast<int>(neighbours[v][0])
61 //+
62 // static_cast<int>(neighbours[v][1]) * static_cast<int>(m_rowSize) +
63 // static_cast<int>(neighbours[v][2])
64 //* static_cast<int>(m_sliceSize);
65 // }
66 // }
67 //
68 // GridElement maxDist = 0;
69 //
70 // int order = forward ? 1 : -1;
71 //
72 // for (unsigned k=0; k<m_innerSize.z; ++k)
73 // {
74 // for (unsigned j=0; j<m_innerSize.y; ++j)
75 // {
76 // for (unsigned i=0; i<m_innerSize.x; ++i)
77 // {
78 // GridElement minVal = _grid[neighborShift[0]] +
79 // static_cast<GridElement>(neighbours[0][3]);
80 //
81 // for (unsigned char v=1; v<14; ++v)
82 // {
83 // GridElement neighborVal =
84 //_grid[neighborShift[v]] + static_cast<GridElement>(neighbours[v][3]);
85 // minVal = std::min(minVal, neighborVal);
86 // }
87 //
88 // *_grid = minVal;
89 //
90 // //we track the max distance
91 // if (minVal > maxDist)
92 // {
93 // maxDist = minVal;
94 // }
95 //
96 // _grid += order;
97 // }
98 // _grid += order*2; //next line
99 //
100 // if (normProgress && !normProgress->oneStep())
101 // {
102 // break;
103 // }
104 // }
105 //
106 // _grid += (order*2) * static_cast<int>(m_rowSize); //next slice
107 // }
108 //
109 // return maxDist;
110 // }
111 
114  if (m_grid.empty()) {
115  assert(false);
116  return -1;
117  }
118 
119  const signed char* fwNeighbours = nullptr;
120  const signed char* bwNeighbours = nullptr;
121  switch (type) {
122  case CHAMFER_111: {
123  fwNeighbours = ForwardNeighbours111;
124  bwNeighbours = BackwardNeighbours111;
125  } break;
126 
127  case CHAMFER_345: {
128  fwNeighbours = ForwardNeighbours345;
129  bwNeighbours = BackwardNeighbours345;
130  } break;
131 
132  default:
133  // unhandled type?!
134  assert(false);
135  return -1;
136  }
137 
138  NormalizedProgress normProgress(progressCb,
139  m_innerSize.y * m_innerSize.z * 2);
140  if (progressCb) {
141  if (progressCb->textCanBeEdited()) {
142  progressCb->setMethodTitle("Chamfer distance");
143  char buffer[256];
144  sprintf(buffer, "Box: [%u x %u x %u]", m_innerSize.x, m_innerSize.y,
145  m_innerSize.z);
146  progressCb->setInfo(buffer);
147  }
148  progressCb->update(0);
149  progressCb->start();
150  }
151 
152  // 1st pass: forward scan
153  {
154  GridElement* _grid = &(m_grid[pos2index(0, 0, 0)]);
155 
156  // accelerating structure
157  int neighborShift[14];
158  {
159  for (unsigned char v = 0; v < 14; ++v) {
160  const signed char* fwNeighbour = fwNeighbours + 4 * v;
161  neighborShift[v] = static_cast<int>(fwNeighbour[0]) +
162  static_cast<int>(fwNeighbour[1]) *
163  static_cast<int>(m_rowSize) +
164  static_cast<int>(fwNeighbour[2]) *
165  static_cast<int>(m_sliceSize);
166  }
167  }
168 
169  for (unsigned k = 0; k < m_innerSize.z; ++k) {
170  for (unsigned j = 0; j < m_innerSize.y; ++j) {
171  for (unsigned i = 0; i < m_innerSize.x; ++i) {
172  GridElement minVal =
173  _grid[neighborShift[0]] +
174  static_cast<GridElement>(fwNeighbours[3]);
175 
176  for (unsigned char v = 1; v < 14; ++v) {
177  const signed char* fwNeighbour = fwNeighbours + 4 * v;
178  GridElement neighborVal =
179  _grid[neighborShift[v]] +
180  static_cast<GridElement>(fwNeighbour[3]);
181  minVal = std::min(minVal, neighborVal);
182  }
183 
184  *_grid++ = minVal;
185  }
186  _grid += 2; // next line
187 
188  if (progressCb && !normProgress.oneStep()) {
189  break;
190  }
191  }
192 
193  _grid += 2 * m_rowSize; // next slice
194  }
195  }
196 
197  // 2nd pass: backward scan
198  GridElement maxDist = 0;
199  {
200  // accelerating structure
201  int neighborShift[14];
202  {
203  for (unsigned char v = 0; v < 14; ++v) {
204  const signed char* bwNeighbour = bwNeighbours + 4 * v;
205  neighborShift[v] = static_cast<int>(bwNeighbour[0]) +
206  static_cast<int>(bwNeighbour[1]) *
207  static_cast<int>(m_rowSize) +
208  static_cast<int>(bwNeighbour[2]) *
209  static_cast<int>(m_sliceSize);
210  }
211  }
212 
213  GridElement* _grid =
214  &(m_grid[pos2index(static_cast<int>(m_innerSize.x) - 1,
215  static_cast<int>(m_innerSize.y) - 1,
216  static_cast<int>(m_innerSize.z) - 1)]);
217 
218  for (unsigned k = 0; k < m_innerSize.z; ++k) {
219  for (unsigned j = 0; j < m_innerSize.y; ++j) {
220  for (unsigned i = 0; i < m_innerSize.x; ++i) {
221  GridElement minVal =
222  _grid[neighborShift[0]] +
223  static_cast<GridElement>(bwNeighbours[3]);
224 
225  for (unsigned char v = 1; v < 14; ++v) {
226  const signed char* bwNeighbour = bwNeighbours + 4 * v;
227  GridElement neighborVal =
228  _grid[neighborShift[v]] +
229  static_cast<GridElement>(bwNeighbour[3]);
230  minVal = std::min(minVal, neighborVal);
231  }
232 
233  *_grid-- = minVal;
234 
235  // we track the max distance
236  if (minVal > maxDist) {
237  maxDist = minVal;
238  }
239  }
240  _grid -= 2; // next line
241 
242  if (progressCb && !normProgress.oneStep()) {
243  break;
244  }
245  }
246 
247  _grid -= 2 * m_rowSize; // next slice
248  }
249  }
250 
251  return static_cast<int>(maxDist);
252 }
CHAMFER_DISTANCE_TYPE
Chamfer distances types.
Definition: CVConst.h:114
@ CHAMFER_111
Definition: CVConst.h:115
@ CHAMFER_345
Definition: CVConst.h:116
char type
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
int propagateDistance(CHAMFER_DISTANCE_TYPE type, GenericProgressCallback *progressCb=nullptr)
Computes the Chamfer distance on the whole grid.
virtual void setInfo(const char *infoStr)=0
Notifies some information about the ongoing process.
virtual void setMethodTitle(const char *methodTitle)=0
Notifies the algorithm title.
virtual bool textCanBeEdited() const
Returns whether the dialog title and info can be updated or not.
virtual void update(float percent)=0
Notifies the algorithm progress.
int64_t pos2index(int i, int j, int k) const
Converts a 3D position to an absolute index.
Definition: Grid3D.h:538
int64_t m_rowSize
1D row size (with margin)
Definition: Grid3D.h:551
Tuple3ui m_innerSize
Dimensions of the grid (without margin)
Definition: Grid3D.h:547
unsigned short GridElement
Cell type.
Definition: Grid3D.h:35
int64_t m_sliceSize
2D slice size (with margin)
Definition: Grid3D.h:553
std::vector< GridElement > m_grid
Grid data.
Definition: Grid3D.h:544
bool oneStep()
Increments total progress value of a single unit.
const signed char ForwardNeighbours345[14 *4]
Forward mask shifts and weights (Chamfer 3-4-5)
const signed char ForwardNeighbours111[14 *4]
Forward mask shifts and weights (Chamfer 1-1-1)
const signed char BackwardNeighbours111[14 *4]
Backward masks shifts and weights (Chamfer 1-1-1)
const signed char BackwardNeighbours345[14 *4]
Backward mask shifts and weights (Chamfer 3-4-5)
int min(int a, int b)
Definition: cutil_math.h:53
Generic file read and write utility for python interface.