opencv knnSearch 使用

本文详细介绍使用OpenCV进行最近邻搜索的示例代码,包括单点和多点搜索,并提供了一个CMake模板用于项目构建。同时,展示了如何用Python和OpenCV显示深度图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

本博客主要包括 利用 opencv 的最近邻搜索. 示例中包括 对一个点和对多个点的.
同时附带了自己目前经常用的Cmake 文件, 以及一个 python opencv 显示深度图的示例.

主要参考的网址有
OpenCV——KD Tree(介绍完整的flann邻近搜索)
opencv官网

主要的示例代码


#include<opencv2/flann/miniflann.hpp>
#include<iostream>
#include<vector>
using namespace std;

int main(){
/*
 * vector<cv::Point2f> m_pOriPtXY={ cv::Point2f(1,1), cv::Point2f(2,2),
               cv::Point2f(3,3), cv::Point2f(4,4), cv::Point2f(5,5), cv::Point2f(2,4)};
 * */
    vector<cv::Point2f> features={{1,1}, {2, 2}, {3, 3}, {4, 4}, {2, 4}};
    vector<cv::Point2f> raw_queries={{0,0}, {3, 4}, {4, 3}};

    /**建立kd树索引**/
    cv::Mat source = cv::Mat(features).reshape(1);
    //cout<<source.size()<<endl;
    source.convertTo(source,  CV_32F);
    //cout<<source.size()<<endl;
	// 注意这里其实最后还是转到一个 Mat 上 Mat 的大小是 n * p_dim [下面输出的size 是 先 width, 然后height]
    // 原本的意思是建立个新的地址进行转换
    cv::Mat queries = cv::Mat(raw_queries);
    //cout<<queries.size()<<endl; // 1 x 3
    queries = queries.reshape(1);
    //cout<<queries.size()<<endl; // 2 x 3
    queries.convertTo(queries,  CV_32F)
    //cout<<queries.size()<<endl; // 2 x 3

    cv::flann::KDTreeIndexParams indexParams(2);
    cv::flann::Index kdtree(source, indexParams); //此部分建立kd-tree索引同上例,故不做详细叙述

    /**预设knnSearch所需参数及容器**/
    unsigned queryNum = 2;//用于设置返回邻近点的个数
    vector<float> vecQuery(2);//存放 查询点 的容器(本例都是vector类型)
    vector<int> vecIndex(queryNum);//存放返回的点索引
    vector<float> vecDist(queryNum);//存放距离
    cv::flann::SearchParams params(32);//设置knnSearch搜索参数

    /**KD树knn查询**/
    vecQuery = {2.5, 2.6};
    kdtree.knnSearch(vecQuery, vecIndex, vecDist, queryNum, params);
    //请注意这句的逻辑:由先前生成的kdtree索引对象调用knnSearch()函数,进行点的knn搜索

    cv::Mat indices;
    cv::Mat dists;

    kdtree.knnSearch(queries, indices, dists, 1, params);

    cout<<"vecDist: "<<endl;
    for(auto&x :vecDist){
        cout<<x<<" ";
    }
    cout<<endl;

    cout<<"vecIndex: "<<endl;
    for(auto&x :vecIndex){
        cout<<x<<" ";
    }
    cout<<endl;

    cout<<indices<<endl; // 0 based
    cout<<dists<<endl; // pow
    return 0;
}

自己简单的CMake 模板

├── CMakeLists.txt
└── src/ # code in
cmake_minimum_required(VERSION 2.8) 
set(targetname test_ocv) 
PROJECT(${targetname}) 

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 

# #####
if(CMAKE_COMPILER_IS_GNUCC)
    add_definitions(-std=c++11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -O3")
endif(CMAKE_COMPILER_IS_GNUCC)
# #####

#######
if(DEFINED _chj_libs)
else()
    set(_chj_libs "")
endif()

IF (WIN32)
	include(xxxxxx/opencv3.1/OpenCVConfig.cmake)
ELSEIF (APPLE)
	MESSAGE(STATUS "Now is Apple systens.")
ELSEIF (UNIX)
    FIND_PACKAGE(OpenCV 3)
ENDIF ()

INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS})
LINK_DIRECTORIES(${OPENCV_LIB_DIR})

LIST(APPEND _chj_libs opencv_core opencv_highgui opencv_imgproc opencv_calib3d opencv_imgcodecs )
######

file(GLOB_RECURSE CURRENT_HEADERS  ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h)  
source_group("Include" FILES ${CURRENT_HEADERS})
file(GLOB_RECURSE Source  ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)  
source_group("Source" FILES ${Source})  

include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/src
)

ADD_EXECUTABLE(main ${Source})

target_link_libraries(main ${_chj_libs} )

显示深度图

今天才知道不用plt, ocv也能做很多事情

with open(fdepth, "rb") as fp:
    raw = np.fromfile(fp, np.float32, h*w*3).reshape(h, w, 3)

