一、给出问题
构建包含以下文件的工程(opencv_test)
各文件内容给出如下:
# CMakeLists.txt
cmake_minimum_required(VERSION 2.18)
project(opencv_test)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} main.cpp
kdtree.cpp
kdtree.h)
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})
// kdtree.cpp
#include "kdtree.h"
KDTree::KDTree(std::vector<Point> ref_points)
{
ref_points_ = ref_points;
ConstructKDTree(kdtree_);
}
void KDTree::ConstructKDTree(cv::flann::Index* kdtree) // C1
{
std::vector<cv::Point2f> features = { { 1,1 },{ 2, 2},{ 3, 3},{ 4, 4},{ 2, 4} };
cv::Mat source = cv::Mat(features).reshape(1);
source.convertTo(source, CV_32F);
cv::flann::KDTreeIndexParams indexParams(2);
kdtree = new cv::flann::Index(source, indexParams); // C2
}
void KDTree::GetIndex()
{
//预设knnSearch所需参数及容器
int queryNum = 3;//用于设置返回邻近点的个数
std::vector<float> vecQuery(2);//存放查询点的容器
std::vector<int> vecIndex(queryNum);//存放返回的点索引
std::vector<float> vecDist(queryNum);//存放距离
cv::flann::SearchParams params(32);//设置knnSearch搜索参数
//KD树knn查询
vecQuery = { 3, 4};
printf("ok31\n");
kdtree_->knnSearch(vecQuery, vecIndex, vecDist, queryNum, params); // C3
printf("ok32\n");
std::cout << "vecDist: " << std::endl;
for (auto&x : vecDist)
std::cout << x << " ";
std::cout << std::endl;
std::cout << "vecIndex: " << std::endl;
for (auto&x : vecIndex)
std::cout << x << " ";
std::cout<<std::endl;
}
// kdtree.h
#ifndef KDTREE_H
#define KDTREE_H
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <memory>
struct Point{
double x;
double y;
double z;
};
class KDTree{
public:
KDTree(std::vector<Point> ref_points);
void ConstructKDTree(cv::flann::Index* kdtree); // C4
void GetIndex();
private:
// cv::Mat source;
std::vector<Point> ref_points_;
cv::flann::Index* kdtree_; // C5
};
#endif // KDTREE_H
// main.cpp
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include "kdtree.h"
int main() {
//用于构造kdtree的点集
std::vector<Point> points;
KDTree kdtree = KDTree(points);
kdtree.GetIndex();
return 0;
}
构建好后
cd ~/opencv_test/build
cmake ..
make
./opencv_test
报错:
ok31
Segmentation fault (core dumped)
根据标记可知,运行到kdtree->knnSearch(...)
这里出错的。
根据opencv kdtree的用法后半部分描述的:
所以,感觉和指针释放有关。于是做了几组实验,分别记录成功不不成功的情况。
二、不同组合的实验与结果
实验通过:对上面代码中注释有C1-C5的各行进行不同设置。
2.1 指针引用cv::flann::Index*& kdtree
作为函数输入(成功)
void KDTree::ConstructKDTree(cv::flann::Index*& kdtree) // C1 变化
kdtree = new cv::flann::Index(source, indexParams); // C2
kdtree_->knnSearch(vecQuery, vecIndex, vecDist, queryNum, params); // C3
void ConstructKDTree(cv::flann::Index*& kdtree); // C4 变化
cv::flann::Index* kdtree_; // C5
2.2 继2.1后,采用内置函数build构建kdtree(失败)
void KDTree::ConstructKDTree(cv::flann::Index*& kdtree) // C1 变化
kdtree->build(source, indexParams); // C2 变化
kdtree_->knnSearch(vecQuery, vecIndex, vecDist, queryNum, params); // C3
void ConstructKDTree(cv::flann::Index*& kdtree); // C4 变化
cv::flann::Index* kdtree_; // C5
内置函数build也可以构建kdtree
发现,直接在kdtree->build(...)
处报错。
2.3 采用变量引用cv::flann::Index& kdtree
(成功)
void KDTree::ConstructKDTree(cv::flann::Index& kdtree) // C1 变化
kdtree.build(source, indexParams); // C2 变化
kdtree_.knnSearch(vecQuery, vecIndex, vecDist, queryNum, params); // C3
void ConstructKDTree(cv::flann::Index& kdtree); // C4 变化
cv::flann::Index kdtree_; // C5
2.4 在2.3基础上采用类构造函数实例化kdtree(失败)
void KDTree::ConstructKDTree(cv::flann::Index& kdtree) // C1 变化
kdtree = cv::flann::Index(source, indexParams); // C2 变化
kdtree_.knnSearch(vecQuery, vecIndex, vecDist, queryNum, params); // C3
void ConstructKDTree(cv::flann::Index& kdtree); // C4 变化
cv::flann::Index kdtree_; // C5
根据标记可知,运行到kdtree.knnSearch(...)
这里出错的。
2.5 在2.4基础上,成员函数不用引用输入
void KDTree::ConstructKDTree(cv::flann::Index kdtree) // C1 变化
kdtree = cv::flann::Index(source, indexParams); // C2 变化
kdtree_.knnSearch(vecQuery, vecIndex, vecDist, queryNum, params); // C3
void ConstructKDTree(cv::flann::Index kdtree); // C4 变化
cv::flann::Index kdtree_; // C5
根据标记可知,初始化kdtree时就出错。
结论
- 内部成员函数传入kdtree变量,无论是否是指针,都要以引用的方式传入;
- 如果是指针变量,以
kdtree = new cv::flann::Index(source, indexParams);
构建kdtree; - 如果是一般变量,则以
kdtree.build(source, indexParams);
构建kdtree.