当前位置:网站首页>OpenCV使用 GenericIndex 进行 KNN 搜索
OpenCV使用 GenericIndex 进行 KNN 搜索
2022-04-23 05:48:00 【mightbxg】
以前不了解 OpenCV 的 flann 模块,做 K-nearest-neighbour 搜索一直用的是 Github 上的一个很简单的实现:kd-tree。这个 KD tree 实现很简洁,仅有一个头文件,方便加入自己的工程,而且使用也特别方便。不过据说 cv::flann 实现的 KNN 速度更快,而且功能更加强大,所以大概看了一下怎么用。
鉴于目前网上相关资料很少,而且基本上能找到的都是关于已经被弃用的 cv::flann::Index,OpenCV 官方文档也缺乏相关说明,我在这里记录一下自己所了解的 cv::flann::GenericIndex 的用法(其实还有很多东西没搞明白,欢迎评论区交流)。
示例代码
// generate points
constexpr size_t num = 100;
constexpr int width = 640, height = 480;
vector<Point2f> pts;
Mat image(height, width, CV_8UC3, cv::Scalar::all(255));
{
mt19937 gen(0);
uniform_real_distribution<float> dis_x(0.f, float(width));
uniform_real_distribution<float> dis_y(0.f, float(height));
pts.reserve(num);
for (size_t i = 0; i < num; ++i) {
pts.emplace_back(dis_x(gen), dis_y(gen));
circle(image, pts.back(), 2, cv::Scalar::all(0), cv::FILLED);
}
}
cout << "num of points: " << pts.size() << '\n';
Point2f query(width / 2.f, height / 2.f);
cout << "query: " << query.x << " " << query.y << '\n';
circle(image, query, 2, {
0, 0, 255 }, cv::FILLED);
// build kd-tree
auto kdtree = flann::GenericIndex(Mat(pts).reshape(1), cvflann::KDTreeIndexParams {
2 }, flann::L2<float> {
});
// knn search
constexpr int K = 4;
vector<int> indices(K);
vector<float> dists(K);
kdtree.knnSearch({
query.x, query.y }, indices, dists, K, cvflann::SearchParams {
});
cout << " nearest " << K << ": " << Mat(indices).t() << endl;
{
Mat result = image.clone();
for (int i : indices) {
line(result, query, pts[i], {
0, 255, 0 });
circle(result, pts[i], 2, {
255, 0, 0 }, cv::FILLED);
}
imwrite("knn_result.png", result);
}
// radius search
constexpr float radius = 50.f;
constexpr size_t max_num = 10;
indices.resize(max_num, -1);
dists.resize(max_num);
kdtree.radiusSearch({
query.x, query.y }, indices, dists, radius * radius, cvflann::SearchParams {
});
cout << "in radius " << radius << ": " << Mat(indices).t() << endl;
{
Mat result = image.clone();
for (int i : indices) {
if (i < 0)
break;
line(result, query, pts[i], {
0, 255, 0 });
circle(result, pts[i], 2, {
255, 0, 0 }, cv::FILLED);
}
circle(result, query, radius, {
0, 0, 255 });
imwrite("radius_result.png", result);
}
这个例子是在大小 640×480 图像上随机生成 100 个点,然后利用 KD tree 查找距离图像中心最近的 4 个点(KNN search),以及与图像中心距离小于 50 像素的点(radius search):


flann::GenericIndex 支持暴力搜索 (LinearIndexParams)、KD tree (KDTreeIndexParams)、层级聚类 (HierarchicalClusteringIndexParams) 等搜索策略,同时支持 L1、L2、Hamming 等距离计算方法,功能确实很强大,参见 OpenCV Docs。
需要注意的是,在使用 L2 距离的情况下, radiusSearch 中的 radius 参数其实是半径的平方(所以代码中写的是 radius*radius),参见 issue#12683。
版权声明
本文为[mightbxg]所创,转载请带上原文链接,感谢
https://blog.csdn.net/mightbxg/article/details/118338302
边栏推荐
- 根据SQL语句查询出的结果集,将其封装为json
- -- SQL query and return limit rows
- [ThreadX] h743zi + lan8720 + ThreadX + netx duo transplantation
- 队列解决约瑟夫问题
- 【UDS统一诊断服务】四、诊断典型服务(5)— 功能/元件测试功能单元(例行程序功能单元0x31)
- Object转Json差异之Gson fastJson jackson 修改字段名
- Busybox initrd and initialization process
- Database - sorting data
- 爬取手游网站游戏详情和评论(MQ+多线程)
- 带默认模板实参的类模板与模板模板形参的匹配
猜你喜欢

Gesture recognition research

Call procedure of function

搭建jpress个人博客

Graduation project, curriculum link, student achievement evaluation system

Cross domain issues - allow origin header contains multiple values but only one is allowed

Robocode教程7——雷达锁定

文件查看命令和用户管理命令

【UDS统一诊断服务】一、诊断概述(3)— ISO 15765体系结构

Swagger2 generates API documents

PM2 deploy nuxt project
随机推荐
安装pyshp库
Uniapp encapsulates request
进程间通信-互斥锁
如何安装jsonpath包
爬取手游网站游戏详情和评论(MQ+多线程)
用C语言实现重写strcmp等四个函数
GDB debugger installation and use
word排版遇到的格式问题
Feign请求日志统一打印
爬取小米有品app商品数据
共用数据的保护
Rust的闭包类型(Fn, FnMut, FnOne的区别)
Miscellaneous 1
【学习一下】HF-Net 训练
线程和进程的关系和区别是什么
小区房价可视化
Make your own small program
类的继承与派生
The waterfall waterfall flow of uview realizes single column and loads more
【OpenCV】使用 FileStorage 读写 Eigen 向量