#include #include #include #include #include #include <opencv2/opencv.hpp>

using namespace std; using namespace cv;

struct Point3D { double x, y, z; };

struct Line { Point3D p1, p2; double length() const { return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2) + pow(p1.z - p2.z, 2)); } };

vector readPLY(const string& filename) { vector points; ifstream fin(filename); string line; while (getline(fin, line)) { if (line == "end_header") break; } while (getline(fin, line)) { double x, y, z; sscanf(line.c_str(), "%lf %lf %lf", &x, &y, &z); points.push_back({ x, y, z }); } return points; }

vector detectLines(const vector& points, int threshold) { const double pi = 3.1415926535897932384626433832795; const int theta_bins = 360; const int phi_bins = 180; const double theta_step = pi / theta_bins; const double phi_step = pi / phi_bins; vector<vector> accumulator(theta_bins, vector(phi_bins, 0)); for (size_t i = 0; i < points.size(); i++) { for (size_t j = i + 1; j < points.size(); j++) { double dx = points[i].x - points[j].x; double dy = points[i].y - points[j].y; double dz = points[i].z - points[j].z; double d = sqrt(dx * dx + dy * dy + dz * dz); if (d == 0) continue; double theta = atan2(dy, dx); double phi = acos(dz / d); int theta_idx = round((theta + pi) / theta_step); int phi_idx = round(phi / phi_step); if (theta_idx < 0 || theta_idx >= theta_bins || phi_idx < 0 || phi_idx >= phi_bins) continue; accumulator[theta_idx][phi_idx]++; } } vector<pair<int, pair<int, int>>> lines; for (int i = 0; i < theta_bins; i++) { for (int j = 0; j < phi_bins; j++) { if (accumulator[i][j] >= threshold) { lines.push_back({ accumulator[i][j], {i, j} }); } } } sort(lines.rbegin(), lines.rend()); vector detected_lines; for (size_t i = 0; i < lines.size(); i++) { double theta = lines[i].second.first * theta_step - pi; double phi = lines[i].second.second * phi_step; double x1 = -1000 * cos(theta) * sin(phi); double y1 = -1000 * sin(theta) * sin(phi); double z1 = -1000 * cos(phi); double x2 = -x1; double y2 = -y1; double z2 = -z1; Line line = { { x1, y1, z1 }, { x2, y2, z2 } }; bool overlap = false; for (size_t j = 0; j < detected_lines.size(); j++) { double a1 = detected_lines[j].p1.x; double b1 = detected_lines[j].p1.y; double c1 = detected_lines[j].p1.z; double a2 = detected_lines[j].p2.x; double b2 = detected_lines[j].p2.y; double c2 = detected_lines[j].p2.z; double d1 = line.p1.x; double e1 = line.p1.y; double f1 = line.p1.z; double d2 = line.p2.x; double e2 = line.p2.y; double f2 = line.p2.z; double dist = sqrt(pow(a1 - d1, 2) + pow(b1 - e1, 2) + pow(c1 - f1, 2)); if (dist < 1e-6) { overlap = true; break; } dist = sqrt(pow(a2 - d2, 2) + pow(b2 - e2, 2) + pow(c2 - f2, 2)); if (dist < 1e-6) { overlap = true; break; } double a = pow(b1 - b2, 2) + pow(c1 - c2, 2) + pow(a1 - a2, 2); double b = (d2 - d1) * (b1 - b2) + (e2 - e1) * (c1 - c2) + (f2 - f1) * (a1 - a2); double c = pow(d1 - d2, 2) + pow(e1 - e2, 2) + pow(f1 - f2, 2); double t = -b / a; if (t < 0 || t > 1) continue; double d = sqrt(c - b * b / a); if (d < 1e-6) { overlap = true; break; } } if (!overlap) { detected_lines.push_back(line); } } return detected_lines; }

void visualize(const vector& points, const vector& lines) { const int width = 800, height = 600; Mat image(height, width, CV_8UC3, Scalar(255, 255, 255)); double max_length = 0; for (const auto& line : lines) { max_length = max(max_length, line.length()); } for (const auto& point : points) { double u = (point.x + max_length) / (2 * max_length) * width; double v = (1 - (point.y + max_length) / (2 * max_length)) * height; circle(image, Point(u, v), 2, Scalar(0, 0, 255), -1); } for (const auto& line : lines) { double u1 = (line.p1.x + max_length) / (2 * max_length) * width; double v1 = (1 - (line.p1.y + max_length) / (2 * max_length)) * height; double u2 = (line.p2.x + max_length) / (2 * max_length) * width; double v2 = (1 - (line.p2.y + max_length) / (2 * max_length)) * height; line(image, Point(u1, v1), Point(u2, v2), Scalar(0, 255, 0), 2); } namedWindow('Visualization', WINDOW_NORMAL); resizeWindow('Visualization', width, height); imshow('Visualization', image); waitKey(0); }

int main(int argc, char** argv) { if (argc < 2) { cerr << "Usage: " << argv[0] << " filename.ply" << endl; return 1; } vector points = readPLY(argv[1]); vector lines = detectLines(points, 500); visualize(points, lines); return 0; }

此代码首先读取 PLY 文件中的点云数据,然后使用 3D Hough 变换检测其中的直线。检测过程中,每个点对之间的距离和方向都被量化为离散的 theta 和 phi 值,并在 Hough 累加器中增加对应位置的投票数。最终,根据累加器中的投票数,找到投票数最多的直线并可视化。函数 readPLY() 读取 PLY 文件,函数 detectLines() 执行 3D Hough 变换,函数 visualize() 将点云和检测到的直线可视化。在此示例中,投票数阈值设置为 500,用于控制检测到的直线数量。

C++ 3D Hough 变换检测 PLY 文件直线并可视化

原文地址: https://www.cveoy.top/t/topic/opEL 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录