RoomRotator::computeRoomMainDirection
作为比较单独且核心的一个算法,这里单独拿出来方便后续查看
double RoomRotator::computeRoomMainDirection(const cv::Mat& room_map, const double map_resolution) { const double map_resolution_inverse = 1./map_resolution; // compute Hough transform on edge image of the map cv::Mat edge_map; cv::Canny(room_map, edge_map, 50, 150, 3); std::vector<cv::Vec4i> lines; double min_line_length = 1.0; // in [m] for (; min_line_length > 0.1; min_line_length -= 0.2) { cv::HoughLinesP(edge_map, lines, 1, CV_PI/180, min_line_length*map_resolution_inverse, min_line_length*map_resolution_inverse, 1.5*min_line_length*map_resolution_inverse); cv::Mat room_hough = edge_map.clone(); for (size_t i=0; i<lines.size(); ++i) { cv::Point p1(lines[i][0], lines[i][1]), p2(lines[i][2], lines[i][3]); cv::line(room_hough, p1, p2, cv::Scalar(128), 2); } //cv::imshow("room_hough", room_hough); if (lines.size() >= 4) break; } // setup a histogram on the line directions weighted by their length to determine the major direction Histogram<double> direction_histogram(0, CV_PI, 36); for (size_t i=0; i<lines.size(); ++i) { double dx = lines[i][2] - lines[i][0]; double dy = lines[i][3] - lines[i][1]; if(dy*dy+dx*dx > 0.0) { double current_direction = std::atan2(dy, dx); while (current_direction < 0.) current_direction += CV_PI; while (current_direction > CV_PI) current_direction -= CV_PI; direction_histogram.addData(current_direction, sqrt(dy*dy+dx*dx)); //std::cout << " dx=" << dx << " dy=" << dy << " dir=" << current_direction << " len=" << sqrt(dy*dy+dx*dx) << std::endl; } } return direction_histogram.getMaxBinPreciseVal(); }
详细解释:
计算分辨率的倒数,用于长度单位转换
const double map_resolution_inverse = 1./map_resolution;
使用 cv::Canny 函数对房间地图进行边缘检测,得到边缘图 edge_map
cv::Mat edge_map;
cv::Canny(room_map, edge_map, 50, 150, 3);
使用霍夫变化检测直线
std::vector<cv::Vec4i> lines; double min_line_length = 1.0; // in [m] for (; min_line_length > 0.1; min_line_length -= 0.2) { cv::HoughLinesP(edge_map, lines, 1, CV_PI/180, min_line_length*map_resolution_inverse, min_line_length*map_resolution_inverse, 1.5*min_line_length*map_resolution_inverse); cv::Mat room_hough = edge_map.clone(); for (size_t i=0; i<lines.size(); ++i) { cv::Point p1(lines[i][0], lines[i][1]), p2(lines[i][2], lines[i][3]); cv::line(room_hough, p1, p2, cv::Scalar(128), 2); } //cv::imshow("room_hough", room_hough); if (lines.size() >= 4) break; }
使用 Histogram 类构建一个直方图,记录所有检测到的直线的方向和长度。
Histogram
遍历所有直线,计算它们的方向,并更新方向直方图。最后,返回方向直方图中最大值对应的方向,即为房间地图的主要方向。
for (size_t i=0; i<lines.size(); ++i) { double dx = lines[i][2] - lines[i][0]; double dy = lines[i][3] - lines[i][1]; if(dy*dy+dx*dx > 0.0) { double current_direction = std::atan2(dy, dx); while (current_direction < 0.) current_direction += CV_PI; while (current_direction > CV_PI) current_direction -= CV_PI; direction_histogram.addData(current_direction, sqrt(dy*dy+dx*dx)); //std::cout << " dx=" << dx << " dy=" << dy << " dir=" << current_direction << " len=" << sqrt(dy*dy+dx*dx) << std::endl; } } return direction_histogram.getMaxBinPreciseVal();