RAPP Platform  v0.6.0
RAPP Platform is a collection of ROS nodes and back-end processes that aim to deliver ready-to-use generic services to robots
 All Classes Namespaces Files Functions Variables Macros
door_check.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 Copyright 2015 RAPP
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 
16  Authors: Maciej StefaƄczyk
17  contact: m.stefanczyk@elka.pw.edu.pl
18 
19 ******************************************************************************/
20 
21 #include <hazard_detection/door_check.hpp>
22 #include <hazard_detection/Line.hpp>
23 
24 
25 
26 int DoorCheck::process( const std::string & fname, DoorCheckParams params ) {
27  cv::Mat img = cv::imread(fname, CV_LOAD_IMAGE_GRAYSCALE);
28 
29  // check, whether image is properly loaded
30  if (img.empty()) return -1;
31 
32  // adaptive thresholding - results similar to edge detection
33  cv::Mat img_thr;
34  cv::adaptiveThreshold(img, img_thr, 255, params.thr_method, cv::THRESH_BINARY_INV, params.thr_block, params.thr_c);
35 
36  int prop_width = img.size().width;
37  int prop_height = img.size().height;
38 
39  // detect line segments
40  std::vector<cv::Vec4i> tmp_lines;
41  cv::HoughLinesP( img_thr, tmp_lines, 1, CV_PI/180, params.hough_thr, params.hough_len, params.hough_gap);
42 
43  std::vector<Line> lines;
44  for( size_t i = 0; i < tmp_lines.size(); i++ )
45  {
46  lines.push_back(Line(cv::Point(tmp_lines[i][0], tmp_lines[i][1]), cv::Point(tmp_lines[i][2], tmp_lines[i][3])));
47  }
48 
49  // estimate door angle
50  Line line;
51 
52  std::vector<Line> lines_v, lines_h;
53 
54  for (int i = 0; i < lines.size(); ++i) {
55  line = lines[i];
56 
57  line.draw(img, cv::Scalar(255,255,255));
58  if (abs(line.getAngle()) < M_PI/6) {
59  lines_h.push_back(line);
60 
61  line.draw(img, cv::Scalar(128));
62  } else
63  if (abs(line.getAngle()) > 2*M_PI/6) {
64  lines_v.push_back(line);
65  } else {
66  // skip line
67  }
68  }
69 
70  std::vector<cv::Point2f> points_v, points_h;
71 
72  /*for (int i = 0; i < 20; ++i) {
73  std::random_shuffle(lines_v.begin(), lines_v.end());
74  }*/
75 
76  // center line - vertical door frame
77  Line * cl = NULL;
78 
79  // score of center line
80  float cl_score = 0;
81 
82  for (int i = 0; i < lines_v.size(); ++i) {
83  Line * tmp = &lines_v[i];
84 
85  // angle score - 1 for perfectly vertical line
86  float angle_score = fabs(tmp->getAngle()) / (M_PI/2);
87 
88  // position score - 1 for centered line
89  float mean_x = (tmp->getP1().x + tmp->getP2().x) / 2;
90  float cx = 0.5 * prop_width;
91  float position_score = 1.0 - fabs(cx - mean_x) / cx;
92 
93  // length score - 1 for line at least half of image height
94  float length_score = 2 * tmp->length() / prop_height;
95  if (length_score > 1) length_score = 1;
96 
97  float tmp_score = angle_score * position_score * length_score;
98  if (tmp_score > cl_score) {
99  cl = tmp;
100  cl_score = tmp_score;
101  }
102  }
103 
104  if (cl)
105  cl->draw(img, cv::Scalar(0, 0, 0));
106 
107  // left line - left floor/wall crossing
108  Line * ll = NULL;
109 
110  // score of left line
111  float ll_score = 0;
112 
113  for (int i = 0; i < lines_h.size(); ++i) {
114  Line * tmp = &lines_h[i];
115 
116  // angle score - 1 for perfectly horizontal line
117  float angle_score = (M_PI/2 - fabs(tmp->getAngle())) / (M_PI/2);
118 
119  // position score - 1 for line centered on the left part
120  float mean_x = (tmp->getP1().x + tmp->getP2().x) / 2;
121  float cx = 0.25 * prop_width;
122  float position_score = 1.0 - fabs(cx - mean_x) / cx;
123  // ignore lines laying on the right side
124  if (mean_x > 0.5 * prop_width) position_score = 0;
125 
126  // length score - 1 for line at least half of image width
127  float length_score = 2 * tmp->length() / prop_width;
128  if (length_score > 1) length_score = 1;
129 
130  float tmp_score = angle_score * position_score * length_score;
131  if (tmp_score > ll_score) {
132  ll = tmp;
133  ll_score = tmp_score;
134  }
135  }
136 
137  if (ll)
138  ll->draw(img, cv::Scalar(0));
139 
140  // right line - right floor/wall crossing
141  Line * rl = NULL;
142 
143  // score of right line
144  float rl_score = 0;
145 
146  for (int i = 0; i < lines_h.size(); ++i) {
147  Line * tmp = &lines_h[i];
148 
149  // angle score - 1 for perfectly horizontal line
150  float angle_score = (M_PI/2 - fabs(tmp->getAngle())) / (M_PI/2);
151 
152  // position score - 1 for line centered on the left part
153  float mean_x = (tmp->getP1().x + tmp->getP2().x) / 2;
154  float cx = 0.75 * prop_width;
155  float position_score = 1.0 - fabs(cx - mean_x) / cx;
156  // ignore lines laying on the left side
157  if (mean_x < 0.5 * prop_width) position_score = 0;
158 
159  // length score - 1 for line at least half of image width
160  float length_score = 2 * tmp->length() / prop_width;
161  if (length_score > 1) length_score = 1;
162 
163  float tmp_score = angle_score * position_score * length_score;
164  if (tmp_score > rl_score) {
165  rl = tmp;
166  rl_score = tmp_score;
167  }
168  }
169 
170  if (rl)
171  rl->draw(img, cv::Scalar(0));
172 
173  float angle = 0;
174  if (ll && rl) {
175  angle = fabs(ll->getAngle() - rl->getAngle()) * 180 / 3.1415;
176  } else {
177  angle = 90;
178  }
179 
180  if (params.debug)
181  cv::imwrite("/tmp/door_out.png", img);
182 
183  return angle;
184 }