OpenCV代码精妙之三 实现点集元素之间最小距离

OpenCV代码精妙之三 实现点集元素之间最小距离

goodFeaturesToTrack 可传入一个参数 表示 返回的特征点像素距离需要 高于 该参数指定的值
具体如何实现的呢

首先 goodFeaturesToTrack 返回的 特征点 是具有 所谓 强度 的,类似于 得分
得分越高, 越优先保留

在该基础之上, 如果某两个特征点 距离低于 了 参数 指定阈值,
那么 其中 得分较低 的将被 剔除

最简单的做法是,遍历所有特征点,
检查其他特征点 与该特征点的距离 是否低于阈值,如果低于,那么删除 这些特征点

该做法 时间复杂度 O(n*n)

OpenCV 的实现的核心 思想了 利用了一个二维数组,
该二维数组 实际上是 将 图像 分成了 N * N的网格
网格的高宽即为 距离阈值,
数组中每一个元素 是一个动态数组, 包含了坐标位于 该网格内的 所有特征点的坐标

std::vector<std::vector<Point2f> > grid(grid_width*grid_height);

注意,std::vector<Point2f>即为 数组内每一个元素
grid 可理解为 一个对应到 图像像素平面 的二维数组, 两个维度大小分别为 grid_width, grid_height

然后 遍历 每一个特征点,
获取 所在网格, 然后 遍历 位于 该网格 以及 其 八连通 邻域内的特征点,
比较 其 距离是否 低于 距离阈值 即可
为什么 是 八连通 邻域呢?
如下图 所示, 即可得出该结论。即, 低于距离阈值的特征点 一定位于 该网格 以及 其 八连通 邻域内
八连通示意

const int grid_width = (w + cell_size - 1) / cell_size; 

这种除法都是为了向上取整,比如 w为100, cell_size 为10, 那么10个cell 刚刚就够了
但w 为91, cell_size 为10, 此时也需要 10个cell

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 Welzl 算法来实现点集最小包围球。以下是使用 OpenCV 和 C++ 实现的示例代码: ```c++ #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp> #include <iostream> #include <vector> #include <random> using namespace cv; using namespace std; // 计算两个点之间距离 double dist(Point3d p1, Point3d p2) { return norm(p1 - p2); } // 判断点 p 是否在圆心为 center,半径为 radius 的圆内 bool insideCircle(Point3d p, Point3d center, double radius) { return dist(p, center) < radius + 1e-6; } // 返回最小包围球的半径和圆心 void minSphere(vector<Point3d>& points, double& radius, Point3d& center) { int n = points.size(); if (n == 0) { radius = 0; center = Point3d(0, 0, 0); return; } else if (n == 1) { radius = 0; center = points[0]; return; } else if (n == 2) { radius = dist(points[0], points[1]) / 2; center = (points[0] + points[1]) / 2; return; } // 随机打乱顺序 random_shuffle(points.begin(), points.end()); // 递归求解 vector<Point3d> rest(points.begin() + 1, points.end()); minSphere(rest, radius, center); if (insideCircle(points[0], center, radius)) return; rest.push_back(points[0]); radius = 0; center = points[0]; for (int i = 0; i < rest.size(); i++) { if (!insideCircle(rest[i], center, radius)) { vector<Point3d> sub(rest.begin(), rest.begin() + i); minSphere(sub, radius, center); if (insideCircle(rest[i], center, radius)) return; rest.erase(sub.begin(), sub.end()); rest.push_back(rest[i]); } } } int main() { // 生成随机点集 vector<Point3d> points; random_device rd; mt19937 gen(rd()); uniform_real_distribution<double> dis(-1.0, 1.0); for (int i = 0; i < 10; i++) { double x = dis(gen); double y = dis(gen); double z = dis(gen); points.push_back(Point3d(x, y, z)); } // 求解最小包围球 double radius; Point3d center; minSphere(points, radius, center); // 绘制点集最小包围球 Mat img(600, 600, CV_8UC3, Scalar(255, 255, 255)); for (auto p : points) { Point2d p2d(p.x * 200 + 300, p.y * 200 + 300); circle(img, p2d, 2, Scalar(0, 0, 255), -1); } Point2d center2d(center.x * 200 + 300, center.y * 200 + 300); circle(img, center2d, radius * 200, Scalar(0, 255, 0), 2); imshow("Minimum Bounding Sphere", img); waitKey(); return 0; } ``` 这里我们使用了 `Point3d` 类型来表示三维点,`minSphere` 函数实现了递归求解最小包围球的过程,`insideCircle` 函数用于判断一个点是否在圆内。最后,我们使用 OpenCV 绘制了点集最小包围球。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值