当前位置:网站首页>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
边栏推荐
猜你喜欢
Call procedure of function
类的继承与派生
Basic knowledge of network in cloud computing
jenkspy包安装
Robocode教程4——Robocode的游戏物理
1007 go running (hdu6808) in the fourth game of 2020 Hangzhou Electric Multi school competition
【UDS统一诊断服务】二、网络层协议(1)— 网络层概述与功能
利用文件保存数据(c语言)
Gesture recognition research
Completely clean up MySQL win
随机推荐
ArcGIS表转EXCEL超出上限转换失败
识别验证码
Explanation of login page
Object转Json差异之Gson fastJson jackson 修改字段名
xlsxwriter.exceptions.FileCreateError: [Errno 13] Permission denied问题
Export the articles written in CSDN to PDF format
搭建openstack平台
LaTeX配置与使用
GDB debugger installation and use
Type conversion in C #
对象数组与对象指针
MySQL groups are sorted by a field, and the first value is taken
Rust 中的 Cell 共享可变指针
C语言实现2048小游戏方向合并逻辑
grub boot. S code analysis
【UDS统一诊断服务】三、应用层协议(2)
SQL sorts according to the specified content
函数的调用过程
斯坦福机器学习课程汇总
进程间通信的方式