Spaces:
Sleeping
Sleeping
using namespace DBoW2; | |
namespace py = pybind11; | |
void changeStructure(const cv::Mat &plain, std::vector<cv::Mat> &out) | |
{ | |
out.resize(plain.rows); | |
for(int i = 0; i < plain.rows; ++i) | |
out[i] = plain.row(i); | |
} | |
void estimateAffine3D(const py::array_t<uint8_t> &pointsA, const py::array_t<uint8_t> &pointsB){ | |
const py::buffer_info buf = pointsA.request(); | |
const cv::Mat lpts(buf.shape[0], 3, CV_64F, (double *)buf.ptr); | |
std::cout << lpts << std::endl; | |
// const cv::Mat image(buf.shape[0], buf.shape[1], CV_64F, (unsigned char*)buf.ptr); | |
} | |
typedef std::vector<std::tuple<double, double, double, double, double>> MatchList; | |
class DPRetrieval { // The class | |
private: | |
std::vector<std::vector<cv::Mat > > features; | |
std::vector<cv::Mat > descs; | |
std::vector<std::vector<cv::KeyPoint > > kps; | |
OrbDatabase db; | |
const int rad; | |
public: // Access specifier | |
DPRetrieval(const std::string vocab_path, const int rad) : rad(rad){ | |
std::cout << "Loading the vocabulary " << vocab_path << std::endl; | |
// load the vocabulary from disk | |
OrbVocabulary voc; | |
voc.loadFromTextFile(vocab_path); | |
db = OrbDatabase(voc, false, 0); // false = do not use direct index | |
// (so ignore the last param) | |
// The direct index is useful if we want to retrieve the features that | |
// belong to some vocabulary node. | |
// db creates a copy of the vocabulary, we may get rid of "voc" now | |
} | |
void insert_image(const py::array_t<uint8_t> &array){ | |
const py::buffer_info buf = array.request(); | |
if ((buf.shape.size() != 3) || buf.shape[2] != 3) | |
throw std::invalid_argument( "invalid image shape" ); | |
const cv::Mat image(buf.shape[0], buf.shape[1], CV_8UC3, (unsigned char*)buf.ptr); | |
// const cv::Mat image = cv::imread(filepath, 0); | |
// cv::imshow("test", image); | |
// cv::waitKey(0); | |
cv::Mat mask; | |
std::vector<cv::KeyPoint> keypoints; | |
cv::Mat descriptors; | |
cv::Ptr<cv::ORB> orb = cv::ORB::create(); | |
orb->detectAndCompute(image, mask, keypoints, descriptors); | |
std::vector<cv::Mat > feats; | |
changeStructure(descriptors, feats); | |
kps.push_back(keypoints); | |
features.push_back(feats); | |
descs.push_back(descriptors); | |
db.add(features.back()); | |
} | |
MatchList match_pair(const int ti, const int qi) const { | |
cv::BFMatcher matcher(cv::NORM_HAMMING, true); | |
cv::Mat train_descriptors = descs.at(ti); | |
cv::Mat query_descriptors = descs.at(qi); | |
std::vector<std::vector<cv::DMatch>> knn_matches; | |
matcher.knnMatch(query_descriptors, train_descriptors, knn_matches, 1); // Finds the 2 best matches for each descriptor | |
MatchList output; | |
for (const auto &pair_list : knn_matches){ | |
if (!pair_list.empty()){ | |
const auto &pair = pair_list.back(); | |
auto trainpt = (kps[ti][pair.trainIdx].pt); | |
auto querypt = (kps[qi][pair.queryIdx].pt); | |
output.emplace_back(trainpt.x, trainpt.y, querypt.x, querypt.y, pair.distance); | |
} | |
} | |
return output; | |
} | |
auto query(const int i) const { | |
if ((i >= features.size()) || (i < 0)) | |
throw std::invalid_argument( "index invalid" ); | |
QueryResults ret; | |
db.query(features[i], ret, 4); | |
std::tuple<float, int, MatchList> output(-1, -1, {}); | |
for (const auto &r : ret){ | |
int j = r.Id; | |
if ((abs(j - i) >= rad) && (r.Score > std::get<0>(output))){ | |
const MatchList matches = match_pair(i, j); | |
output = std::make_tuple(r.Score, j, matches); | |
} | |
} | |
return output; | |
} | |
}; | |
PYBIND11_MODULE(dpretrieval, m) { | |
py::class_<DPRetrieval>(m, "DPRetrieval") | |
.def(py::init<std::string, int>()) | |
.def("insert_image", &DPRetrieval::insert_image) | |
.def("match_pair", &DPRetrieval::match_pair) | |
.def("query", &DPRetrieval::query); | |
m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO); | |
m.attr("__version__") = "dev"; | |
} | |