path_optimization.h
Go to the documentation of this file.
1 #pragma once
2 // std
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <vector>
7 #include <list>
8 #include <set>
9 #include <unistd.h> // sleep
10 // other headers
11 #include "global.h" // global variables
12 #include "data_engine.h" // scene reconstruction
13 #include "../include/LBFGS/LBFGS.h" // solve path optimizaion
14 
15 using namespace std;
16 using namespace LBFGSpp;
17 
18 cv::Mat dist;
19 vector<int> fixed_node_indexes;
22 
23 // distance field
24 void initDistanceField(DataEngine* p_de);
25 
26 // get field value
27 double fieldIntensity(Eigen::Vector2d xy);
28 
29 // get distance from obstacles
30 double getValueDistanceField(int r, int c);
31 
32 // get field gradient
33 Eigen::Vector2d fieldGradient(Eigen::Vector2d xy);
34 
35 // rho
36 double rho(Eigen::Vector2d xy);
37 
38 // grho
39 Eigen::Vector2d grho(Eigen::Vector2d xy);
40 
41 // objective func
42 double energyFunc(const Eigen::VectorXd& x, Eigen::VectorXd& grad);
43 
44 // check if path cross obstacles.
45 bool crossObstacles(DataEngine* p_de, int cr, int cc, int lr, int lc);
46 
47 // get distance from obstacles
48 float getValueDist(int r, int c);
49 
50 // optimization
51 bool Optimize_Path(DataEngine* p_de, vector<iro::SE2> & path);
52 
53 // distance field
55 {
56  // distance transform
57  cv::Mat map_mat = p_de->visCellMap();
58  cv::Mat binary_mat(map_rows, map_cols, CV_8UC1);
59  for (int i = 0; i < binary_mat.rows; i++)
60  {
61  for (int j = 0; j < binary_mat.cols; j++)
62  {
63  binary_mat.ptr<uchar>(i)[j] = 0;
64  if (map_mat.ptr<cv::Vec3b>(i)[j][1] == 255)
65  binary_mat.ptr<uchar>(i)[j] = 255;
66  }
67  }
68  cv::threshold(binary_mat, binary_mat, 0, 255, cv::THRESH_BINARY);
69  cv::distanceTransform(binary_mat, dist, CV_DIST_L2, 3);
70  cv::normalize(dist, dist, 0, 1., cv::NORM_MINMAX); // normalize distance field.
71  // dist.type() = CV_32F
72  //cv::imshow("normalized distance field", dist);
73  //cv::waitKey(0);
74  return;
75 }
76 
77 // get distance from obstacles
78 double getValueDistanceField(int r, int c)
79 {
80  // information field value
81 
82  //distanceField[r][c] = -(double)getValueDist(r, c);
83 
84  distanceField[r][c] = 1.0/(double)getValueDist(r, c);
85 
86  cerr<<"distance value "<<distanceField[r][c]<<endl;
87  return distanceField[r][c];
88 }
89 
90 // get distance from obstacles
91 float getValueDist(int r, int c)
92 {
93  float d = dist.ptr<float>(r)[c];
94  if (d<=0) d = 0.0001;
95  return d;
96 }
97 
98 // get field value
99 double fieldIntensity(Eigen::Vector2d xy)
100 {
101  cv::Point p((int)round(xy.x()), (int)round(xy.y()));
102  if (p.x<0 || p.x>map_cols || p.y<0 || p.y>map_rows)
103  return 0;
104  //return distanceField[p.y][p.x];
105  return getValueDistanceField(p.y, p.x);
106 }
107 
108 // get field gradient
109 Eigen::Vector2d fieldGradient(Eigen::Vector2d xy)
110 {
111  cv::Point p((int)round(xy.x()), (int)round(xy.y()));
112  if (p.x<0 || p.x>map_cols || p.y<0 || p.y>map_rows)
113  return Eigen::Vector2d(0, 0);
114  Eigen::Vector2d grd;
115  grd.x() = getValueDistanceField(p.y, p.x + 1) - getValueDistanceField(p.y, p.x);
116  grd.y() = getValueDistanceField(p.y + 1, p.x) - getValueDistanceField(p.y, p.x);
117  return grd;
118 }
119 
120 // rho
121 double rho(Eigen::Vector2d xy)
122 {
123  return pow((255 + fieldIntensity(xy)), 1);
124 }
125 
126 // grho
127 Eigen::Vector2d grho(Eigen::Vector2d xy)
128 {
129  return fieldGradient(xy);
130 }
131 
132 // objective func
133 double energyFunc(const Eigen::VectorXd& x, Eigen::VectorXd& grad)
134 {
135  // f = sigma rho(mid)^2 * ( x_i - x_i+1 )^2
136  // df =
137  const int n = x.size();
138  // f
139  double f(0);
140  for (int i = 0; i < n - 4; i += 2)
141  {
142  Eigen::Vector2d mid((x[i] + x[i + 2]) / 2, (x[i + 1] + x[i + 3]) / 2);
143  f +=
144  (
145  pow((x[i] - x[i + 2]), 2)
146  +
147  pow((x[i + 1] - x[i + 3]), 2)
148  )
149  *
150  //pow(rho(mid), 2);
151  pow(rho(mid), 3); // 2018-09-23
152  }
153  // grad
154  // fix begin and end points
155  {
156  grad[0] = 0;
157  grad[1] = 0;
158  grad[n - 2] = 0;
159  grad[n - 1] = 0;
160  }
161  // gradients of other points
162  for (int i = 2; i < n - 2; i += 2)
163  {
164  Eigen::Vector2d xy_i(x[i], x[i + 1]);
165  // next point
166  Eigen::Vector2d xy_n(x[i + 2], x[i + 3]);
167  Eigen::Vector2d mid_n = (xy_i + xy_n) / 2;
168  Eigen::Vector2d g_mid_n = grho(mid_n);
169  // last point
170  Eigen::Vector2d xy_l(x[i - 2], x[i - 1]);
171  Eigen::Vector2d mid_l = (xy_i + xy_l) / 2;
172  Eigen::Vector2d g_mid_l = grho(mid_l);
173  grad[i] =
174  3 * rho(mid_n) * g_mid_n.x() * (pow(x[i] - x[i + 2], 2) + pow(x[i + 1] - x[i + 3], 2)) + pow(rho(mid_n), 2) * 2 * (x[i] - x[i + 2])
175  +
176  3 * rho(mid_l) * g_mid_l.x() * (pow(x[i] - x[i - 2], 2) + pow(x[i + 1] - x[i - 1], 2)) + pow(rho(mid_l), 2) * 2 * (x[i] - x[i - 2]);
177 
178  grad[i + 1] =
179  3 * rho(mid_n) * g_mid_n.y() * (pow(x[i] - x[i + 2], 2) + pow(x[i + 1] - x[i + 3], 2)) + pow(rho(mid_n), 2) * 2 * (x[i + 1] - x[i + 3])
180  +
181  3 * rho(mid_l) * g_mid_l.y() * (pow(x[i] - x[i - 2], 2) + pow(x[i + 1] - x[i - 1], 2)) + pow(rho(mid_l), 2) * 2 * (x[i + 1] - x[i - 1]);
182  }
183  // fix begin and end points
184  {
185  grad[0] = 0;
186  grad[1] = 0;
187  grad[n - 2] = 0;
188  grad[n - 1] = 0;
189  }
190  return f;
191 }
192 
193 // check if path cross obstacles.
194 bool crossObstacles(DataEngine* p_de, int cr, int cc, int lr, int lc)
195 {
196  // set up
197  cv::Point beg(cc, cr);
198  cv::Point end(lc, lr);
199  // dda check
200  bool occlusion = false;
201  int dx = end.x - beg.x;
202  int dy = end.y - beg.y;
203  if (dx == 0)
204  {
205  if (beg.y < end.y)
206  {
207  for (int y = beg.y; y <= end.y; y++)
208  {
209  if (!(p_de->m_recon2D.m_cellmap[y][beg.x].isScanned && p_de->m_recon2D.m_cellmap[y][beg.x].isFree))
210  {
211  occlusion = true;
212  break;
213  }
214  }
215  }
216  else
217  {
218  for (int y = beg.y; y >= end.y; y--)
219  {
220  if (!(p_de->m_recon2D.m_cellmap[y][beg.x].isScanned && p_de->m_recon2D.m_cellmap[y][beg.x].isFree))
221  {
222  occlusion = true;
223  break;
224  }
225  }
226  }
227  }
228  else if (dy == 0)
229  {
230  if (beg.x < end.x)
231  {
232  for (int x = beg.x; x <= end.x; x++)
233  {
234  if (!(p_de->m_recon2D.m_cellmap[beg.y][x].isScanned && p_de->m_recon2D.m_cellmap[beg.y][x].isFree))
235  {
236  occlusion = true;
237  break;
238  }
239  }
240  }
241  else
242  {
243  for (int x = beg.x; x >= end.x; x--)
244  {
245  if (!(p_de->m_recon2D.m_cellmap[beg.y][x].isScanned && p_de->m_recon2D.m_cellmap[beg.y][x].isFree))
246  {
247  occlusion = true;
248  break;
249  }
250  }
251  }
252  }
253  else if (dx == 0 && dy == 0){}
254  else
255  {
256  int MaxStep = abs(dx) > abs(dy) ? abs(dx) : abs(dy); // steps
257  double fXUnitLen = 1.0; // X delta
258  double fYUnitLen = 1.0; // Y delta
259  fYUnitLen = (double)(dy) / (double)(MaxStep);
260  fXUnitLen = (double)(dx) / (double)(MaxStep);
261  double x = (double)(beg.x);
262  double y = (double)(beg.y);
263  // dda begin
264  for (long i = 1; i < MaxStep; i++) // '<' or '<=', not include end point
265  {
266  x = x + fXUnitLen;
267  y = y + fYUnitLen;
268  int crt_r = (int)round(y);
269  int crt_c = (int)round(x);
270  if (!(p_de->m_recon2D.m_cellmap[crt_r][crt_c].isScanned && p_de->m_recon2D.m_cellmap[crt_r][crt_c].isFree))
271  {
272  occlusion = true;
273  break;
274  }
275  }
276  }
277  // done.
278  return occlusion;
279 }
280 
281 // optimization
282 bool Optimize_Path(DataEngine* p_de, vector<iro::SE2> & path)
283 {
284  // set up
285  initDistanceField(p_de);
286  const int n = path.size() * 2;
288  param.epsilon = 1e-6;
289  //param.max_iterations = 1000; // defualt
290  param.max_iterations = 10;
291  LBFGSSolver<double> solver(param);
292  Eigen::VectorXd x = Eigen::VectorXd::Zero(n); // variable
293  fixed_node_indexes.clear(); // fixed point
294  fixed_variabe_indexes.clear(); // fixed point
295  for (int nid = 0; nid < path.size(); nid++)
296  {
297  x[nid * 2] = path[nid].translation().x();
298  x[nid * 2 + 1] = -path[nid].translation().y();
299  if (fabs(path[nid].rotation().angle() - 0.0) > 0.01) // key view
300  {
301  fixed_node_indexes.push_back(nid);
302  fixed_variabe_indexes.push_back(nid * 2);
303  fixed_variabe_indexes.push_back(nid * 2 + 1);
304  }
305  }
306  double fx;
307 /*
308  // vis show origin
309  {
310  cv::Mat vis = p_de->visCellMap();
311  for (int i = 0; i <= n - 2; i += 2)
312  {
313  cv::circle(vis, cv::Point(x[i], x[i + 1]), 3, CV_RGB(0, 0, 0));
314  if (i != 0)
315  cv::line(vis, cv::Point(x[i], x[i + 1]), cv::Point(x[i - 2], x[i - 1]), CV_RGB(0, 0, 0));
316  }
317  cv::imshow("origin", vis);
318  }
319 //*/
320 
321  int niter = solver.minimize(energyFunc, x, fx); // lbfgs
322 /*
323  // vis show result
324  {
325  cv::Mat vis = p_de->visCellMap();
326  for (int i = 0; i <= n - 2; i += 2)
327  {
328  cv::circle(vis, cv::Point(x[i], x[i + 1]), 3, CV_RGB(0, 0, 0));
329  if (i != 0)
330  cv::line(vis, cv::Point(x[i], x[i + 1]), cv::Point(x[i - 2], x[i - 1]), CV_RGB(0, 0, 0));
331  }
332  cv::imshow("result", vis);
333  }
334  cv::waitKey(0);
335 //*/
336 
337  // save optimized path
338  int lr = 0;
339  int lc = 0;
340  for (int nid = 0; nid < path.size(); nid++)
341  {
342  int cr = (int)round(x[nid * 2 + 1]);
343  int cc = (int)round(x[nid * 2]);
344  // avoid out of boundary. 2018-09-24.
345  if (cr < 0 || cr >= map_rows || cc < 0 || cc >= map_cols) return false;
346  //if (getValueDist((int)round(x[nid * 2 + 1]), (int)round(x[nid * 2]))) return false;
347  // avoid crossing obstacles when sample points are few. 2019-06-12.
348  if (nid > 0) if (crossObstacles(p_de, cr, cc, lr, lc)) return false;
349  lr = cr;
350  lc = cc;
351  }
352  for (int nid = 0; nid < path.size(); nid++)
353  {
354  path[nid].translation().x() = x[nid * 2];
355  path[nid].translation().y() = -x[nid * 2 + 1];
356  }
357  return true;
358 }
d
unsigned char uchar
Definition: data_engine.cpp:6
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half pow(const half &a, const half &b)
Definition: Half.h:407
cv::Mat visCellMap()
bool param(const std::string &param_name, T &param_val, const T &default_val)
Eigen::Vector2d fieldGradient(Eigen::Vector2d xy)
f
bool Optimize_Path(DataEngine *p_de, vector< iro::SE2 > &path)
Definition: LBFGS.h:11
int minimize(Foo &f, Vector &x, Scalar &fx)
Definition: LBFGS.h:77
CellMap ** m_cellmap
Definition: data_engine.h:53
float getValueDist(int r, int c)
Scalar epsilon
Definition: Param.h:91
double distanceField[map_rows][map_cols]
cv::Mat dist
void initDistanceField(DataEngine *p_de)
double rho(Eigen::Vector2d xy)
vector< int > fixed_variabe_indexes
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const AbsReturnType abs() const
double getValueDistanceField(int r, int c)
double fieldIntensity(Eigen::Vector2d xy)
bool isFree
Definition: data_engine.h:35
const int map_rows
Definition: data_engine.h:40
vector< int > fixed_node_indexes
const int map_cols
Definition: data_engine.h:41
double energyFunc(const Eigen::VectorXd &x, Eigen::VectorXd &grad)
bool isScanned
Definition: data_engine.h:34
Recon2D m_recon2D
Definition: data_engine.h:127
Eigen::Vector2d grho(Eigen::Vector2d xy)
bool crossObstacles(DataEngine *p_de, int cr, int cc, int lr, int lc)
EIGEN_DEVICE_FUNC const RoundReturnType round() const


co_scan
Author(s):
autogenerated on Mon Feb 28 2022 23:00:47