raw = raw[:, :,2]
raw[raw>2000]=0 # 去掉背景

cv.normalize(raw, raw, 0,255, cv.NORM_MINMAX)
#p(raw.dtype)
raw=raw.astype(np.uint8)
#p(raw.dtype)
#new_raw=raw.copy()
raw = cv.applyColorMap(raw, cv.COLORMAP_JET)
<think>我们正在讨论OpenCV中的KDTree功能。用户希望了解如何在OpenCV中实现和使用KDTree。根据引用[1]中的内容,用户有一个CMakeLists.txt文件配置了OpenCV环境,因此我们假设用户已经安装了OpenCV,并且版本至少为3.4.8(因为路径中指定了opencv-3.4.8)。在OpenCV中,KDTree的功能是通过cv::flann模块提供的。flann(FastLibraryforApproximateNearestNeighbors)是一个用于快速近似最近邻搜索的库,OpenCV集成了这个库。其中包含了KDTree的实现。使用步骤通常包括:1.构建数据:将特征点数据转换为Mat矩阵,每一行是一个特征点的描述子(或坐标)。2.构建KDTree索引:使用cv::flann::Index类的构造函数,指定算法为KDTree。3.进行最近邻搜索:使用knnSearch方法进行k近邻搜索。注意:在OpenCV的flann模块中,KDTree可以通过指定索引参数来创建。常用的参数是algorithm(算法类型)和trees(树的数目,即森林中KDTree的数量)。接下来,我们将详细说明实现步骤,并给出示例代码。</think> ### OpenCV 中的 KDTree 实现与使用指南 OpenCV 中的 KDTree 通过 `cv::flann` 模块实现,专用于高效的多维空间最近邻搜索。以下是核心实现方法和使用步骤,基于 OpenCV 3.4+(您引用的版本兼容)[^1]: --- #### **1. 基本实现原理** - **数据结构**:通过递归分割 k 维空间构建二叉树,每个节点存储一个数据点和分割超平面 - **算法参数**: - `index_params = cv::flann::KDTreeIndexParams(trees)` `trees` 指定森林中 KDTree 的数量(默认为 1) - `search_params = cv::flann::SearchParams(checks)` `checks` 控制搜索精度(值越大越精确,速度越慢) --- #### **2. 基础使用示例** ```cpp #include <opencv2/core.hpp> #include <opencv2/flann.hpp> int main() { // 构建数据集 (1000个3维点) cv::Mat dataset(1000, 3, CV_32F); randu(dataset, 0.0f, 100.0f); // 随机生成数据 // 创建 KDTree 索引 cv::flann::Index kdIndex(dataset, cv::flann::KDTreeIndexParams(4), // 4棵树组成的森林 cvflann::FLANN_DIST_EUCLIDEAN); // 欧氏距离 // 查询点 cv::Mat query = (cv::Mat_<float>(1, 3) << 50, 50, 50); // 搜索最近邻 (k=3) std::vector<int> indices(3); std::vector<float> dists(3); kdIndex.knnSearch(query, indices, dists, 3, cv::flann::SearchParams(32)); // 检查32个叶节点 // 输出结果 for (int i = 0; i < 3; ++i) { std::cout << "第" << i+1 << "近邻: 索引=" << indices[i] << " 距离=" << dists[i] << std::endl; } return 0; } ``` --- #### **3. 关键应用场景** 1. **特征匹配加速** 加速 SIFT/SURF 等算法的特征匹配,替代暴力匹配器 ```cpp cv::Ptr<cv::FlannBasedMatcher> matcher = cv::FlannBasedMatcher::create( new cv::flann::KDTreeIndexParams(5)); matcher->knnMatch(descriptors1, descriptors2, matches, 2); ``` 2. **点云处理** 用于 3D 点云的最近邻查询(需将点云转为 `N×3` 的 `CV_32F` 矩阵) 3. **目标跟踪** 在高维特征空间快速定位相似目标(如颜色直方图/纹理特征) --- #### **4. 性能优化建议** - **参数调优**: - 数据维度 > 20 时增加 `trees` 数量(通常设 4-16) - 平衡精度/速度:`checks` 建议范围 [16, 128] - **数据类型优化**: - 整型数据转换为 `CV_32S` 避免隐式浮点转换 - 启用 OpenMP 并行编译加速建树过程 ```cmake # 在您的CMakeLists.txt中[^1] find_package(OpenMP REQUIRED) target_link_libraries(ASIFT OpenMP::OpenMP_CXX) ``` --- #### **5. 与竞品对比** | 算法 | 适用场景 | OpenCV 实现 | |-------------|--------------------------|------------------| | **KDTree** | 中低维数据 (<50维) | `cv::flann::Index` | | **LSH** | 高维二值特征 | `cv::flann::LshIndexParams` | | **Hilbert** | 流式数据/动态更新 | 需第三方库集成 | > 注:超过 50 维时推荐使用近似算法如 Annoy 或 Faiss[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值