You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
7.2 KiB
C++

/*
* registration implementation
*
* Copyright (C) HamidReza Houshiar
*
* Released under the GPL version 3.
*
*/
#include "slam6d/fbr/registration.h"
using namespace std;
namespace fbr{
registration::registration(unsigned int minD, double minE, unsigned int minI, registration_method method){
minDistance = minD;
minError = minE;
minInlier = minI;
rMethod = method;
bestError = minError;
bestErrorIndex = 0;
for(int i = 0; i < 16; i++)
bestAlign[i] = 0;
}
registration::registration(){
minDistance = 50;
minError = 50;
minInlier = 5;
rMethod = RANSAC;
bestError = minError;
bestErrorIndex = 0;
for(int i = 0; i < 16; i++)
bestAlign[i] = 0;
}
int registration::getCoord(vector<cv::KeyPoint> fKeypoints, vector<cv::KeyPoint> sKeypoints, vector<cv::DMatch> matches, cv::Mat fPMap, cv::Mat sPMap, int idx, cv::Point3f& cq, cv::Point3f& ct){
int x, y;
y = fKeypoints[matches[idx].queryIdx].pt.x;
x = fKeypoints[matches[idx].queryIdx].pt.y;
if(fKeypoints[matches[idx].queryIdx].pt.x - x > 0.5)
x++;
if(fKeypoints[matches[idx].queryIdx].pt.y - y > 0.5)
y++;
cv::Mat_<cv::Vec3f> _fPMap = fPMap;
float sqr = sqrt (_fPMap(x,y)[0] * _fPMap(x,y)[0] + _fPMap(x,y)[1] * _fPMap(x,y)[1] + _fPMap(x,y)[2] * _fPMap(x,y)[2]);
if(sqr != 0){
cq.x = _fPMap(x,y)[0];
cq.y = _fPMap(x,y)[1];
cq.z = _fPMap(x,y)[2];
}
else
return 0;
y = sKeypoints[matches[idx].trainIdx].pt.x;
x = sKeypoints[matches[idx].trainIdx].pt.y;
if(sKeypoints[matches[idx].trainIdx].pt.x - x > 0.5)
x++;
if(sKeypoints[matches[idx].trainIdx].pt.y - y > 0.5)
y++;
cv::Mat_<cv::Vec3f> _sPMap = sPMap;
sqr = sqrt (_sPMap(x,y)[0] * _sPMap(x,y)[0] + _sPMap(x,y)[1] * _sPMap(x,y)[1] + _sPMap(x,y)[2] * _sPMap(x,y)[2]);
if(sqr != 0){
ct.x = _sPMap(x,y)[0];
ct.y = _sPMap(x,y)[1];
ct.z = _sPMap(x,y)[2];
}
else
return 0;
return 1;
}
void registration::pointToArray(cv::Point3f c, double* cd){
cd[0] = c.x;
cd[1] = c.y;
cd[2] = c.z;
}
cv::Point3f registration::coordTransform(cv::Point3f p, double* align){
cv::Point3f tp;
tp.x = align[0]*p.x + align[4]*p.y + align[8]*p.z + align[12];
tp.y = align[1]*p.x + align[5]*p.y + align[9]*p.z + align[13];
tp.z = align[2]*p.x + align[6]*p.y + align[10]*p.z + align[14];
return tp;
}
int registration::findAlign(unsigned int i, unsigned int j, unsigned int k, cv::Mat fPMap, vector<cv::KeyPoint> fKeypoints, cv::Mat sPMap, vector<cv::KeyPoint> sKeypoints, vector<cv::DMatch> matches){
cv::Point3f c1q, c2q, c3q, c1t, c2t, c3t;
if(i == j || i == k || j == k)
return 0;
//get the coordinates
if(getCoord(fKeypoints, sKeypoints, matches, fPMap, sPMap, i, c1q, c1t) == 0)
return 0;
if(getCoord(fKeypoints, sKeypoints, matches, fPMap, sPMap, j, c2q, c2t) == 0)
return 0;
if(getCoord(fKeypoints, sKeypoints, matches, fPMap, sPMap, k, c3q, c3t) == 0)
return 0;
//check for min distance
if(norm(c1q - c2q) < minDistance || norm(c1q - c3q) < minDistance || norm(c2q - c3q) < minDistance || norm(c1t - c2t) < minDistance || norm(c1t - c3t) < minDistance || norm(c2t - c3t) < minDistance)
return 0;
//calculate the centroids
cv::Point3f centroidq, centroidt;
centroidq = (c1q + c2q + c3q);
centroidt = (c1t + c2t + c3t);
centroidq.x = centroidq.x / 3;
centroidq.y = centroidq.y / 3;
centroidq.z = centroidq.z / 3;
centroidt.x = centroidt.x / 3;
centroidt.y = centroidt.y / 3;
centroidt.z = centroidt.z / 3;
//put each point into double array
double c1qd[3], c2qd[3], c3qd[3], c1td[3], c2td[3], c3td[3];
cv::Point3f temp;
pointToArray(c1q, c1qd);
pointToArray(c2q, c2qd);
pointToArray(c3q, c3qd);
pointToArray(c1t, c1td);
pointToArray(c2t, c2td);
pointToArray(c3t, c3td);
//create PtPair and calc the align with icp6D_QUAT
vector<PtPair> pairs;
pairs.push_back(PtPair(c1qd, c1td));
pairs.push_back(PtPair(c2qd, c2td));
pairs.push_back(PtPair(c3qd, c3td));
double align[16];
double centroidqd[3], centroidtd[3];
pointToArray(centroidq, centroidqd);
pointToArray(centroidt, centroidtd);
icp6D_QUAT q(true);
q.Point_Point_Align(pairs, align, centroidqd, centroidtd);
//transform the matches with align if the error is less than minerror
double iError = 0;
unsigned int eIdx = 0;
for(unsigned int p = 0; p < matches.size(); p++){
if(p == i || p == j || p == k)
continue;
cv::Point3f cq, ct, ct_trans;
if(getCoord(fKeypoints, sKeypoints, matches, fPMap, sPMap, p, cq, ct) == 0)
continue;
ct_trans = coordTransform(ct, align);
if(norm(ct_trans - cq) < minError){
iError += norm(ct_trans - cq);
eIdx++;
}
}
//check for mininlier and find the best align
if(eIdx > minInlier){
double aError = iError / eIdx;
if(aError - iInfluence*eIdx < bestError - iInfluence*bestErrorIndex){
bestError = aError;
bestErrorIndex = eIdx;
for(int a = 0; a < 16; a++)
bestAlign[a] = align[a];
}
}
return 1;
}
void registration::findRegistration(cv::Mat fPMap, vector<cv::KeyPoint> fKeypoints, cv::Mat sPMap, vector<cv::KeyPoint> sKeypoints, vector<cv::DMatch> matches){
//go through all matches
if(rMethod == ALL){
for(unsigned int i = 0; i < matches.size(); i++)
for(unsigned int j = 0; j < matches.size(); j++)
for(unsigned int k = 0; k < matches.size(); k++){
findAlign(i, j, k, fPMap, fKeypoints, sPMap, sKeypoints, matches);
}
}
//RANSAC
if(rMethod == RANSAC)
for(int r = 0; r < RANSACITR; r++){
if((r % (RANSACITR/10)) == 0){
cout<<"RANSAC iteration: "<<(r / (RANSACITR/10) + 1) * 10 <<"%"<<endl;
}
unsigned int i = rand() % matches.size();
unsigned int j = rand() % matches.size();
unsigned int k = rand() % matches.size();
findAlign(i, j, k, fPMap, fKeypoints, sPMap, sKeypoints, matches);
}
}
unsigned int registration::getMinDistance(){
return minDistance;
}
double registration::getMinError(){
return minError;
}
unsigned int registration::getMinInlier(){
return minInlier;
}
registration_method registration::getRegistrationMethod(){
return rMethod;
}
double * registration::getBestAlign(){
return bestAlign;
}
double registration::getBestError(){
return bestError;
}
unsigned int registration::getBestErrorIndex(){
return bestErrorIndex;
}
void registration::getDescription(){
cout<<"Registration minDistance: "<<minDistance<<", minError: "<<minError<<", minInlier: "<<minInlier<<", registrationMethod: "<<registrationMethodToString(rMethod)<<"."<<endl;
cout<<"Registration finished with besterror of: "<<bestError<<" and best error index of: "<<bestErrorIndex<<"."<<endl;
cout<<"align Matrix:"<<endl;
if(bestErrorIndex > 0){
cout<<bestAlign[0]<<" "<<bestAlign[4]<<" "<<bestAlign[8]<<" "<<bestAlign[12]<<endl;
cout<<bestAlign[1]<<" "<<bestAlign[5]<<" "<<bestAlign[9]<<" "<<bestAlign[13]<<endl;
cout<<bestAlign[2]<<" "<<bestAlign[6]<<" "<<bestAlign[10]<<" "<<bestAlign[14]<<endl;
cout<<bestAlign[3]<<" "<<bestAlign[7]<<" "<<bestAlign[11]<<" "<<bestAlign[15]<<endl;
}
cout<<endl;
}
}