ed_sensor_integration
mesh_tools.cpp
Go to the documentation of this file.
1 #include "ed/kinect/mesh_tools.h"
2 
3 #include <geolib/Mesh.h>
4 #include <opencv2/core/core.hpp>
5 #include <opencv2/imgproc/imgproc.hpp>
6 //#include <opencv2/highgui/highgui.hpp>
7 #include <ros/console.h>
8 
9 namespace dml
10 {
11 
12 // ----------------------------------------------------------------------------------------------------
13 
14 void findContours(const cv::Mat& image, const geo::Vec2i& p, int d_start, std::vector<geo::Vec2i>& points,
15  std::vector<geo::Vec2i>& line_starts, cv::Mat& contour_map, bool add_first)
16 {
17  static int dx[4] = {1, 0, -1, 0 };
18  static int dy[4] = {0, 1, 0, -1 };
19 
20  unsigned char v = image.at<unsigned char>(p.y, p.x);
21 
22  int d_current = d_start; // Current direction
23  int x2 = p.x;
24  int y2 = p.y;
25 
26  int line_piece_min = 1e9; // minimum line piece length of current line
27  int line_piece_max = 0; // maximum line piece length of current line
28 
29  int d_main = d_current; // The main direction in which we're heading. If we follow a line
30  // that gradually changes to the side (1-cell side steps), this direction
31  // denotes the principle axis of the line
32 
33  if (add_first)
34  points.push_back(p);
35 
36  int n_uninterrupted = 1;
37  geo::Vec2i p_corner = p;
38 
39  while (true)
40  {
41  bool found = false;
42  int d = (d_current + 3) % 4; // check going left first
43 
44  for(int i = -1; i < 3; ++i)
45  {
46  int idx_x = x2 + dx[d];
47  int idx_y = y2 + dy[d];
48 
49  // Clip the indices
50  idx_x = std::min(image.cols - 1, std::max(0, idx_x));
51  idx_y = std::min(image.rows - 1, std::max(0, idx_y));
52 
53  if (idx_y < 0 || idx_y >= image.rows || idx_x < 0 || idx_x >= image.cols)
54  {
55  ROS_ERROR("This should not happen! Image going out of bound, findContours. [%d, %d] and image size is [%d,%d]", idx_y, idx_x, image.rows, image.cols);
56  return;
57  }
58  if (image.at<unsigned char>(idx_y, idx_x) == v)
59  {
60  found = true;
61  break;
62  }
63 
64  d = (d + 1) % 4;
65  }
66 
67  if (!found)
68  return;
69 
70  geo::Vec2i p_current(x2, y2);
71 
72  if ((d + 2) % 4 == d_current)
73  {
74  // 180 degree turn
75 
76  if (x2 == p.x && y2 == p.y) // Edge case: if we returned to the start point and
77  // this is a 180 degree angle, return without adding it
78  return;
79 
80 
81  points.push_back(p_current);
82  d_main = d;
83  line_piece_min = 1e9;
84  line_piece_max = 0;
85 
86  }
87  else if (d_current != d_main)
88  {
89  // Not moving in main direction (side step)
90 
91  if (d != d_main)
92  {
93  // We are not moving back in the main direction
94  // Add the corner to the list and make this our main direction
95 
96  points.push_back(p_corner);
97  d_main = d_current;
98  line_piece_min = 1e9;
99  line_piece_max = 0;
100  }
101  }
102  else
103  {
104  // Moving in main direction (no side step)
105 
106  if (d_current != d)
107  {
108  // Turning 90 degrees
109 
110  // Check if the length of the last line piece is OK w.r.t. the other pieces in this line. If it differs to much,
111  // (i.e., the contour has taken a different angle), add the last corner to the list. This way, we introduce a
112  // bend in the contour
113  if (line_piece_max > 0 && (n_uninterrupted < line_piece_max - 2 || n_uninterrupted > line_piece_min + 2))
114  {
115  // Line is broken, add the corner as bend
116  points.push_back(p_corner);
117 
118  line_piece_min = 1e9;
119  line_piece_max = 0;
120  }
121 
122  // Update the line piece lenth boundaries with the current found piece
123  line_piece_min = std::min(line_piece_min, n_uninterrupted);
124  line_piece_max = std::max(line_piece_max, n_uninterrupted);
125  }
126  }
127 
128  if (d_current != d)
129  {
130  p_corner = p_current;
131  n_uninterrupted = 0;
132  }
133 
134  if ((d_current == 3 && d != 2) || (d == 3 && d != 0)) // up
135  line_starts.push_back(p_current);
136 
137  if (p_current.y < 0 || p_current.y >= contour_map.rows || p_current.x < 0 || p_current.x >= contour_map.cols)
138  {
139  ROS_ERROR("This should not happen! Contour map going out of bound, findContours. [%d, %d] and contour map size is [%d,%d]", p_current.y, p_current.x, contour_map.rows, contour_map.cols);
140  return;
141  }
142  contour_map.at<unsigned char>(p_current.y, p_current.x) = 1;
143 
144  ++n_uninterrupted;
145 
146  if (points.size() > 1 && x2 == p.x && y2 == p.y)
147  return;
148 
149  x2 = x2 + dx[d];
150  y2 = y2 + dy[d];
151 
152  d_current = d;
153  }
154 }
155 
156 // ----------------------------------------------------------------------------------------------------
157 
158 void calculateContour(const cv::Mat& image, std::vector<std::vector<geo::Vec2i> >& contours)
159 {
160  cv::Mat contour_map(image.rows, image.cols, CV_8UC1, cv::Scalar(0));
161 
162  for(int y = 0; y < image.rows; ++y)
163  {
164  for(int x = 0; x < image.cols; ++x)
165  {
166  unsigned char v = image.at<unsigned char>(y, x);
167 
168  if (v == 0)
169  continue;
170 
171  contours.push_back(std::vector<geo::Vec2i>());
172  std::vector<geo::Vec2i>& points = contours.back();
173 
174  std::vector<geo::Vec2i> line_starts;
175  findContours(image, geo::Vec2i(x, y), 0, points, line_starts, contour_map, true);
176 
177  unsigned int num_points = points.size();
178 
179  if (num_points <= 2)
180  {
181  contours.pop_back();
182  continue;
183  }
184 
185  // Check for holes within the contour
186  for(unsigned int i = 0; i < line_starts.size(); ++i)
187  {
188  int x2 = line_starts[i].x;
189  int y2 = line_starts[i].y;
190 
191  while(image.at<unsigned char>(y2, x2) == v)
192  ++x2;
193 
194  if (contour_map.at<unsigned char>(y2, x2 - 1) != 0)
195  continue;
196 
197  // found a hole, so find the contours of this hole
198 
200  std::vector<geo::Vec2i>& hole_points = contours.back();
201 
202  findContours(image, geo::Vec2i(x2 - 1, y2 + 1), 1, hole_points, line_starts, contour_map, false);
203 
204  if (hole_points.size() <= 2)
205  {
206  contours.pop_back();
207  continue;
208  }
209  }
210 
211  // Remove the shape
212  cv::floodFill(image, cv::Point(x, y), 0);
213  }
214  }
215 }
216 
217 // ----------------------------------------------------------------------------------------------------
218 
220 {
221  const std::vector<geo::TriangleI>& triangles = mesh.getTriangleIs();
222  const std::vector<geo::Vec3>& vertices = mesh.getPoints();
223 
224  if (vertices.empty())
225  return;
226 
227  // Calculate bounding rectangle
228 
229  geo::Vec2 min(vertices[0].x, vertices[0].y);
230  geo::Vec2 max = min;
231 
232  for(std::vector<geo::Vec3>::const_iterator it = vertices.begin(); it != vertices.end(); ++it)
233  {
234  const geo::Vec3& v = *it;
235  min.x = std::min(min.x, v.x);
236  min.y = std::min(min.y, v.y);
237  max.x = std::max(max.x, v.x);
238  max.y = std::max(max.y, v.y);
239  }
240 
241  // Initialize grid
242  double w = max.x - min.x;
243  double h = max.y - min.y;
244  double res = 500 / std::min(w, h); // TODO: get rid of ad-hoc resolution calculation
245  cv::Mat grid(h * res + 5, w * res + 5, CV_8UC1, cv::Scalar(0));
246 
247  // Downproject vertices
248  std::vector<cv::Point2d> proj_vertices(vertices.size());
249  for(unsigned int i = 0; i < proj_vertices.size(); ++i)
250  {
251  const geo::Vec3& v = vertices[i];
252  proj_vertices[i] = cv::Point2d((v.x - min.x) * res + 1, (v.y - min.y) * res + 1);
253  }
254 
255  // Draw triangles
256  std::vector<cv::Point> pts(3);
257  for(std::vector<geo::TriangleI>::const_iterator it = triangles.begin(); it != triangles.end(); ++it)
258  {
259  const geo::TriangleI& t = *it;
260  pts[0] = proj_vertices[t.i1_];
261  pts[1] = proj_vertices[t.i2_];
262  pts[2] = proj_vertices[t.i3_];
263  cv::fillConvexPoly(grid, &pts[0], 3, cv::Scalar(1));
264  }
265 
266 // cv::Mat canvas = grid.clone() * 255;
267 
268  // Calculate contours
269  std::vector<std::vector<geo::Vec2i> > contours_pixel;
270  calculateContour(grid, contours_pixel);
271 
272  contours.resize(contours_pixel.size());
273  for(unsigned int i = 0; i < contours_pixel.size(); ++i)
274  {
275  std::vector<geo::Vec2i>& contour_pixel = contours_pixel[i];
276  std::vector<geo::Vec2>& contour = contours[i];
277  contour.resize(contour_pixel.size());
278 
279  for(unsigned int j = 0; j < contour.size(); ++j)
280  contour[j] = geo::Vec2(contour_pixel[j].x - 1, contour_pixel[j].y - 1) / res + min;
281  }
282 
283 
284 // for(std::vector<std::vector<geo::Vec2i> >::const_iterator it = contours_pixel.begin(); it != contours_pixel.end(); ++it)
285 // {
286 // const std::vector<geo::Vec2i>& contour = *it;
287 // for(unsigned int i = 0; i < contour.size(); ++i)
288 // {
289 // unsigned int j = (i + 1) % contour.size();
290 
291 // const geo::Vec2i& p1 = contour[i];
292 // const geo::Vec2i& p2 = contour[j];
293 
294 // cv::line(canvas, cv::Point(p1.x, p1.y), cv::Point(p2.x, p2.y), cv::Scalar(128), 2);
295 // }
296 
297 // for(std::vector<geo::Vec2i>::const_iterator it2 = it->begin(); it2 != it->end(); ++it2)
298 // {
299 // const geo::Vec2i& p = *it2;
300 // cv::circle(canvas, cv::Point(p.x, p.y), 5, cv::Scalar(128));
301 // }
302 // }
303 
304 // cv::imshow("grid", canvas);
305 // cv::waitKey();
306 
307 }
308 
309 } // end namespace dml
310 
std::vector::resize
T resize(T... args)
geo::Mesh::getTriangleIs
const std::vector< TriangleI > & getTriangleIs() const
t
Timer t
geo::Vec2T::y
T y
std::vector
std::vector::size
T size(T... args)
geo::Vec3T
geo::Vec2T::x
T x
std::vector::back
T back(T... args)
dml::calculateContour
void calculateContour(const cv::Mat &image, std::vector< std::vector< geo::Vec2i > > &contours)
Definition: mesh_tools.cpp:158
std::vector::push_back
T push_back(T... args)
image
cv::Mat image
geo::Vec3T::y
T y
geo::TriangleI
geo::Mesh::getPoints
const std::vector< geo::Vector3 > & getPoints() const
std::min
T min(T... args)
dml
Definition: mesh_tools.h:13
Mesh.h
std::vector::begin
T begin(T... args)
std::vector::empty
T empty(T... args)
dml::project2D
void project2D(const geo::Mesh &mesh, std::vector< std::vector< geo::Vec2 > > &contours)
Definition: mesh_tools.cpp:219
std::vector::end
T end(T... args)
std::max
T max(T... args)
mesh_tools.h
geo::Mesh
geo::Vec3T::x
T x
geo::Vec2T
dml::findContours
void findContours(const cv::Mat &image, const geo::Vec2i &p, int d_start, std::vector< geo::Vec2i > &points, std::vector< geo::Vec2i > &line_starts, cv::Mat &contour_map, bool add_first)
Definition: mesh_tools.cpp:14