OpenCV_4.2.0/opencv_contrib-4.2.0/modules/rgbd/src/warpfield.cpp

354 lines
9.4 KiB
C++

#include "precomp.hpp"
#include "warpfield.hpp"
namespace cv {
namespace dynafu {
WarpField::WarpField(int _maxNeighbours, int K, int levels, float baseResolution, float resolutionGrowth):
k(K), n_levels(levels),
nodes(), maxNeighbours(_maxNeighbours), // good amount for dense kinfu pointclouds
baseRes(baseResolution),
resGrowthRate(resolutionGrowth),
regGraphNodes(n_levels-1),
heirarchy(n_levels-1),
nodeIndex(nullptr)
{
CV_Assert(k <= DYNAFU_MAX_NEIGHBOURS);
}
NodeVectorType const& WarpField::getNodes() const
{
return nodes;
}
std::vector<NodeVectorType> const& WarpField::getGraphNodes() const
{
return regGraphNodes;
}
heirarchyType const& WarpField::getRegGraph() const
{
return heirarchy;
}
bool PtCmp(cv::Point3f a, cv::Point3f b)
{
return (a.x < b.x) ||
((a.x >= b.x) && (a.y < b.y)) ||
((a.x >= b.x) && (a.y >= b.y) && (a.z < b.z));
}
Ptr<flann::GenericIndex<flann::L2_Simple<float> > > WarpField::getNodeIndex() const
{
return nodeIndex;
}
Mat getNodesPos(NodeVectorType nv)
{
Mat nodePos((int)nv.size(), 3, CV_32F);
for(int i = 0; i < (int)nv.size(); i++)
{
nodePos.at<float>(i, 0) = nv[i]->pos.x;
nodePos.at<float>(i, 1) = nv[i]->pos.y;
nodePos.at<float>(i, 2) = nv[i]->pos.z;
}
return nodePos;
}
void WarpField::updateNodesFromPoints(InputArray inputPoints)
{
Mat points_matrix(inputPoints.size().height, 3, CV_32F);
if(inputPoints.channels() == 1)
{
points_matrix = inputPoints.getMat().colRange(0, 3);
}
else
{
points_matrix = inputPoints.getMat().reshape(1).colRange(0, 3).clone();
}
cvflann::LinearIndexParams params;
flann::GenericIndex<flann::L2_Simple <float> > searchIndex(points_matrix, params);
AutoBuffer<bool> validIndex;
removeSupported(searchIndex, validIndex);
NodeVectorType newNodes;
if((int)nodes.size() > k)
{
newNodes = subsampleIndex(points_matrix, searchIndex, validIndex, baseRes, nodeIndex);
}
else
{
newNodes = subsampleIndex(points_matrix, searchIndex, validIndex, baseRes);
}
initTransforms(newNodes);
nodes.insert(nodes.end(), newNodes.begin(), newNodes.end());
nodesPos = getNodesPos(nodes);
//re-build index
nodeIndex = new flann::GenericIndex<flann::L2_Simple<float> >(nodesPos,
cvflann::LinearIndexParams());
constructRegGraph();
}
void WarpField::removeSupported(flann::GenericIndex<flann::L2_Simple<float> >& ind,
AutoBuffer<bool>& validInd)
{
validInd.allocate(ind.size());
std::fill_n(validInd.data(), ind.size(), true);
for(WarpNode* n: nodes)
{
std::vector<float> query = {n->pos.x, n->pos.y, n->pos.z};
std::vector<int> indices_vec(maxNeighbours);
std::vector<float> dists_vec(maxNeighbours);
ind.radiusSearch(query, indices_vec, dists_vec, n->radius, cvflann::SearchParams());
for(auto i: indices_vec)
{
validInd[i] = false;
}
}
}
NodeVectorType WarpField::subsampleIndex(Mat& pmat,
flann::GenericIndex<flann::L2_Simple<float> >& ind,
AutoBuffer<bool>& validIndex, float res,
Ptr<flann::GenericIndex<flann::L2_Simple<float> > > knnIndex)
{
CV_TRACE_FUNCTION();
NodeVectorType temp_nodes;
for(int i = 0; i < (int)validIndex.size(); i++)
{
if(!validIndex[i])
{
continue;
}
std::vector<int> indices_vec(maxNeighbours);
std::vector<float> dist_vec(maxNeighbours);
ind.radiusSearch(pmat.row(i), indices_vec, dist_vec, res, cvflann::SearchParams());
Ptr<WarpNode> wn = new WarpNode;
Point3f centre(0, 0, 0);
float len = 0;
for(int index: indices_vec)
{
if(validIndex[index])
{
centre += Point3f(pmat.at<float>(index, 0),
pmat.at<float>(index, 1),
pmat.at<float>(index, 2));
len++;
}
}
centre /= len;
wn->pos = centre;
for(auto index: indices_vec)
{
validIndex[index] = false;
}
std::vector<int> knn_indices(k+1, 0);
std::vector<float> knn_dists(k+1, 0);
std::vector<float> query = {wn->pos.x, wn->pos.y, wn->pos.z};
if(knnIndex != nullptr)
{
knnIndex->knnSearch(query, knn_indices, knn_dists, (k+1), cvflann::SearchParams());
wn->radius = *std::max_element(knn_dists.begin(), knn_dists.end());
}
else
{
wn->radius = res;
}
wn->transform = Affine3f::Identity();
temp_nodes.push_back(wn);
}
return temp_nodes;
}
void WarpField::initTransforms(NodeVectorType nv)
{
if(nodesPos.size().height == 0)
{
return;
}
for(auto nodePtr: nv)
{
std::vector<int> knnIndices(k);
std::vector<float> knnDists(k);
std::vector<float> query = {nodePtr->pos.x, nodePtr->pos.y, nodePtr->pos.z};
nodeIndex->knnSearch(query ,knnIndices, knnDists, k, cvflann::SearchParams());
std::vector<float> weights(knnIndices.size());
std::vector<Affine3f> transforms(knnIndices.size());
size_t i = 0;
for(int idx: knnIndices)
{
weights[i] = nodes[idx]->weight(nodePtr->pos);
transforms[i++] = nodes[idx]->transform;
}
Affine3f pose = DQB(weights, transforms);
// linearly interpolate translations
Vec3f translation(0,0,0);
float totalWeight = 0;
for(i = 0; i < transforms.size(); i++)
{
translation += weights[i]*transforms[i].translation();
totalWeight += weights[i];
}
if(totalWeight < 1e-5) translation = Vec3f(0, 0, 0);
else translation /= totalWeight;
nodePtr->transform = Affine3f(pose.rotation(), translation);
}
}
void WarpField::constructRegGraph()
{
CV_TRACE_FUNCTION();
regGraphNodes.clear();
if(n_levels == 1) // First level (Nwarp) is already stored in nodes
{
return;
}
float effResolution = baseRes*resGrowthRate;
NodeVectorType curNodes = nodes;
Mat curNodeMatrix = getNodesPos(curNodes);
Ptr<flann::GenericIndex<flann::L2_Simple<float> > > curNodeIndex(
new flann::GenericIndex<flann::L2_Simple<float> >(curNodeMatrix,
cvflann::LinearIndexParams()));
for(int l = 0; l < (n_levels-1); l++)
{
AutoBuffer<bool> nodeValidity;
nodeValidity.allocate(curNodeIndex->size());
std::fill_n(nodeValidity.data(), curNodeIndex->size(), true);
NodeVectorType coarseNodes = subsampleIndex(curNodeMatrix, *curNodeIndex, nodeValidity,
effResolution);
initTransforms(coarseNodes);
Mat coarseNodeMatrix = getNodesPos(coarseNodes);
Ptr<flann::GenericIndex<flann::L2_Simple<float> > > coarseNodeIndex(
new flann::GenericIndex<flann::L2_Simple<float> >(coarseNodeMatrix,
cvflann::LinearIndexParams()));
heirarchy[l] = std::vector<nodeNeighboursType>(curNodes.size());
for(int i = 0; i < (int)curNodes.size(); i++)
{
std::vector<int> children_indices(k);
std::vector<float> children_dists(k);
std::vector<float> query = {curNodeMatrix.at<float>(i, 0),
curNodeMatrix.at<float>(i, 1),
curNodeMatrix.at<float>(i, 2)};
coarseNodeIndex->knnSearch(query, children_indices, children_dists, k,
cvflann::SearchParams());
heirarchy[l][i].fill(-1);
std::copy(children_indices.begin(), children_indices.end(), heirarchy[l][i].begin());
}
regGraphNodes.push_back(coarseNodes);
curNodes = coarseNodes;
curNodeMatrix = coarseNodeMatrix;
curNodeIndex = coarseNodeIndex;
effResolution *= resGrowthRate;
}
}
Point3f WarpField::applyWarp(Point3f p, const nodeNeighboursType neighbours, int n, bool normal) const
{
CV_TRACE_FUNCTION();
if(n == 0)
{
return p;
}
float totalWeight = 0;
Point3f WarpedPt(0,0,0);
for(int i = 0; i < n; i++)
{
Ptr<WarpNode> neigh = nodes[neighbours[i]];
float w = neigh->weight(p);
if(w < 0.01)
{
continue;
}
Matx33f R = neigh->transform.rotation();
Point3f newPt(0, 0, 0);
if(normal)
{
newPt = R * p;
}
else
{
newPt = R * (p - neigh->pos) + neigh->pos;
Vec3f T = neigh->transform.translation();
newPt.x += T[0];
newPt.y += T[1];
newPt.z += T[2];
}
WarpedPt += newPt * w;
totalWeight += w;
}
WarpedPt /= totalWeight;
if(totalWeight == 0)
{
return p;
}
else
{
return WarpedPt;
}
}
void WarpField::setAllRT(Affine3f warpRT)
{
for(auto n: nodes)
{
n->transform = warpRT;
}
}
} // namepsace dynafu
} // namespace cv