You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2128 lines
70 KiB
2128 lines
70 KiB
6 months ago
|
#include "alignment.h"
|
||
|
#include <omp.h>
|
||
|
|
||
|
//-------------------------------------------------alignment order
|
||
|
void ImageAligner::sortImageOrder(int referNo, bool shallLoad, bool isInorder)
|
||
|
{
|
||
|
cout<<"#Finding topology ..."<<endl;
|
||
|
TopoFinder topoBar(_matcher);
|
||
|
|
||
|
_similarityMat = topoBar.findTopology(shallLoad, isInorder);
|
||
|
Mat_<double> costGraph = Utils::buildCostGraph(_similarityMat);
|
||
|
cout<<"-Completed"<<endl;
|
||
|
|
||
|
cout<<"#Graph analysis for aligning order ..."<<endl;
|
||
|
if (referNo == -1)
|
||
|
{
|
||
|
_visitOrder = Graph::FloydForPath(costGraph);
|
||
|
_refImgNo = _visitOrder[0].imgNo;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_visitOrder = Graph::DijkstraForPath(costGraph, referNo);
|
||
|
_refImgNo = _visitOrder[0].imgNo;
|
||
|
}
|
||
|
cout<<"Image "<<_refImgNo<<" become the reference frame."<<endl;
|
||
|
cout<<"-Completed"<<endl;
|
||
|
|
||
|
divideImageGroups();
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::divideImageGroups()
|
||
|
{
|
||
|
//! the first group imgIndex
|
||
|
_groupCusorList.push_back(0);
|
||
|
//! the following group cursors
|
||
|
int offset = OPT_GROUP_NUM;
|
||
|
for (int imgIndex = offset; imgIndex < _imgNum; imgIndex += offset)
|
||
|
{
|
||
|
if (_imgNum-imgIndex < offset/2)
|
||
|
{
|
||
|
imgIndex = _imgNum-1;
|
||
|
}
|
||
|
_groupCusorList.push_back(imgIndex);
|
||
|
}
|
||
|
int groupNum = _groupCusorList.size();
|
||
|
if (_groupCusorList[groupNum-1] < _imgNum-1)
|
||
|
{
|
||
|
_groupCusorList.push_back(_imgNum-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//-------------------------------------------------alignment
|
||
|
void ImageAligner::imageStitcherbyGroup(int referNo, bool isSeqData, bool loadKeypts, bool loadTopology)
|
||
|
{
|
||
|
//! =============== extract features ===============
|
||
|
bool extractFeature = !loadKeypts; //! ### set this for new data
|
||
|
_matcher = new PointMatcher(_filePathList, extractFeature);
|
||
|
_imgSizeList = _matcher->_imgSizeList;
|
||
|
|
||
|
//! =============== Topology sorting ===============
|
||
|
bool shallLoad = loadTopology, isInOrder = isSeqData; //! ### set this for new data
|
||
|
sortImageOrder(referNo, shallLoad, isInOrder);
|
||
|
|
||
|
//! =============== build match net ===============
|
||
|
fillImageMatchNet();
|
||
|
|
||
|
// loadHomographies();
|
||
|
cout<<"#Sequential image alignment start ..."<<endl;
|
||
|
Mat_<double> identMatrix = Mat::eye(3,3,CV_64FC1); //cvtMatrix of reference image
|
||
|
_alignModelList.push_back(identMatrix);
|
||
|
_initModelList.push_back(identMatrix);
|
||
|
Quadra bar;
|
||
|
bar.imgSize = _imgSizeList[_visitOrder[0].imgNo];
|
||
|
bar.centroid = Point2d(bar.imgSize.width/2, bar.imgSize.height/2);
|
||
|
_projCoordSet.push_back(bar);
|
||
|
for (int i = 1; i < _groupCusorList.size(); i ++)
|
||
|
{
|
||
|
int sIndex = _groupCusorList[i-1]+1;
|
||
|
int eIndex = _groupCusorList[i];
|
||
|
cout<<"Aligning Group "<<i<<endl;
|
||
|
for (int t = sIndex; t <= eIndex; t ++)
|
||
|
{
|
||
|
cout<<_visitOrder[t].imgNo<<" ";
|
||
|
if ((t-sIndex+1)%10 == 0)
|
||
|
{
|
||
|
cout<<endl;
|
||
|
}
|
||
|
}
|
||
|
cout<<"Models initializing ..."<<endl;
|
||
|
solveGroupModels(sIndex, eIndex);
|
||
|
cout<<"Done!"<<endl;
|
||
|
// recheckTopology(sIndex, eIndex);
|
||
|
cout<<endl;
|
||
|
bool needRefine = false;
|
||
|
if (needRefine && i == _groupCusorList.size()-1)
|
||
|
{
|
||
|
bundleAdjustingA(1, eIndex);
|
||
|
//sIndex = 0;
|
||
|
//RefineAligningModels(sIndex, eIndex);
|
||
|
}
|
||
|
}
|
||
|
cout<<"-Completed!"<<endl;
|
||
|
// labelGroupNodes();
|
||
|
saveModelParams();
|
||
|
drawTopologyNet();
|
||
|
outputPrecise();
|
||
|
saveMosaicImageP();
|
||
|
cout<<"== Mosaic completed successfully!\n";
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::imageStitcherbySolos(int referNo, bool isSeqData, bool loadKeypts, bool loadTopology)
|
||
|
{
|
||
|
//! =============== extract features ===============
|
||
|
bool extractFeature = !loadKeypts; //! set this for new data
|
||
|
_matcher = new PointMatcher(_filePathList, extractFeature);
|
||
|
_imgSizeList = _matcher->_imgSizeList;
|
||
|
//! =============== Topology sorting ===============
|
||
|
bool shallLoad = loadTopology, isInOrder = isSeqData; //! ### set this for new data
|
||
|
sortImageOrder(referNo, shallLoad, isInOrder);
|
||
|
// return false;
|
||
|
//! =============== build match net ===============
|
||
|
fillImageMatchNet();
|
||
|
|
||
|
cout<<"#Sequential image alignment start ..."<<endl;
|
||
|
Mat_<double> identMatrix = Mat::eye(3,3,CV_64FC1); //cvtMatrix of reference image
|
||
|
_alignModelList.push_back(identMatrix);
|
||
|
_initModelList.push_back(identMatrix);
|
||
|
bool needRefine = true;
|
||
|
for (int i = 1; i < _imgNum; i ++)
|
||
|
{
|
||
|
cout<<"Aligning Image "<<_visitOrder[i].imgNo<<" ";
|
||
|
solveSingleModel(i);
|
||
|
if (needRefine && 0)
|
||
|
{
|
||
|
for (int j = 0; j < _groupCusorList.size(); j ++)
|
||
|
{
|
||
|
if (i == _groupCusorList[j])
|
||
|
{
|
||
|
int sIndex = _groupCusorList[j-1]+1;
|
||
|
int eIndex = _groupCusorList[j];
|
||
|
bundleAdjustingA(sIndex, eIndex);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
cout<<"Done!"<<endl;
|
||
|
}
|
||
|
if (needRefine)
|
||
|
{
|
||
|
cout<<"-Bundle adjustment ..."<<endl;
|
||
|
bundleAdjustingA(1, _imgNum-1);
|
||
|
}
|
||
|
|
||
|
cout<<"-Completed!"<<endl;
|
||
|
drawTopologyNet();
|
||
|
outputPrecise();
|
||
|
saveModelParams();
|
||
|
saveMosaicImageP();
|
||
|
cout<<"== Mosaic completed successfully!\n";
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::fillImageMatchNet()
|
||
|
{
|
||
|
cout<<"#Loading topology matching data ..."<<endl;
|
||
|
//!initialization
|
||
|
for (int i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
Match_Net curBar;
|
||
|
curBar.imgNo = i;
|
||
|
_matchNetList.push_back(curBar);
|
||
|
}
|
||
|
int sum = 0;
|
||
|
//! fill matching data
|
||
|
for (int i = 0; i < _imgNum-1; i ++)
|
||
|
{
|
||
|
for (int j = i+1; j < _imgNum; j ++)
|
||
|
{
|
||
|
int PtNum = _similarityMat(i,j);
|
||
|
if (PtNum == 0)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
vector<Point2d> PtSet1, PtSet2;
|
||
|
if (!Utils::loadMatchPts(i,j,PtSet1,PtSet2))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
sum += PtSet1.size();
|
||
|
int indexj = findVisitIndex(j);
|
||
|
_matchNetList[i].relatedImgs.push_back(indexj);
|
||
|
_matchNetList[i].PointSet.push_back(PtSet1);
|
||
|
int indexi = findVisitIndex(i);
|
||
|
_matchNetList[j].relatedImgs.push_back(indexi);
|
||
|
_matchNetList[j].PointSet.push_back(PtSet2);
|
||
|
}
|
||
|
}
|
||
|
cout<<"-Completed! - with "<<sum<<" pairs of matches"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::solveGroupModels(int sIndex, int eIndex)
|
||
|
{
|
||
|
int measureNum = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
if (relatedNos[j] < i) //! avoid repeating counting
|
||
|
{
|
||
|
measureNum += pointSet[j].size();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
int paramNum = 6*(eIndex-sIndex+1);
|
||
|
Mat_<double> A = Mat(2*measureNum, paramNum, CV_64FC1, Scalar(0));
|
||
|
Mat_<double> L = Mat(2*measureNum, 1, CV_64FC1, Scalar(0));
|
||
|
int rn = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
int neigIndex = relatedNos[j];
|
||
|
if (neigIndex > i)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
int neigImgNo = _visitOrder[neigIndex].imgNo;
|
||
|
vector<int> neigRelatedNos = _matchNetList[neigImgNo].relatedImgs;
|
||
|
|
||
|
vector<Point2d> curPts, neigPts;
|
||
|
curPts = pointSet[j];
|
||
|
//! case 1 : aligning with aligned image
|
||
|
if (neigIndex < sIndex)
|
||
|
{
|
||
|
for (int t = 0; t < neigRelatedNos.size(); t ++)
|
||
|
{
|
||
|
if (neigRelatedNos[t] == i)
|
||
|
{
|
||
|
neigPts = _matchNetList[neigImgNo].PointSet[t];
|
||
|
Utils::pointTransform(_alignModelList[neigIndex], neigPts);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
int fillPos = 6*(i-sIndex);
|
||
|
for (int k = 0; k < curPts.size(); k ++)
|
||
|
{
|
||
|
A(2*rn,fillPos) = curPts[k].x; A(2*rn,fillPos+1) = curPts[k].y; A(2*rn,fillPos+2) = 1;
|
||
|
A(2*rn+1,fillPos+3) = curPts[k].x; A(2*rn+1,fillPos+4) = curPts[k].y; A(2*rn+1,fillPos+5) = 1;
|
||
|
L(2*rn) = neigPts[k].x;
|
||
|
L(2*rn+1) = neigPts[k].y;
|
||
|
rn ++;
|
||
|
}
|
||
|
}
|
||
|
//! case 2 : aligning with unaligned image
|
||
|
else if (neigIndex >= sIndex)
|
||
|
{
|
||
|
for (int t = 0; t < neigRelatedNos.size(); t ++)
|
||
|
{
|
||
|
if (neigRelatedNos[t] == i)
|
||
|
{
|
||
|
neigPts = _matchNetList[neigImgNo].PointSet[t];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
int fillPos1 = 6*(i-sIndex), fillPos2 = 6*(neigIndex-sIndex);
|
||
|
for (int k = 0; k < curPts.size(); k ++)
|
||
|
{
|
||
|
A(2*rn,fillPos1) = curPts[k].x; A(2*rn,fillPos1+1) = curPts[k].y; A(2*rn,fillPos1+2) = 1;
|
||
|
A(2*rn+1,fillPos1+3) = curPts[k].x; A(2*rn+1,fillPos1+4) = curPts[k].y; A(2*rn+1,fillPos1+5) = 1;
|
||
|
A(2*rn,fillPos2) = -neigPts[k].x; A(2*rn,fillPos2+1) = -neigPts[k].y; A(2*rn,fillPos2+2) = -1;
|
||
|
A(2*rn+1,fillPos2+3) = -neigPts[k].x; A(2*rn+1,fillPos2+4) = -neigPts[k].y; A(2*rn+1,fillPos2+5) = -1;
|
||
|
L(2*rn) = 0;
|
||
|
L(2*rn+1) = 0;
|
||
|
rn ++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Mat_<double> X = (A.t()*A).inv()*(A.t()*L);
|
||
|
for (int i = 0; i < paramNum; i += 6)
|
||
|
{
|
||
|
Mat_<double> affineModel = (Mat_<double>(3,3) << X(i) , X(i+1), X(i+2),
|
||
|
X(i+3), X(i+4), X(i+5),
|
||
|
0, 0, 1);
|
||
|
_alignModelList.push_back(affineModel);
|
||
|
_initModelList.push_back(affineModel);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::solveGroupModelsS(int sIndex, int eIndex)
|
||
|
{
|
||
|
int measureNum = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
if (relatedNos[j] < i) //! avoid repeating counting
|
||
|
{
|
||
|
measureNum += pointSet[j].size();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
int paramNum = 4*(eIndex-sIndex+1);
|
||
|
Mat_<double> A = Mat(2*measureNum, paramNum, CV_64FC1, Scalar(0));
|
||
|
Mat_<double> L = Mat(2*measureNum, 1, CV_64FC1, Scalar(0));
|
||
|
int rn = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
int neigIndex = relatedNos[j];
|
||
|
if (neigIndex > i)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
int neigImgNo = _visitOrder[neigIndex].imgNo;
|
||
|
vector<int> neigRelatedNos = _matchNetList[neigImgNo].relatedImgs;
|
||
|
|
||
|
vector<Point2d> curPts, neigPts;
|
||
|
curPts = pointSet[j];
|
||
|
//! case 1 : aligning with aligned image
|
||
|
if (neigIndex < sIndex)
|
||
|
{
|
||
|
for (int t = 0; t < neigRelatedNos.size(); t ++)
|
||
|
{
|
||
|
if (neigRelatedNos[t] == i)
|
||
|
{
|
||
|
neigPts = _matchNetList[neigImgNo].PointSet[t];
|
||
|
Utils::pointTransform(_alignModelList[neigIndex], neigPts);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
int fillPos = 4*(i-sIndex);
|
||
|
for (int k = 0; k < curPts.size(); k ++)
|
||
|
{
|
||
|
A(2*rn,fillPos) = curPts[k].x; A(2*rn,fillPos+1) = -curPts[k].y; A(2*rn,fillPos+2) = 1;
|
||
|
A(2*rn+1,fillPos) = curPts[k].y; A(2*rn+1,fillPos+1) = curPts[k].x; A(2*rn+1,fillPos+3) = 1;
|
||
|
L(2*rn) = neigPts[k].x;
|
||
|
L(2*rn+1) = neigPts[k].y;
|
||
|
rn ++;
|
||
|
}
|
||
|
}
|
||
|
//! case 2 : aligning with unaligned image
|
||
|
else if (neigIndex >= sIndex)
|
||
|
{
|
||
|
for (int t = 0; t < neigRelatedNos.size(); t ++)
|
||
|
{
|
||
|
if (neigRelatedNos[t] == i)
|
||
|
{
|
||
|
neigPts = _matchNetList[neigImgNo].PointSet[t];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
int fillPos1 = 4*(i-sIndex), fillPos2 = 4*(neigIndex-sIndex);
|
||
|
for (int k = 0; k < curPts.size(); k ++)
|
||
|
{
|
||
|
A(2*rn,fillPos1) = curPts[k].x; A(2*rn,fillPos1+1) = -curPts[k].y; A(2*rn,fillPos1+2) = 1;
|
||
|
A(2*rn+1,fillPos1) = curPts[k].y; A(2*rn+1,fillPos1+1) = curPts[k].x; A(2*rn+1,fillPos1+3) = 1;
|
||
|
A(2*rn,fillPos2) = -neigPts[k].x; A(2*rn,fillPos2+1) = neigPts[k].y; A(2*rn,fillPos2+2) = -1;
|
||
|
A(2*rn+1,fillPos2) = -neigPts[k].y; A(2*rn+1,fillPos2+1) = -neigPts[k].x; A(2*rn+1,fillPos2+3) = -1;
|
||
|
L(2*rn) = 0;
|
||
|
L(2*rn+1) = 0;
|
||
|
rn ++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Mat_<double> X = (A.t()*A).inv()*(A.t()*L);
|
||
|
for (int i = 0; i < paramNum; i += 4)
|
||
|
{
|
||
|
Mat_<double> affineModel = (Mat_<double>(3,3) << X(i) , -X(i+1), X(i+2),
|
||
|
X(i+1), X(i), X(i+3),
|
||
|
0, 0, 1);
|
||
|
// cout<<modelParam<<endl;
|
||
|
_alignModelList.push_back(affineModel);
|
||
|
_initModelList.push_back(affineModel);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::solveSingleModel(int imgIndex)
|
||
|
{
|
||
|
int measureNum = 0;
|
||
|
int imgNo = _visitOrder[imgIndex].imgNo;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
for (int i = 0; i < relatedNos.size(); i ++)
|
||
|
{
|
||
|
if (relatedNos[i] < imgIndex)
|
||
|
{
|
||
|
measureNum += pointSet[i].size();
|
||
|
}
|
||
|
}
|
||
|
int paramNum = 6;
|
||
|
Mat_<double> A = Mat(2*measureNum, paramNum, CV_64FC1, Scalar(0));
|
||
|
Mat_<double> L = Mat(2*measureNum, 1, CV_64FC1, Scalar(0));
|
||
|
int rn = 0;
|
||
|
vector<Point2d> PtSet1, PtSet2;
|
||
|
for (int i = 0; i < relatedNos.size(); i ++)
|
||
|
{
|
||
|
int neigIndex = relatedNos[i];
|
||
|
if (neigIndex > imgIndex)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
vector<Point2d> curPts, neigPts;
|
||
|
curPts = pointSet[i];
|
||
|
int neigImgNo = _visitOrder[neigIndex].imgNo;
|
||
|
vector<int> neigRelatedNos = _matchNetList[neigImgNo].relatedImgs;
|
||
|
for (int t = 0; t < neigRelatedNos.size(); t ++)
|
||
|
{
|
||
|
if (neigRelatedNos[t] == imgIndex)
|
||
|
{
|
||
|
neigPts = _matchNetList[neigImgNo].PointSet[t];
|
||
|
Utils::pointTransform(_alignModelList[neigIndex], neigPts);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
for (int k = 0; k < curPts.size(); k ++)
|
||
|
{
|
||
|
A(2*rn,0) = curPts[k].x; A(2*rn,1) = curPts[k].y; A(2*rn,2) = 1;
|
||
|
A(2*rn+1,3) = curPts[k].x; A(2*rn+1,4) = curPts[k].y; A(2*rn+1,5) = 1;
|
||
|
L(2*rn) = neigPts[k].x;
|
||
|
L(2*rn+1) = neigPts[k].y;
|
||
|
rn ++;
|
||
|
}
|
||
|
//! for homogaphy
|
||
|
//for (int k = 0; k < curPts.size(); k ++)
|
||
|
//{
|
||
|
// PtSet1.push_back(curPts[k]);
|
||
|
// PtSet2.push_back(neigPts[k]);
|
||
|
//}
|
||
|
}
|
||
|
Mat_<double> X = (A.t()*A).inv()*(A.t()*L);
|
||
|
Mat_<double> affineModel = (Mat_<double>(3,3) << X(0), X(1), X(2),
|
||
|
X(3), X(4), X(5),
|
||
|
0, 0, 1);
|
||
|
|
||
|
// Mat_<double> homoMat = findHomography(PtSet1, PtSet2, CV_RANSAC, 1.5);
|
||
|
|
||
|
_alignModelList.push_back(affineModel);
|
||
|
_initModelList.push_back(affineModel);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::bundleAdjusting(int sIndex, int eIndex)
|
||
|
{
|
||
|
cout<<"Bundle adjusting ...("<<eIndex-sIndex+1<<" images)"<<endl;
|
||
|
int measureNum = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
if (relatedNos[j] < i) //! avoid repeating counting
|
||
|
{
|
||
|
int num = pointSet[j].size();
|
||
|
num = num%3 == 0 ? (num/3) : (num/3+1);
|
||
|
measureNum += num; //! only 1/3 of matching pairs for optimization
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
int paramNum = 8*(eIndex-sIndex+1); //! optimizing homgraphic model with 8 DoF
|
||
|
double *X = new double[paramNum];
|
||
|
double *initX = new double[6*(eIndex-sIndex+1)];
|
||
|
buildIniSolution(X, initX, sIndex, eIndex);
|
||
|
//! parameters setting of least square optimization
|
||
|
double lambada = Lambada;
|
||
|
int max_iters = 10;
|
||
|
|
||
|
int rn = 0, ite = 0;
|
||
|
while (1)
|
||
|
{
|
||
|
double meanBias = 0;
|
||
|
rn = 0;
|
||
|
Mat_<double> AtA = Mat(paramNum, paramNum, CV_64FC1, Scalar(0));
|
||
|
Mat_<double> AtL = Mat(paramNum, 1, CV_64FC1, Scalar(0));
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
//! prepare relative data or parameters of current image
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
int neigIndex = relatedNos[j];
|
||
|
if (neigIndex > i)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
vector<Point2d> curPts, neigPts;
|
||
|
curPts = pointSet[j];
|
||
|
int neigImgNo = _visitOrder[neigIndex].imgNo;
|
||
|
vector<int> neigRelatedNos = _matchNetList[neigImgNo].relatedImgs;
|
||
|
for (int k = 0; k < neigRelatedNos.size(); k ++)
|
||
|
{
|
||
|
if (neigRelatedNos[k] == i)
|
||
|
{
|
||
|
neigPts = _matchNetList[neigImgNo].PointSet[k];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int curse0 = i-sIndex, curse1 = neigIndex-sIndex;
|
||
|
int fillPos0 = curse0*8, fillPos1 = curse1*8;
|
||
|
int num = curPts.size(), n = 0;
|
||
|
Mat_<double> Ai = Mat(num, paramNum, CV_64FC1, Scalar(0));
|
||
|
Mat_<double> Li = Mat(num, 1, CV_64FC1, Scalar(0));
|
||
|
double *AiPtr = (double*)Ai.data;
|
||
|
double *LiPtr = (double*)Li.data;
|
||
|
//! case 1 : with a fixed image
|
||
|
if (neigIndex < sIndex)
|
||
|
{
|
||
|
Utils::pointTransform(_alignModelList[neigIndex], neigPts);
|
||
|
for (int t = 0; t < curPts.size(); t += 3)
|
||
|
{
|
||
|
int x0 = curPts[t].x, y0 = curPts[t].y, x1 = neigPts[t].x, y1 = neigPts[t].y;
|
||
|
double hX0 = X[fillPos0+0]*x0 + X[fillPos0+1]*y0 + X[fillPos0+2]; //! h1*x0 + h2*y0 + h3
|
||
|
double hY0 = X[fillPos0+3]*x0 + X[fillPos0+4]*y0 + X[fillPos0+5]; //! h4*x0 + h5*y0 + h6
|
||
|
double hW0 = X[fillPos0+6]*x0 + X[fillPos0+7]*y0 + 1; //! h7*x0 + h8*y0 + 1
|
||
|
|
||
|
double orgx0 = initX[6*curse0+0]*x0 + initX[6*curse0+1]*y0 + initX[6*curse0+2];
|
||
|
double orgy0 = initX[6*curse0+3]*x0 + initX[6*curse0+4]*y0 + initX[6*curse0+5];
|
||
|
|
||
|
double K1 = 2*(hX0/hW0-x1) + 2*lambada*(hX0/hW0-orgx0);
|
||
|
double K2 = 2*(hY0/hW0-y1) + 2*lambada*(hY0/hW0-orgy0);
|
||
|
|
||
|
//! for : x = ...
|
||
|
AiPtr[n*paramNum+fillPos0] = K1*x0/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+1] = K1*y0/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+2] = K1*1/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+3] = K2*x0/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+4] = K2*y0/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+5] = K2*1/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+6] = -(K1+K2)*x0*hX0/(hW0*hW0);
|
||
|
AiPtr[n*paramNum+fillPos0+7] = -(K1+K2)*y0*hX0/(hW0*hW0);
|
||
|
|
||
|
double delta_d = (hX0/hW0-x1)*(hX0/hW0-x1) + (hY0/hW0-y1)*(hY0/hW0-y1);
|
||
|
double delta_r = lambada*((hX0/hW0-orgx0)*(hX0/hW0-orgx0) + (hY0/hW0-orgy0)*(hY0/hW0-orgy0));
|
||
|
LiPtr[n] = -(delta_d+delta_r);
|
||
|
|
||
|
double bias = sqrt(delta_d+delta_r);
|
||
|
meanBias += bias;
|
||
|
n ++;
|
||
|
rn ++;
|
||
|
}
|
||
|
//! get in normal equation matrix
|
||
|
Mat_<double> Ait = Ai.t();
|
||
|
Mat_<double> barA = Ait*Ai, barL = Ait*Li;
|
||
|
AtA += barA;
|
||
|
AtL += barL;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//! case 2 : with a remain optimized image
|
||
|
for (int t = 0; t < curPts.size(); t += 3)
|
||
|
{
|
||
|
int x0 = curPts[t].x, y0 = curPts[t].y, x1 = neigPts[t].x, y1 = neigPts[t].y;
|
||
|
double hX0 = X[fillPos0+0]*x0 + X[fillPos0+1]*y0 + X[fillPos0+2]; //! h1*x0 + h2*y0 + h3
|
||
|
double hY0 = X[fillPos0+3]*x0 + X[fillPos0+4]*y0 + X[fillPos0+5]; //! h4*x0 + h5*y0 + h6
|
||
|
double hW0 = X[fillPos0+6]*x0 + X[fillPos0+7]*y0 + 1; //! h7*x0 + h8*y0 + 1
|
||
|
double hX1 = X[fillPos1+0]*x1 + X[fillPos1+1]*y1 + X[fillPos1+2]; //! h1'*x1 + h2'*y1 + h3'
|
||
|
double hY1 = X[fillPos1+3]*x1 + X[fillPos1+4]*y1 + X[fillPos1+5]; //! h4'*x1 + h5'*y1 + h6'
|
||
|
double hW1 = X[fillPos1+6]*x1 + X[fillPos1+7]*y1 + 1; //! h7'*x1 + h8'*y1 + 1
|
||
|
|
||
|
double orgx0 = initX[6*curse0+0]*x0 + initX[6*curse0+1]*y0 + initX[6*curse0+2];
|
||
|
double orgy0 = initX[6*curse0+3]*x0 + initX[6*curse0+4]*y0 + initX[6*curse0+5];
|
||
|
double orgx1 = initX[6*curse1+0]*x1 + initX[6*curse1+1]*y1 + initX[6*curse1+2];
|
||
|
double orgy1 = initX[6*curse1+3]*x1 + initX[6*curse1+4]*y1 + initX[6*curse1+5];
|
||
|
|
||
|
double K1 = 2*(hX0/hW0-hX1/hW1) + 2*lambada*(hX0/hW0-orgx0);
|
||
|
double K2 = 2*(hY0/hW0-hY1/hW1) + 2*lambada*(hY0/hW0-orgy0);
|
||
|
double K3 = -2*(hX0/hW0-hX1/hW1) + 2*lambada*(hX1/hW1-orgx1);
|
||
|
double K4 = -2*(hY0/hW0-hY1/hW1) + 2*lambada*(hY1/hW1-orgy1);
|
||
|
|
||
|
//! for : x = ...
|
||
|
//! cur-image
|
||
|
AiPtr[n*paramNum+fillPos0] = K1*x0/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+1] = K1*y0/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+2] = K1*1/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+3] = K2*x0/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+4] = K2*y0/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+5] = K2*1/hW0;
|
||
|
AiPtr[n*paramNum+fillPos0+6] = -(K1+K2)*x0*hX0/(hW0*hW0);
|
||
|
AiPtr[n*paramNum+fillPos0+7] = -(K1+K2)*y0*hX0/(hW0*hW0);
|
||
|
//! neig-image
|
||
|
AiPtr[n*paramNum+fillPos1] = K3*x1/hW1;
|
||
|
AiPtr[n*paramNum+fillPos1+1] = K3*y1/hW1;
|
||
|
AiPtr[n*paramNum+fillPos1+2] = K3*1/hW1;
|
||
|
AiPtr[n*paramNum+fillPos1+3] = K4*x1/hW1;
|
||
|
AiPtr[n*paramNum+fillPos1+4] = K4*y1/hW1;
|
||
|
AiPtr[n*paramNum+fillPos1+5] = K4*1/hW1;
|
||
|
AiPtr[n*paramNum+fillPos1+6] = -(K3+K4)*x1*hX1/(hW1*hW1);
|
||
|
AiPtr[n*paramNum+fillPos1+7] = -(K3+K4)*y1*hX1/(hW1*hW1);
|
||
|
|
||
|
double delta_d = (hX0/hW0-hX1/hW1)*(hX0/hW0-hX1/hW1) + (hY0/hW0-hY1/hW1)*(hY0/hW0-hY1/hW1);
|
||
|
double delta_r = lambada*((hX0/hW0-orgx0)*(hX0/hW0-orgx0) + (hY0/hW0-orgy0)*(hY0/hW0-orgy0)
|
||
|
+ (hX1/hW1-orgx1)*(hX1/hW1-orgx1) + (hY1/hW1-orgy1)*(hY1/hW1-orgy1));
|
||
|
LiPtr[n] = -(delta_d+delta_r);
|
||
|
|
||
|
double bias = sqrt(delta_d+delta_r);
|
||
|
meanBias += bias;
|
||
|
rn ++;
|
||
|
n ++;
|
||
|
}
|
||
|
//! get in normal equation matrix
|
||
|
Mat_<double> Ait = Ai.t();
|
||
|
Mat_<double> barA = Ait*Ai, barL = Ait*Li;
|
||
|
AtA += barA;
|
||
|
AtL += barL;
|
||
|
}
|
||
|
}
|
||
|
meanBias = meanBias/rn;
|
||
|
cout<<"Iteration: "<<ite<<" with cost: "<<meanBias<<endl;
|
||
|
Mat_<double> dX = AtA.inv()*AtL;
|
||
|
double *dXPtr = (double*)dX.data;
|
||
|
double delta = 0; //! record the translation parameters of images
|
||
|
int num = 0;
|
||
|
for (int i = 0; i < paramNum; i ++)
|
||
|
{
|
||
|
X[i] += dXPtr[i];
|
||
|
if ((i+1)%8 == 3 || (i+1)%8 == 6)
|
||
|
{
|
||
|
// cout<<dX(i)<<endl;
|
||
|
delta += abs(dXPtr[i]);
|
||
|
num ++;
|
||
|
}
|
||
|
}
|
||
|
delta = delta/num;
|
||
|
if (delta < 0.08)
|
||
|
{
|
||
|
cout<<"Iteration has converged!"<<endl;
|
||
|
break;
|
||
|
}
|
||
|
if (ite++ == max_iters)
|
||
|
{
|
||
|
cout<<"arrive the limited iterations("<<max_iters<<")"<<endl;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
//! update the optimized parameters
|
||
|
int cnt = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
double *data = (double*)_alignModelList[i].data;
|
||
|
for (int j = 0; j < 8; j ++)
|
||
|
{
|
||
|
data[j] = X[cnt++];
|
||
|
}
|
||
|
}
|
||
|
delete []X;
|
||
|
delete []initX;
|
||
|
cout<<"This optimization round is over!"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::bundleAdjustingA(int sIndex, int eIndex)
|
||
|
{
|
||
|
cout<<"Bundle adjusting ...("<<eIndex-sIndex+1<<" images)"<<endl;
|
||
|
int measureNum = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
if (relatedNos[j] < i) //! avoid repeating counting
|
||
|
{
|
||
|
int num = pointSet[j].size();
|
||
|
num = num%3 == 0 ? (num/3) : (num/3+1);
|
||
|
measureNum += num; //! only 1/3 of matching pairs for optimization
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
int paramNum = 8*(eIndex-sIndex+1); //! optimizing homgraphic model with 8 DoF
|
||
|
Mat_<double> A = Mat(2*measureNum, paramNum, CV_64FC1, Scalar(0));
|
||
|
Mat_<double> L = Mat(2*measureNum, 1, CV_64FC1, Scalar(0));
|
||
|
double *APtr = (double*)A.data;
|
||
|
double *LPtr = (double*)L.data;
|
||
|
|
||
|
double *X = new double[paramNum];
|
||
|
double *initX = new double[6*(eIndex-sIndex+1)];
|
||
|
buildIniSolution(X, initX, sIndex, eIndex);
|
||
|
//! parameters setting of least square optimization
|
||
|
double lambada = Lambada;
|
||
|
int max_iters = 10;
|
||
|
|
||
|
int rn = 0, ite = 0;
|
||
|
while (1)
|
||
|
{
|
||
|
double meanBias = 0;
|
||
|
rn = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
//! prepare relative data or parameters of current image
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
int neigIndex = relatedNos[j];
|
||
|
if (neigIndex > i)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
vector<Point2d> curPts, neigPts;
|
||
|
curPts = pointSet[j];
|
||
|
int neigImgNo = _visitOrder[neigIndex].imgNo;
|
||
|
vector<int> neigRelatedNos = _matchNetList[neigImgNo].relatedImgs;
|
||
|
for (int k = 0; k < neigRelatedNos.size(); k ++)
|
||
|
{
|
||
|
if (neigRelatedNos[k] == i)
|
||
|
{
|
||
|
neigPts = _matchNetList[neigImgNo].PointSet[k];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int curse0 = i-sIndex, curse1 = neigIndex-sIndex;
|
||
|
int fillPos0 = curse0*8, fillPos1 = curse1*8;
|
||
|
//! case 1 : with a fixed image
|
||
|
if (neigIndex < sIndex)
|
||
|
{
|
||
|
Utils::pointTransform(_alignModelList[neigIndex], neigPts);
|
||
|
for (int t = 0; t < curPts.size(); t += 3)
|
||
|
{
|
||
|
int x0 = curPts[t].x, y0 = curPts[t].y, x1 = neigPts[t].x, y1 = neigPts[t].y;
|
||
|
double hX0 = X[fillPos0+0]*x0 + X[fillPos0+1]*y0 + X[fillPos0+2]; //! h1*x0 + h2*y0 + h3
|
||
|
double hY0 = X[fillPos0+3]*x0 + X[fillPos0+4]*y0 + X[fillPos0+5]; //! h4*x0 + h5*y0 + h6
|
||
|
double hW0 = X[fillPos0+6]*x0 + X[fillPos0+7]*y0 + 1; //! h7*x0 + h8*y0 + 1
|
||
|
|
||
|
//! for : x = ...
|
||
|
//A(2*rn,fillPos0) = (1+lambada)*x0/hW0; A(2*rn,fillPos0+1) = (1+lambada)*y0/hW0; A(2*rn,fillPos0+2) = (1+lambada)*1/hW0;
|
||
|
//A(2*rn,fillPos0+6) = -(1+lambada)*x0*hX0/(hW0*hW0); A(2*rn,fillPos0+7) = -(1+lambada)*y0*hX0/(hW0*hW0);
|
||
|
APtr[2*rn*paramNum+fillPos0] = (1+lambada)*x0/hW0; APtr[2*rn*paramNum+fillPos0+1] = (1+lambada)*y0/hW0; APtr[2*rn*paramNum+fillPos0+2] = (1+lambada)*1/hW0;
|
||
|
APtr[2*rn*paramNum+fillPos0+6] = -(1+lambada)*x0*hX0/(hW0*hW0); APtr[2*rn*paramNum+fillPos0+7] = -(1+lambada)*y0*hX0/(hW0*hW0);
|
||
|
double orgx0 = initX[6*curse0+0]*x0 + initX[6*curse0+1]*y0 + initX[6*curse0+2];
|
||
|
//L(2*rn) = lambada*(orgx0)+x1 - ((1+lambada)*hX0/hW0);
|
||
|
LPtr[2*rn] = lambada*(orgx0)+x1 - ((1+lambada)*hX0/hW0);
|
||
|
|
||
|
//! for : y = ...
|
||
|
//A(2*rn+1,fillPos0+3) = (1+lambada)*x0/hW0; A(2*rn+1,fillPos0+4) = (1+lambada)*y0/hW0; A(2*rn+1,fillPos0+5) = (1+lambada)*1/hW0;
|
||
|
//A(2*rn+1,fillPos0+6) = -(1+lambada)*x0*hY0/(hW0*hW0); A(2*rn+1,fillPos0+7) = -(1+lambada)*y0*hY0/(hW0*hW0);
|
||
|
APtr[(2*rn+1)*paramNum+fillPos0+3] = (1+lambada)*x0/hW0; APtr[(2*rn+1)*paramNum+fillPos0+4] = (1+lambada)*y0/hW0; APtr[(2*rn+1)*paramNum+fillPos0+5] = (1+lambada)*1/hW0;
|
||
|
APtr[(2*rn+1)*paramNum+fillPos0+6] = -(1+lambada)*x0*hY0/(hW0*hW0); APtr[(2*rn+1)*paramNum+fillPos0+7] = -(1+lambada)*y0*hY0/(hW0*hW0);
|
||
|
double orgy0 = initX[6*curse0+3]*x0 + initX[6*curse0+4]*y0 + initX[6*curse0+5];
|
||
|
//L(2*rn+1) = lambada*(orgy0)+y1 - ((1+lambada)*hY0/hW0);
|
||
|
LPtr[2*rn+1] = lambada*(orgy0)+y1 - ((1+lambada)*hY0/hW0);
|
||
|
|
||
|
double bias = (L(2*rn)*L(2*rn) + L(2*rn+1)*L(2*rn+1));
|
||
|
meanBias += sqrt(bias);
|
||
|
rn ++;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//! case 2 : with a remain optimized image
|
||
|
for (int t = 0; t < curPts.size(); t += 3)
|
||
|
{
|
||
|
int x0 = curPts[t].x, y0 = curPts[t].y, x1 = neigPts[t].x, y1 = neigPts[t].y;
|
||
|
double hX0 = X[fillPos0+0]*x0 + X[fillPos0+1]*y0 + X[fillPos0+2]; //! h1*x0 + h2*y0 + h3
|
||
|
double hY0 = X[fillPos0+3]*x0 + X[fillPos0+4]*y0 + X[fillPos0+5]; //! h4*x0 + h5*y0 + h6
|
||
|
double hW0 = X[fillPos0+6]*x0 + X[fillPos0+7]*y0 + 1; //! h7*x0 + h8*y0 + 1
|
||
|
|
||
|
double hX1 = X[fillPos1+0]*x1 + X[fillPos1+1]*y1 + X[fillPos1+2]; //! h1'*x1 + h2'*y1 + h3'
|
||
|
double hY1 = X[fillPos1+3]*x1 + X[fillPos1+4]*y1 + X[fillPos1+5]; //! h4'*x1 + h5'*y1 + h6'
|
||
|
double hW1 = X[fillPos1+6]*x1 + X[fillPos1+7]*y1 + 1; //! h7'*x1 + h8'*y1 + 1
|
||
|
|
||
|
//! for : x = ...
|
||
|
//! cur-image
|
||
|
//A(2*rn,fillPos0) = (1+lambada)*x0/hW0; A(2*rn,fillPos0+1) = (1+lambada)*y0/hW0; A(2*rn,fillPos0+2) = (1+lambada)*1/hW0;
|
||
|
//A(2*rn,fillPos0+6) = -(1+lambada)*x0*hX0/(hW0*hW0); A(2*rn,fillPos0+7) = -(1+lambada)*y0*hX0/(hW0*hW0);
|
||
|
APtr[2*rn*paramNum+fillPos0] = (1+lambada)*x0/hW0; APtr[2*rn*paramNum+fillPos0+1] = (1+lambada)*y0/hW0; APtr[2*rn*paramNum+fillPos0+2] = (1+lambada)*1/hW0;
|
||
|
APtr[2*rn*paramNum+fillPos0+6] = -(1+lambada)*x0*hX0/(hW0*hW0); APtr[2*rn*paramNum+fillPos0+7] = -(1+lambada)*y0*hX0/(hW0*hW0);
|
||
|
//! neig-image
|
||
|
//A(2*rn,fillPos1) = (lambada-1)*x1/hW1; A(2*rn,fillPos1+1) = (lambada-1)*y1/hW1; A(2*rn,fillPos1+2) = (lambada-1)*1/hW1;
|
||
|
//A(2*rn,fillPos1+6) = -(lambada-1)*x1*hX1/(hW1*hW1); A(2*rn,fillPos1+7) = -(lambada-1)*y1*hX1/(hW1*hW1);
|
||
|
APtr[2*rn*paramNum+fillPos1] = (lambada-1)*x1/hW1; APtr[2*rn*paramNum+fillPos1+1] = (lambada-1)*y1/hW1; APtr[2*rn*paramNum+fillPos1+2] = (lambada-1)*1/hW1;
|
||
|
APtr[2*rn*paramNum+fillPos1+6] = -(lambada-1)*x1*hX1/(hW1*hW1); APtr[2*rn*paramNum+fillPos1+7] = -(lambada-1)*y1*hX1/(hW1*hW1);
|
||
|
|
||
|
double orgx0 = initX[6*curse0+0]*x0 + initX[6*curse0+1]*y0 + initX[6*curse0+2];
|
||
|
double orgx1 = initX[6*curse1+0]*x1 + initX[6*curse1+1]*y1 + initX[6*curse1+2];
|
||
|
//L(2*rn) = lambada*(orgx0+orgx1) - ((1+lambada)*hX0/hW0 + (lambada-1)*hX1/hW1);
|
||
|
LPtr[2*rn] = lambada*(orgx0+orgx1) - ((1+lambada)*hX0/hW0 + (lambada-1)*hX1/hW1);
|
||
|
|
||
|
//! for : y = ...
|
||
|
//! cur-image
|
||
|
//A(2*rn+1,fillPos0+3) = (1+lambada)*x0/hW0; A(2*rn+1,fillPos0+4) = (1+lambada)*y0/hW0; A(2*rn+1,fillPos0+5) = (1+lambada)*1/hW0;
|
||
|
//A(2*rn+1,fillPos0+6) = -(1+lambada)*x0*hY0/(hW0*hW0); A(2*rn+1,fillPos0+7) = -(1+lambada)*y0*hY0/(hW0*hW0);
|
||
|
APtr[(2*rn+1)*paramNum+fillPos0+3] = (1+lambada)*x0/hW0; APtr[(2*rn+1)*paramNum+fillPos0+4] = (1+lambada)*y0/hW0; APtr[(2*rn+1)*paramNum+fillPos0+5] = (1+lambada)*1/hW0;
|
||
|
APtr[(2*rn+1)*paramNum+fillPos0+6] = -(1+lambada)*x0*hY0/(hW0*hW0); APtr[(2*rn+1)*paramNum+fillPos0+7] = -(1+lambada)*y0*hY0/(hW0*hW0);
|
||
|
//! neig-image
|
||
|
//A(2*rn+1,fillPos1+3) = (lambada-1)*x1/hW1; A(2*rn+1,fillPos1+4) = (lambada-1)*y1/hW1; A(2*rn+1,fillPos1+5) = (lambada-1)*1/hW1;
|
||
|
//A(2*rn+1,fillPos1+6) = -(lambada-1)*x1*hY1/(hW1*hW1); A(2*rn+1,fillPos1+7) = -(lambada-1)*y1*hY1/(hW1*hW1);
|
||
|
APtr[(2*rn+1)*paramNum+fillPos1+3] = (lambada-1)*x1/hW1; APtr[(2*rn+1)*paramNum+fillPos1+4] = (lambada-1)*y1/hW1; APtr[(2*rn+1)*paramNum+fillPos1+5] = (lambada-1)*1/hW1;
|
||
|
APtr[(2*rn+1)*paramNum+fillPos1+6] = -(lambada-1)*x1*hY1/(hW1*hW1); APtr[(2*rn+1)*paramNum+fillPos1+7] = -(lambada-1)*y1*hY1/(hW1*hW1);
|
||
|
|
||
|
double orgy0 = initX[6*curse0+3]*x0 + initX[6*curse0+4]*y0 + initX[6*curse0+5];
|
||
|
double orgy1 = initX[6*curse1+3]*x1 + initX[6*curse1+4]*y1 + initX[6*curse1+5];
|
||
|
//L(2*rn+1) = lambada*(orgy0+orgy1) - ((1+lambada)*hY0/hW0 + (lambada-1)*hY1/hW1);
|
||
|
LPtr[2*rn+1] = lambada*(orgy0+orgy1) - ((1+lambada)*hY0/hW0 + (lambada-1)*hY1/hW1);
|
||
|
|
||
|
double bias = (L(2*rn)*L(2*rn) + L(2*rn+1)*L(2*rn+1));
|
||
|
meanBias += sqrt(bias);
|
||
|
rn ++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
meanBias = meanBias/rn;
|
||
|
cout<<"Iteration: "<<ite<<" with cost: "<<meanBias<<endl;
|
||
|
Mat_<double> At = A.t();
|
||
|
Mat_<double> dX = (At*A).inv()*(At*L);
|
||
|
// cout<<A.t()*A<<endl<<(A.t()*L)<<endl;
|
||
|
double *dXPtr = (double*)dX.data;
|
||
|
// cout<<dX<<endl;
|
||
|
double delta = 0; //! record the translation parameters of images
|
||
|
int num = 0;
|
||
|
for (int i = 0; i < paramNum; i ++)
|
||
|
{
|
||
|
X[i] += dXPtr[i];
|
||
|
if ((i+1)%8 == 3 || (i+1)%8 == 6)
|
||
|
{
|
||
|
// cout<<dX(i)<<endl;
|
||
|
delta += abs(dXPtr[i]);
|
||
|
num ++;
|
||
|
}
|
||
|
}
|
||
|
delta = delta/num;
|
||
|
if (delta < 0.08)
|
||
|
{
|
||
|
cout<<"Iteration has converged!"<<endl;
|
||
|
break;
|
||
|
}
|
||
|
if (ite++ == max_iters)
|
||
|
{
|
||
|
cout<<"arrive the limited iterations("<<max_iters<<")"<<endl;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
//! update the optimized parameters
|
||
|
int cnt = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
double *data = (double*)_alignModelList[i].data;
|
||
|
for (int j = 0; j < 8; j ++)
|
||
|
{
|
||
|
data[j] = X[cnt++];
|
||
|
}
|
||
|
}
|
||
|
delete []X;
|
||
|
delete []initX;
|
||
|
cout<<"This optimization round is over!"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::bundleAdjustinga(int sIndex, int eIndex)
|
||
|
{
|
||
|
cout<<"Bundle adjusting ...("<<eIndex-sIndex+1<<" images)"<<endl;
|
||
|
int measureNum = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
if (relatedNos[j] < i) //! avoid repeating counting
|
||
|
{
|
||
|
int num = pointSet[j].size();
|
||
|
num = num%3 == 0 ? (num/3) : (num/3+1);
|
||
|
measureNum += num; //! only 1/3 of matching pairs for optimization
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
int paramNum = 8*(eIndex-sIndex+1); //! optimizing homgraphic model with 8 DoF
|
||
|
double *X = new double[paramNum];
|
||
|
double *initX = new double[6*(eIndex-sIndex+1)];
|
||
|
buildIniSolution(X, initX, sIndex, eIndex);
|
||
|
//! parameters setting of least square optimization
|
||
|
double lambada = Lambada;
|
||
|
int max_iters = 10;
|
||
|
|
||
|
int rn = 0, ite = 0;
|
||
|
while (1)
|
||
|
{
|
||
|
double meanBias = 0;
|
||
|
rn = 0;
|
||
|
Mat_<double> AtA = Mat(paramNum, paramNum, CV_64FC1, Scalar(0));
|
||
|
Mat_<double> AtL = Mat(paramNum, 1, CV_64FC1, Scalar(0));
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
//! prepare relative data or parameters of current image
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[imgNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[imgNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
int neigIndex = relatedNos[j];
|
||
|
if (neigIndex > i)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
vector<Point2d> curPts, neigPts;
|
||
|
curPts = pointSet[j];
|
||
|
int neigImgNo = _visitOrder[neigIndex].imgNo;
|
||
|
vector<int> neigRelatedNos = _matchNetList[neigImgNo].relatedImgs;
|
||
|
for (int k = 0; k < neigRelatedNos.size(); k ++)
|
||
|
{
|
||
|
if (neigRelatedNos[k] == i)
|
||
|
{
|
||
|
neigPts = _matchNetList[neigImgNo].PointSet[k];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int curse0 = i-sIndex, curse1 = neigIndex-sIndex;
|
||
|
int fillPos0 = curse0*8, fillPos1 = curse1*8;
|
||
|
int num = curPts.size(), n = 0;
|
||
|
Mat_<double> Ai = Mat(2*num, paramNum, CV_64FC1, Scalar(0));
|
||
|
Mat_<double> Li = Mat(2*num, 1, CV_64FC1, Scalar(0));
|
||
|
double *AiPtr = (double*)Ai.data;
|
||
|
double *LiPtr = (double*)Li.data;
|
||
|
//! case 1 : with a fixed image
|
||
|
if (neigIndex < sIndex)
|
||
|
{
|
||
|
Utils::pointTransform(_alignModelList[neigIndex], neigPts);
|
||
|
for (int t = 0; t < curPts.size(); t += 3)
|
||
|
{
|
||
|
int x0 = curPts[t].x, y0 = curPts[t].y, x1 = neigPts[t].x, y1 = neigPts[t].y;
|
||
|
double hX0 = X[fillPos0+0]*x0 + X[fillPos0+1]*y0 + X[fillPos0+2]; //! h1*x0 + h2*y0 + h3
|
||
|
double hY0 = X[fillPos0+3]*x0 + X[fillPos0+4]*y0 + X[fillPos0+5]; //! h4*x0 + h5*y0 + h6
|
||
|
double hW0 = X[fillPos0+6]*x0 + X[fillPos0+7]*y0 + 1; //! h7*x0 + h8*y0 + 1
|
||
|
|
||
|
//! for : x = ...
|
||
|
AiPtr[2*n*paramNum+fillPos0] = (1+lambada)*x0/hW0;
|
||
|
AiPtr[2*n*paramNum+fillPos0+1] = (1+lambada)*y0/hW0;
|
||
|
AiPtr[2*n*paramNum+fillPos0+2] = (1+lambada)*1/hW0;
|
||
|
AiPtr[2*n*paramNum+fillPos0+6] = -(1+lambada)*x0*hX0/(hW0*hW0);
|
||
|
AiPtr[2*n*paramNum+fillPos0+7] = -(1+lambada)*y0*hX0/(hW0*hW0);
|
||
|
double orgx0 = initX[6*curse0+0]*x0 + initX[6*curse0+1]*y0 + initX[6*curse0+2];
|
||
|
|
||
|
LiPtr[2*n] = lambada*(orgx0)+x1 - ((1+lambada)*hX0/hW0);
|
||
|
|
||
|
//! for : y = ...
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+3] = (1+lambada)*x0/hW0;
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+4] = (1+lambada)*y0/hW0;
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+5] = (1+lambada)*1/hW0;
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+6] = -(1+lambada)*x0*hY0/(hW0*hW0);
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+7] = -(1+lambada)*y0*hY0/(hW0*hW0);
|
||
|
double orgy0 = initX[6*curse0+3]*x0 + initX[6*curse0+4]*y0 + initX[6*curse0+5];
|
||
|
|
||
|
LiPtr[2*n+1] = lambada*(orgy0)+y1 - ((1+lambada)*hY0/hW0);
|
||
|
|
||
|
double bias = (LiPtr[2*n]*LiPtr[2*n] + LiPtr[2*n+1]*LiPtr[2*n+1]);
|
||
|
meanBias += sqrt(bias);
|
||
|
n ++;
|
||
|
rn ++;
|
||
|
}
|
||
|
//! get in normal equation matrix
|
||
|
Mat_<double> Ait = Ai.t();
|
||
|
Mat_<double> barA = Ait*Ai, barL = Ait*Li;
|
||
|
AtA += barA;
|
||
|
AtL += barL;
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//! case 2 : with a remain optimized image
|
||
|
for (int t = 0; t < curPts.size(); t += 3)
|
||
|
{
|
||
|
int x0 = curPts[t].x, y0 = curPts[t].y, x1 = neigPts[t].x, y1 = neigPts[t].y;
|
||
|
double hX0 = X[fillPos0+0]*x0 + X[fillPos0+1]*y0 + X[fillPos0+2]; //! h1*x0 + h2*y0 + h3
|
||
|
double hY0 = X[fillPos0+3]*x0 + X[fillPos0+4]*y0 + X[fillPos0+5]; //! h4*x0 + h5*y0 + h6
|
||
|
double hW0 = X[fillPos0+6]*x0 + X[fillPos0+7]*y0 + 1; //! h7*x0 + h8*y0 + 1
|
||
|
|
||
|
double hX1 = X[fillPos1+0]*x1 + X[fillPos1+1]*y1 + X[fillPos1+2]; //! h1'*x1 + h2'*y1 + h3'
|
||
|
double hY1 = X[fillPos1+3]*x1 + X[fillPos1+4]*y1 + X[fillPos1+5]; //! h4'*x1 + h5'*y1 + h6'
|
||
|
double hW1 = X[fillPos1+6]*x1 + X[fillPos1+7]*y1 + 1; //! h7'*x1 + h8'*y1 + 1
|
||
|
|
||
|
//! for : x = ...
|
||
|
//! cur-image
|
||
|
AiPtr[2*n*paramNum+fillPos0] = (1+lambada)*x0/hW0;
|
||
|
AiPtr[2*n*paramNum+fillPos0+1] = (1+lambada)*y0/hW0;
|
||
|
AiPtr[2*n*paramNum+fillPos0+2] = (1+lambada)*1/hW0;
|
||
|
AiPtr[2*n*paramNum+fillPos0+6] = -(1+lambada)*x0*hX0/(hW0*hW0);
|
||
|
AiPtr[2*n*paramNum+fillPos0+7] = -(1+lambada)*y0*hX0/(hW0*hW0);
|
||
|
//! neig-image
|
||
|
AiPtr[2*n*paramNum+fillPos1] = (lambada-1)*x1/hW1;
|
||
|
AiPtr[2*n*paramNum+fillPos1+1] = (lambada-1)*y1/hW1;
|
||
|
AiPtr[2*n*paramNum+fillPos1+2] = (lambada-1)*1/hW1;
|
||
|
AiPtr[2*n*paramNum+fillPos1+6] = -(lambada-1)*x1*hX1/(hW1*hW1);
|
||
|
AiPtr[2*n*paramNum+fillPos1+7] = -(lambada-1)*y1*hX1/(hW1*hW1);
|
||
|
|
||
|
double orgx0 = initX[6*curse0+0]*x0 + initX[6*curse0+1]*y0 + initX[6*curse0+2];
|
||
|
double orgx1 = initX[6*curse1+0]*x1 + initX[6*curse1+1]*y1 + initX[6*curse1+2];
|
||
|
|
||
|
LiPtr[2*n] = lambada*(orgx0+orgx1) - ((1+lambada)*hX0/hW0 + (lambada-1)*hX1/hW1);
|
||
|
|
||
|
//! for : y = ...
|
||
|
//! cur-image
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+3] = (1+lambada)*x0/hW0;
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+4] = (1+lambada)*y0/hW0;
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+5] = (1+lambada)*1/hW0;
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+6] = -(1+lambada)*x0*hY0/(hW0*hW0);
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos0+7] = -(1+lambada)*y0*hY0/(hW0*hW0);
|
||
|
//! neig-image
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos1+3] = (lambada-1)*x1/hW1;
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos1+4] = (lambada-1)*y1/hW1;
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos1+5] = (lambada-1)*1/hW1;
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos1+6] = -(lambada-1)*x1*hY1/(hW1*hW1);
|
||
|
AiPtr[(2*n+1)*paramNum+fillPos1+7] = -(lambada-1)*y1*hY1/(hW1*hW1);
|
||
|
|
||
|
double orgy0 = initX[6*curse0+3]*x0 + initX[6*curse0+4]*y0 + initX[6*curse0+5];
|
||
|
double orgy1 = initX[6*curse1+3]*x1 + initX[6*curse1+4]*y1 + initX[6*curse1+5];
|
||
|
|
||
|
LiPtr[2*n+1] = lambada*(orgy0+orgy1) - ((1+lambada)*hY0/hW0 + (lambada-1)*hY1/hW1);
|
||
|
|
||
|
double bias = (LiPtr[2*n]*LiPtr[2*n] + LiPtr[2*n+1]*LiPtr[2*n+1]);
|
||
|
meanBias += sqrt(bias);
|
||
|
n ++;
|
||
|
rn ++;
|
||
|
}
|
||
|
//! get in normal equation matrix
|
||
|
Mat_<double> Ait = Ai.t();
|
||
|
Mat_<double> barA = Ait*Ai, barL = Ait*Li;
|
||
|
AtA += barA;
|
||
|
AtL += barL;
|
||
|
}
|
||
|
}
|
||
|
meanBias = meanBias/rn;
|
||
|
cout<<"Iteration: "<<ite<<" with cost: "<<meanBias<<endl;
|
||
|
Mat_<double> dX = AtA.inv()*AtL;
|
||
|
double *dXPtr = (double*)dX.data;
|
||
|
// cout<<dX<<endl;
|
||
|
double delta = 0; //! record the translation parameters of images
|
||
|
int num = 0;
|
||
|
for (int i = 0; i < paramNum; i ++)
|
||
|
{
|
||
|
X[i] += dXPtr[i];
|
||
|
if ((i+1)%8 == 3 || (i+1)%8 == 6)
|
||
|
{
|
||
|
// cout<<dX(i)<<endl;
|
||
|
delta += abs(dXPtr[i]);
|
||
|
num ++;
|
||
|
}
|
||
|
}
|
||
|
delta = delta/num;
|
||
|
if (delta < 0.08)
|
||
|
{
|
||
|
cout<<"Iteration has converged!"<<endl;
|
||
|
break;
|
||
|
}
|
||
|
if (ite++ == max_iters)
|
||
|
{
|
||
|
cout<<"arrive the limited iterations("<<max_iters<<")"<<endl;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
//! update the optimized parameters
|
||
|
int cnt = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
double *data = (double*)_alignModelList[i].data;
|
||
|
for (int j = 0; j < 8; j ++)
|
||
|
{
|
||
|
data[j] = X[cnt++];
|
||
|
}
|
||
|
}
|
||
|
delete []X;
|
||
|
delete []initX;
|
||
|
cout<<"This optimization round is over!"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::buildIniSolution(double* X, double* initX, int sIndex, int eIndex)
|
||
|
{
|
||
|
int cnt = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
Mat_<double> tempMat = _alignModelList[i];
|
||
|
double *data = (double*)tempMat.data;
|
||
|
for (int j = 0; j < 8; j ++)
|
||
|
{
|
||
|
X[cnt++] = data[j];
|
||
|
}
|
||
|
}
|
||
|
cnt = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
Mat_<double> tempMat = _initModelList[i];
|
||
|
double *data = (double*)tempMat.data;
|
||
|
for (int j = 0; j < 6; j ++)
|
||
|
{
|
||
|
initX[cnt++] = data[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::buildIniSolution(double* X, int sIndex, int eIndex)
|
||
|
{
|
||
|
int cnt = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
Mat_<double> tempMat = _alignModelList[i];
|
||
|
double *data = (double*)tempMat.data;
|
||
|
for (int j = 0; j < 8; j ++)
|
||
|
{
|
||
|
X[cnt++] = data[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::RefineAligningModels(int sIndex, int eIndex)
|
||
|
{
|
||
|
int m = 0, n = 0, max_its = 200;
|
||
|
m = (eIndex-sIndex+1) * 8; //without optimizing the start one
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
int curNo = _visitOrder[i].imgNo;
|
||
|
vector<vector<Point2d> > pointSet = _matchNetList[curNo].PointSet;
|
||
|
vector<int> relatedNos = _matchNetList[curNo].relatedImgs;
|
||
|
for (int j = 0; j < relatedNos.size(); j ++)
|
||
|
{
|
||
|
if (relatedNos[j] < i)
|
||
|
{
|
||
|
//! using only one third of corresponding for optimization
|
||
|
n += pointSet[j].size()/3;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
double *d = new double[n];
|
||
|
for (int i = 0; i < n; i ++)
|
||
|
{
|
||
|
d[i] = 0;
|
||
|
}
|
||
|
double *X = new double[m];
|
||
|
buildIniSolution(X, sIndex, eIndex);
|
||
|
|
||
|
LMData *LMInput = new LMData; //! prepare input data for optimization
|
||
|
LMInput->sIndex = sIndex;
|
||
|
LMInput->eIndex = eIndex;
|
||
|
LMInput->matchPtr = &_matchNetList;
|
||
|
LMInput->modelPtr = &_alignModelList;
|
||
|
LMInput->visitOrder = _visitOrder;
|
||
|
|
||
|
double opts[LM_OPTS_SZ], info[LM_INFO_SZ];
|
||
|
opts[0]=1E-20; opts[1]=1E-30; opts[2]=1E-30; opts[3]=1E-30; opts[4]= 1e-9;
|
||
|
int ret = dlevmar_dif(OptimizationFunction, X, d, m, n, max_its, opts, info, NULL, NULL, (void*)LMInput);
|
||
|
for (int i = sIndex; i <= eIndex; i ++) //stock optimized homographic matrix
|
||
|
{
|
||
|
double *homoVec = X + 8*(i-sIndex);
|
||
|
Mat_<double> homoMat(3,3,CV_64FC1);
|
||
|
homoMat(0,0) = homoVec[0]; homoMat(0,1) = homoVec[1]; homoMat(0,2) = homoVec[2];
|
||
|
homoMat(1,0) = homoVec[3]; homoMat(1,1) = homoVec[4]; homoMat(1,2) = homoVec[5];
|
||
|
homoMat(2,0) = homoVec[6]; homoMat(2,1) = homoVec[7]; homoMat(2,2) = 1.0;
|
||
|
_alignModelList[i] = homoMat;
|
||
|
}
|
||
|
|
||
|
delete []d; //free stack
|
||
|
delete []X;
|
||
|
delete LMInput;
|
||
|
cout<<"Optimization done with iterations("<<ret<<")"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::OptimizationFunction(double* X, double* d, int m, int n, void* data)
|
||
|
{
|
||
|
LMData *dataPtr = (LMData *)data;
|
||
|
vector<Match_Net> *matchNetPtr = dataPtr->matchPtr;
|
||
|
int startIndex = dataPtr->sIndex, endIndex = dataPtr->eIndex;
|
||
|
vector<Mat_<double> > *modelListPtr = dataPtr->modelPtr;
|
||
|
vector<TreeNode> visitOrder = dataPtr->visitOrder;
|
||
|
int cnt = 0;
|
||
|
double meanError = 0;
|
||
|
for (int i = startIndex; i <= endIndex; i ++) //without the start image
|
||
|
{
|
||
|
int curNo = visitOrder[i].imgNo;
|
||
|
Match_Net matchNet = (*matchNetPtr)[curNo];
|
||
|
vector<int> relatedImgs = matchNet.relatedImgs;
|
||
|
double *homoVec1, *homoVec2;
|
||
|
double *iniHomoVec1, *iniHomoVec2;
|
||
|
homoVec1 = X + 8*(i-startIndex);
|
||
|
iniHomoVec1 = (double*)(*modelListPtr)[i].data;
|
||
|
for (int j = 0; j < relatedImgs.size(); j ++)
|
||
|
{
|
||
|
int neigIndex = relatedImgs[j];
|
||
|
if (neigIndex > i)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
vector<Point2d> ptSet1, ptSet2;
|
||
|
ptSet1 = matchNet.PointSet[j]; //! points on cur_image
|
||
|
int neigNo = visitOrder[neigIndex].imgNo;
|
||
|
Match_Net neigMatchNet = (*matchNetPtr)[neigNo];
|
||
|
for (int k = 0; k < neigMatchNet.relatedImgs.size(); k ++)
|
||
|
{
|
||
|
if (neigMatchNet.relatedImgs[k] == i)
|
||
|
{
|
||
|
ptSet2 = neigMatchNet.PointSet[k];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
bool fixedNeigh = false;
|
||
|
if (neigIndex < startIndex)
|
||
|
{
|
||
|
double *data = (double*)(*modelListPtr)[neigIndex].data;
|
||
|
homoVec2 = data;
|
||
|
fixedNeigh = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
homoVec2 = X + 8*(neigIndex-startIndex);
|
||
|
iniHomoVec2 = (double*)(*modelListPtr)[neigIndex].data;
|
||
|
}
|
||
|
//! using only one third of corresponding for optimization
|
||
|
for (int t = 0; t < ptSet1.size(); t += 3)
|
||
|
{
|
||
|
double x1 = ptSet1[t].x, y1 = ptSet1[t].y;
|
||
|
double x2 = ptSet2[t].x, y2 = ptSet2[t].y;
|
||
|
double mosaic_x1 = (homoVec1[0]*x1 + homoVec1[1]*y1 + homoVec1[2])/(homoVec1[6]*x1 + homoVec1[7]*y1 + 1.0);
|
||
|
double mosaic_y1 = (homoVec1[3]*x1 + homoVec1[4]*y1 + homoVec1[5])/(homoVec1[6]*x1 + homoVec1[7]*y1 + 1.0);
|
||
|
double mosaic_x2 = (homoVec2[0]*x2 + homoVec2[1]*y2 + homoVec2[2])/(homoVec2[6]*x2 + homoVec2[7]*y2 + 1.0);
|
||
|
double mosaic_y2 = (homoVec2[3]*x2 + homoVec2[4]*y2 + homoVec2[5])/(homoVec2[6]*x2 + homoVec2[7]*y2 + 1.0);
|
||
|
double bias = sqrt((mosaic_x1-mosaic_x2)*(mosaic_x1-mosaic_x2)+(mosaic_y1-mosaic_y2)*(mosaic_y1-mosaic_y2));
|
||
|
|
||
|
//! perspective penalty items
|
||
|
double penalty = 0;
|
||
|
if (!fixedNeigh)
|
||
|
{
|
||
|
double iniMosaic_x1 = (iniHomoVec1[0]*x1 + iniHomoVec1[1]*y1 + iniHomoVec1[2])/(iniHomoVec1[6]*x1 + iniHomoVec1[7]*y1 + 1.0);
|
||
|
double iniMosaic_y1 = (iniHomoVec1[3]*x1 + iniHomoVec1[4]*y1 + iniHomoVec1[5])/(iniHomoVec1[6]*x1 + iniHomoVec1[7]*y1 + 1.0);
|
||
|
double iniMosaic_x2 = (iniHomoVec2[0]*x2 + iniHomoVec2[1]*y2 + iniHomoVec2[2])/(iniHomoVec2[6]*x2 + iniHomoVec2[7]*y2 + 1.0);
|
||
|
double iniMosaic_y2 = (iniHomoVec2[3]*x2 + iniHomoVec2[4]*y2 + iniHomoVec2[5])/(iniHomoVec2[6]*x2 + iniHomoVec2[7]*y2 + 1.0);
|
||
|
double penalty1 = sqrt((mosaic_x1-iniMosaic_x1)*(mosaic_x1-iniMosaic_x1)+(mosaic_y1-iniMosaic_y1)*(mosaic_y1-iniMosaic_y1));
|
||
|
double penalty2 = sqrt((mosaic_x2-iniMosaic_x2)*(mosaic_x2-iniMosaic_x2)+(mosaic_y2-iniMosaic_y2)*(mosaic_y2-iniMosaic_y2));
|
||
|
penalty = (penalty1 + penalty2)/2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
double iniMosaic_x1 = (iniHomoVec1[0]*x1 + iniHomoVec1[1]*y1 + iniHomoVec1[2])/(iniHomoVec1[6]*x1 + iniHomoVec1[7]*y1 + 1.0);
|
||
|
double iniMosaic_y1 = (iniHomoVec1[3]*x1 + iniHomoVec1[4]*y1 + iniHomoVec1[5])/(iniHomoVec1[6]*x1 + iniHomoVec1[7]*y1 + 1.0);
|
||
|
penalty = sqrt((mosaic_x1-iniMosaic_x1)*(mosaic_x1-iniMosaic_x1)+(mosaic_y1-iniMosaic_y1)*(mosaic_y1-iniMosaic_y1));
|
||
|
}
|
||
|
d[cnt++] = bias + PENALTY_COEFF*penalty;
|
||
|
meanError += bias;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
meanError /= cnt;
|
||
|
cout<<"current mean-warping-bias is: "<<meanError<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
int ImageAligner::findVisitIndex(int imgNo)
|
||
|
{
|
||
|
int imgIndex = 0;
|
||
|
for (int i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
if (_visitOrder[i].imgNo == imgNo)
|
||
|
{
|
||
|
imgIndex = i;
|
||
|
}
|
||
|
}
|
||
|
return imgIndex;
|
||
|
}
|
||
|
|
||
|
|
||
|
Rect ImageAligner::setImageSize(vector<Point2d> &nodePts)
|
||
|
{
|
||
|
vector<Point2d> marginPtList;
|
||
|
int i, j;
|
||
|
for (i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
Mat_<double> homoMat = _alignModelList[i];
|
||
|
int curImgNo = _visitOrder[i].imgNo;
|
||
|
Size imgSize = _imgSizeList[curImgNo];
|
||
|
int height = imgSize.height, width = imgSize.width;
|
||
|
Point2d srcPt00(0,0), srcPt01(width,0), srcPt10(0,height), srcPt11(width,height);
|
||
|
Point2d dstPt00, dstPt01, dstPt10, dstPt11;
|
||
|
Utils::pointTransform(homoMat, srcPt00, dstPt00);
|
||
|
Utils::pointTransform(homoMat, srcPt01, dstPt01);
|
||
|
Utils::pointTransform(homoMat, srcPt10, dstPt10);
|
||
|
Utils::pointTransform(homoMat, srcPt11, dstPt11);
|
||
|
marginPtList.push_back(dstPt00);
|
||
|
marginPtList.push_back(dstPt01);
|
||
|
marginPtList.push_back(dstPt10);
|
||
|
marginPtList.push_back(dstPt11);
|
||
|
if (i != 0)
|
||
|
{
|
||
|
nodePts.push_back(dstPt10);
|
||
|
nodePts.push_back(dstPt11);
|
||
|
}
|
||
|
}
|
||
|
int minX = 999, minY = 999, maxX = 0, maxY = 0;
|
||
|
for (i = 0; i < marginPtList.size(); i ++)
|
||
|
{
|
||
|
Point2d tmpPt = marginPtList[i];
|
||
|
int x = int(fabs(tmpPt.x)+1)*(tmpPt.x < 0 ? -1 : 1);
|
||
|
int y = int(fabs(tmpPt.y)+1)*(tmpPt.y < 0 ? -1 : 1);
|
||
|
if (x > maxX)
|
||
|
maxX = x;
|
||
|
if (x < minX)
|
||
|
minX = x;
|
||
|
if (y > maxY)
|
||
|
maxY = y;
|
||
|
if (y < minY)
|
||
|
minY = y;
|
||
|
}
|
||
|
for (i = 0; i < nodePts.size(); i ++)
|
||
|
{
|
||
|
nodePts[i].x -= minX;
|
||
|
nodePts[i].y -= minY;
|
||
|
}
|
||
|
Rect mosaicRect;
|
||
|
mosaicRect.x = minX; mosaicRect.y = minY;
|
||
|
mosaicRect.width = maxX-minX+1; mosaicRect.height = maxY-minY+1;
|
||
|
return mosaicRect;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::saveMosaicImage()
|
||
|
{
|
||
|
cout<<"#Warping sequential images ..."<<endl;
|
||
|
bool needMask = false, needAlpha = false;
|
||
|
vector<Point2d> nodePts;
|
||
|
Rect mosaicRect = setImageSize(nodePts);
|
||
|
int newRow = mosaicRect.height, newCol = mosaicRect.width;
|
||
|
int i, j;
|
||
|
Rect newImgRect;
|
||
|
Mat stitchImage(newRow, newCol, CV_8UC3, Scalar(BKGRNDPIX,BKGRNDPIX,BKGRNDPIX));
|
||
|
uchar *mosaicData = (uchar*)stitchImage.data;
|
||
|
for (i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
int curImgNo = _visitOrder[i].imgNo;
|
||
|
cout<<"Warping Image: "<<curImgNo<<"..."<<endl;
|
||
|
Mat_<double> homoMat = _alignModelList[i];
|
||
|
Size imgSize = _imgSizeList[curImgNo];
|
||
|
int height = imgSize.height, width = imgSize.width;
|
||
|
Point2d srcPt00(0,0), srcPt01(width,0), srcPt10(0,height), srcPt11(width,height);
|
||
|
Point2d dstPt00, dstPt01, dstPt10, dstPt11;
|
||
|
Utils::pointTransform(homoMat, srcPt00, dstPt00);
|
||
|
Utils::pointTransform(homoMat, srcPt01, dstPt01);
|
||
|
Utils::pointTransform(homoMat, srcPt10, dstPt10);
|
||
|
Utils::pointTransform(homoMat, srcPt11, dstPt11);
|
||
|
|
||
|
double fminX, fminY, fmaxX, fmaxY;
|
||
|
fminX = min(min(dstPt00.x, dstPt01.x), min(dstPt10.x, dstPt11.x));
|
||
|
fmaxX = max(max(dstPt00.x, dstPt01.x), max(dstPt10.x, dstPt11.x));
|
||
|
fminY = min(min(dstPt00.y, dstPt01.y), min(dstPt10.y, dstPt11.y));
|
||
|
fmaxY = max(max(dstPt00.y, dstPt01.y), max(dstPt10.y, dstPt11.y));
|
||
|
int minX, minY, maxX, maxY;
|
||
|
minX = int(fabs(fminX)+1)*(fminX < 0 ? -1 : 1);
|
||
|
maxX = int(fabs(fmaxX)+1)*(fmaxX < 0 ? -1 : 1);
|
||
|
minY = int(fabs(fminY)+1)*(fminY < 0 ? -1 : 1);
|
||
|
maxY = int(fabs(fmaxY)+1)*(fmaxY < 0 ? -1 : 1);
|
||
|
|
||
|
int startX = minX-mosaicRect.x; int endX = startX+maxX-minX;
|
||
|
int startY = minY-mosaicRect.y; int endY = startY+maxY-minY;
|
||
|
int r, c;
|
||
|
Mat warpedImage;
|
||
|
if (needMask && needAlpha)
|
||
|
{
|
||
|
warpedImage = Mat(newRow, newCol, CV_8UC4, Scalar(BKGRNDPIX,BKGRNDPIX,BKGRNDPIX,0));
|
||
|
}
|
||
|
else if (needMask && !needAlpha)
|
||
|
{
|
||
|
warpedImage = Mat(newRow, newCol, CV_8UC3, Scalar(BKGRNDPIX,BKGRNDPIX,BKGRNDPIX));
|
||
|
}
|
||
|
uchar *curWarpData = (uchar*)warpedImage.data;
|
||
|
|
||
|
string filePath = _filePathList[curImgNo];
|
||
|
Mat image = imread(filePath);
|
||
|
uchar *curImgData = (uchar*)image.data;
|
||
|
Mat_<double> invHomoMat = homoMat.inv();
|
||
|
for (r = startY; r < endY; r ++)
|
||
|
{
|
||
|
for (c = startX; c < endX; c ++)
|
||
|
{
|
||
|
int grayValueR, grayValueG, grayValueB;
|
||
|
Point2d dstPt(c+mosaicRect.x,r+mosaicRect.y), srcPt(0,0);
|
||
|
Utils::pointTransform(invHomoMat, dstPt, srcPt);
|
||
|
int u = int(srcPt.x), v = int(srcPt.y);
|
||
|
if (0 < u && width-1 > u && 0 < v && height-1 > v)
|
||
|
{
|
||
|
int grayValueR1 = 0, grayValueR2 = 0;
|
||
|
int grayValueG1 = 0, grayValueG2 = 0;
|
||
|
int grayValueB1 = 0, grayValueB2 = 0;
|
||
|
|
||
|
//bilinear interpolation
|
||
|
grayValueR1 = curImgData[3*(v*width+u)+0]*(1-(srcPt.x-u)) + curImgData[3*(v*width+u+1)+0]*(srcPt.x-u);
|
||
|
grayValueG1 = curImgData[3*(v*width+u)+1]*(1-(srcPt.x-u)) + curImgData[3*(v*width+u+1)+1]*(srcPt.x-u);
|
||
|
grayValueB1 = curImgData[3*(v*width+u)+2]*(1-(srcPt.x-u)) + curImgData[3*(v*width+u+1)+2]*(srcPt.x-u);
|
||
|
|
||
|
grayValueR2 = curImgData[3*((v+1)*width+u)+0]*(1-(srcPt.x-u)) + curImgData[3*((v+1)*width+(u+1))+0]*(srcPt.x-u);
|
||
|
grayValueG2 = curImgData[3*((v+1)*width+u)+1]*(1-(srcPt.x-u)) + curImgData[3*((v+1)*width+(u+1))+1]*(srcPt.x-u);
|
||
|
grayValueB2 = curImgData[3*((v+1)*width+u)+2]*(1-(srcPt.x-u)) + curImgData[3*((v+1)*width+(u+1))+2]*(srcPt.x-u);
|
||
|
|
||
|
grayValueR = grayValueR1*(1-(srcPt.y-v)) + grayValueR2*(srcPt.y-v);
|
||
|
grayValueG = grayValueG1*(1-(srcPt.y-v)) + grayValueG2*(srcPt.y-v);
|
||
|
grayValueB = grayValueB1*(1-(srcPt.y-v)) + grayValueB2*(srcPt.y-v);
|
||
|
|
||
|
if (needMask)
|
||
|
{
|
||
|
if (!needAlpha)
|
||
|
{
|
||
|
curWarpData[3*(r*newCol+c)+0] = grayValueR;
|
||
|
curWarpData[3*(r*newCol+c)+1] = grayValueG;
|
||
|
curWarpData[3*(r*newCol+c)+2] = grayValueB;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
warpedImage.at<Vec4b>(r,c)[3] = 255; //! for alpha channel
|
||
|
warpedImage.at<Vec4b>(r,c)[0] = grayValueR; //! B
|
||
|
warpedImage.at<Vec4b>(r,c)[1] = grayValueG; //! G
|
||
|
warpedImage.at<Vec4b>(r,c)[2] = grayValueB; //! R
|
||
|
}
|
||
|
}
|
||
|
//! set for the mosaic image
|
||
|
mosaicData[3*(r*newCol+c)+0] = grayValueR;
|
||
|
mosaicData[3*(r*newCol+c)+1] = grayValueG;
|
||
|
mosaicData[3*(r*newCol+c)+2] = grayValueB;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!needMask)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
char name[512];
|
||
|
sprintf(name,"/Masks/warp%03d.png", curImgNo);
|
||
|
string savePath = Utils::baseDir + string(name);
|
||
|
imwrite(savePath, warpedImage);
|
||
|
}
|
||
|
|
||
|
string filePath = Utils::baseDir + "/mosaic.png";
|
||
|
imwrite(filePath, stitchImage);
|
||
|
cout<<"-Completed!"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::saveMosaicImageP()
|
||
|
{
|
||
|
cout<<"#Warping sequential images ..."<<endl;
|
||
|
bool needMask = Need_Mask, needAlpha = false;
|
||
|
vector<Point2d> nodePts;
|
||
|
Rect mosaicRect = setImageSize(nodePts);
|
||
|
int newRow = mosaicRect.height, newCol = mosaicRect.width;
|
||
|
int i, j;
|
||
|
Rect newImgRect;
|
||
|
Mat stitchImage(newRow, newCol, CV_8UC3, Scalar(BKGRNDPIX,BKGRNDPIX,BKGRNDPIX));
|
||
|
uchar *mosaicData = (uchar*)stitchImage.data;
|
||
|
Rect refRect;
|
||
|
for (i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
int curImgNo = i;
|
||
|
int curIndex = findVisitIndex(curImgNo);
|
||
|
cout<<"Warping Image: "<<curImgNo<<"..."<<endl;
|
||
|
Mat_<double> homoMat = _alignModelList[curIndex];
|
||
|
Size imgSize = _imgSizeList[curImgNo];
|
||
|
int height = imgSize.height, width = imgSize.width;
|
||
|
Point2d srcPt00(0,0), srcPt01(width,0), srcPt10(0,height), srcPt11(width,height);
|
||
|
Point2d dstPt00, dstPt01, dstPt10, dstPt11;
|
||
|
Utils::pointTransform(homoMat, srcPt00, dstPt00);
|
||
|
Utils::pointTransform(homoMat, srcPt01, dstPt01);
|
||
|
Utils::pointTransform(homoMat, srcPt10, dstPt10);
|
||
|
Utils::pointTransform(homoMat, srcPt11, dstPt11);
|
||
|
|
||
|
double fminX, fminY, fmaxX, fmaxY;
|
||
|
fminX = min(min(dstPt00.x, dstPt01.x), min(dstPt10.x, dstPt11.x));
|
||
|
fmaxX = max(max(dstPt00.x, dstPt01.x), max(dstPt10.x, dstPt11.x));
|
||
|
fminY = min(min(dstPt00.y, dstPt01.y), min(dstPt10.y, dstPt11.y));
|
||
|
fmaxY = max(max(dstPt00.y, dstPt01.y), max(dstPt10.y, dstPt11.y));
|
||
|
int minX, minY, maxX, maxY;
|
||
|
minX = int(fabs(fminX)+1)*(fminX < 0 ? -1 : 1);
|
||
|
maxX = int(fabs(fmaxX)+1)*(fmaxX < 0 ? -1 : 1);
|
||
|
minY = int(fabs(fminY)+1)*(fminY < 0 ? -1 : 1);
|
||
|
maxY = int(fabs(fmaxY)+1)*(fmaxY < 0 ? -1 : 1);
|
||
|
|
||
|
int startX = minX-mosaicRect.x; int endX = startX+maxX-minX;
|
||
|
int startY = minY-mosaicRect.y; int endY = startY+maxY-minY;
|
||
|
if (i == _refImgNo)
|
||
|
{
|
||
|
refRect.x = startX; refRect.y = startY;
|
||
|
refRect.width = endX-startX+1;
|
||
|
refRect.height = endY-startY+1;
|
||
|
}
|
||
|
int r, c;
|
||
|
Mat warpedImage;
|
||
|
if (needMask && needAlpha)
|
||
|
{
|
||
|
warpedImage = Mat(newRow, newCol, CV_8UC4, Scalar(BKGRNDPIX,BKGRNDPIX,BKGRNDPIX,0));
|
||
|
}
|
||
|
else if (needMask && !needAlpha)
|
||
|
{
|
||
|
warpedImage = Mat(newRow, newCol, CV_8UC3, Scalar(BKGRNDPIX,BKGRNDPIX,BKGRNDPIX));
|
||
|
}
|
||
|
uchar *curWarpData = (uchar*)warpedImage.data;
|
||
|
string filePath = _filePathList[curImgNo];
|
||
|
Mat image = imread(filePath);
|
||
|
uchar *curImgData = (uchar*)image.data;
|
||
|
Mat_<double> invHomoMat = homoMat.inv();
|
||
|
for (r = startY; r < endY; r ++)
|
||
|
{
|
||
|
for (c = startX; c < endX; c ++)
|
||
|
{
|
||
|
int grayValueR, grayValueG, grayValueB;
|
||
|
Point2d dstPt(c+mosaicRect.x,r+mosaicRect.y), srcPt(0,0);
|
||
|
Utils::pointTransform(invHomoMat, dstPt, srcPt);
|
||
|
int u = int(srcPt.x), v = int(srcPt.y);
|
||
|
if (0+1 < u && width-2 > u && 0+1 < v && height-2 > v)
|
||
|
{
|
||
|
int grayValueR1 = 0, grayValueR2 = 0;
|
||
|
int grayValueG1 = 0, grayValueG2 = 0;
|
||
|
int grayValueB1 = 0, grayValueB2 = 0;
|
||
|
|
||
|
//bilinear interpolation
|
||
|
grayValueR1 = curImgData[3*(v*width+u)+0]*(1-(srcPt.x-u)) + curImgData[3*(v*width+u+1)+0]*(srcPt.x-u);
|
||
|
grayValueG1 = curImgData[3*(v*width+u)+1]*(1-(srcPt.x-u)) + curImgData[3*(v*width+u+1)+1]*(srcPt.x-u);
|
||
|
grayValueB1 = curImgData[3*(v*width+u)+2]*(1-(srcPt.x-u)) + curImgData[3*(v*width+u+1)+2]*(srcPt.x-u);
|
||
|
|
||
|
grayValueR2 = curImgData[3*((v+1)*width+u)+0]*(1-(srcPt.x-u)) + curImgData[3*((v+1)*width+(u+1))+0]*(srcPt.x-u);
|
||
|
grayValueG2 = curImgData[3*((v+1)*width+u)+1]*(1-(srcPt.x-u)) + curImgData[3*((v+1)*width+(u+1))+1]*(srcPt.x-u);
|
||
|
grayValueB2 = curImgData[3*((v+1)*width+u)+2]*(1-(srcPt.x-u)) + curImgData[3*((v+1)*width+(u+1))+2]*(srcPt.x-u);
|
||
|
|
||
|
grayValueR = grayValueR1*(1-(srcPt.y-v)) + grayValueR2*(srcPt.y-v);
|
||
|
grayValueG = grayValueG1*(1-(srcPt.y-v)) + grayValueG2*(srcPt.y-v);
|
||
|
grayValueB = grayValueB1*(1-(srcPt.y-v)) + grayValueB2*(srcPt.y-v);
|
||
|
|
||
|
if (needMask)
|
||
|
{
|
||
|
if (!needAlpha)
|
||
|
{
|
||
|
curWarpData[3*(r*newCol+c)+0] = grayValueR;
|
||
|
curWarpData[3*(r*newCol+c)+1] = grayValueG;
|
||
|
curWarpData[3*(r*newCol+c)+2] = grayValueB;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
warpedImage.at<Vec4b>(r,c)[3] = 255; //! for alpha channel
|
||
|
warpedImage.at<Vec4b>(r,c)[0] = grayValueR; //! B
|
||
|
warpedImage.at<Vec4b>(r,c)[1] = grayValueG; //! G
|
||
|
warpedImage.at<Vec4b>(r,c)[2] = grayValueB; //! R
|
||
|
}
|
||
|
}
|
||
|
//! set for the mosaic image
|
||
|
mosaicData[3*(r*newCol+c)+0] = grayValueR;
|
||
|
mosaicData[3*(r*newCol+c)+1] = grayValueG;
|
||
|
mosaicData[3*(r*newCol+c)+2] = grayValueB;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!needMask)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
char name[512];
|
||
|
sprintf(name,"/Masks/warp%03d.png", curImgNo);
|
||
|
string savePath = Utils::baseDir + string(name);
|
||
|
imwrite(savePath, warpedImage);
|
||
|
}
|
||
|
|
||
|
if (0)
|
||
|
{
|
||
|
rectangle(stitchImage, Point2d(refRect.x,refRect.y), Point2d(refRect.x+refRect.width,refRect.y+refRect.height), Scalar(0,0,255), 5);
|
||
|
}
|
||
|
string filePath = Utils::baseDir + "/mosaic.png";
|
||
|
imwrite(filePath, stitchImage);
|
||
|
cout<<"-Completed!"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
double ImageAligner::CalWarpDeviation(vector<Point2d> pointSet1, vector<Point2d> pointSet2, Mat_<double> cvtMat, vector<double> weightList)
|
||
|
{
|
||
|
unsigned i;
|
||
|
int ptNum = pointSet1.size();
|
||
|
if (weightList.size() == 0)
|
||
|
{
|
||
|
for (i = 0; i < ptNum; i ++)
|
||
|
{
|
||
|
weightList.push_back(1.0);
|
||
|
}
|
||
|
}
|
||
|
double meanDist = 0, allWeight = 0;
|
||
|
// vector<double> errorList;
|
||
|
for (i = 0; i < ptNum; i ++) //mean value
|
||
|
{
|
||
|
Point2d warpedPt;
|
||
|
Utils::pointTransform(cvtMat, pointSet2[i], warpedPt);
|
||
|
double dist = 0;
|
||
|
dist = sqrt((warpedPt.x-pointSet1[i].x)*(warpedPt.x-pointSet1[i].x) + (warpedPt.y-pointSet1[i].y)*(warpedPt.y-pointSet1[i].y));
|
||
|
meanDist += dist*weightList[i];
|
||
|
allWeight += weightList[i];
|
||
|
}
|
||
|
meanDist /= allWeight;
|
||
|
return meanDist;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::recheckTopology(int sIndex, int eIndex)
|
||
|
{
|
||
|
cout<<"-Recheck potential topology ..."<<endl;
|
||
|
int addedPairs = 0;
|
||
|
for (int i = sIndex; i <= eIndex; i ++)
|
||
|
{
|
||
|
int curNo = _visitOrder[i].imgNo;
|
||
|
Mat_<double> affineMat = _alignModelList[i];
|
||
|
//! calculating projecting centroid
|
||
|
Quadra bar;
|
||
|
bar.imgSize = _imgSizeList[curNo];
|
||
|
Point2d centroid(bar.imgSize.width/2.0, bar.imgSize.height/2.0);
|
||
|
bar.centroid = Utils::pointTransform(affineMat, centroid);
|
||
|
_projCoordSet.push_back(bar);
|
||
|
|
||
|
vector<int> relatedNos = _matchNetList[curNo].relatedImgs;
|
||
|
//! check with previously aligned images, except for its known neighbors
|
||
|
for (int j = 0; j < sIndex; j ++)
|
||
|
{
|
||
|
bool isOldFriend = false;
|
||
|
for (int k = 0; k < relatedNos.size(); k ++)
|
||
|
{
|
||
|
if (relatedNos[k] == j)
|
||
|
{
|
||
|
isOldFriend = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (isOldFriend)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
int testNo = _visitOrder[j].imgNo;
|
||
|
Quadra testObj = _projCoordSet[j];
|
||
|
double threshold = 0.5*(max(bar.imgSize.width,bar.imgSize.height) + max(testObj.imgSize.width, testObj.imgSize.height));
|
||
|
double dist = Utils::calPointDist(bar.centroid, testObj.centroid);
|
||
|
if (dist > threshold*0.6)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
vector<Point2d> PtSet1, PtSet2;
|
||
|
bool yeah = _matcher->featureMatcher(curNo,testNo,PtSet1,PtSet2);
|
||
|
if (yeah)
|
||
|
{
|
||
|
_similarityMat(testNo,curNo) = PtSet1.size();
|
||
|
_similarityMat(curNo,testNo) = PtSet1.size();
|
||
|
|
||
|
_matchNetList[curNo].relatedImgs.push_back(j);
|
||
|
_matchNetList[curNo].PointSet.push_back(PtSet1);
|
||
|
_matchNetList[testNo].relatedImgs.push_back(i);
|
||
|
_matchNetList[testNo].PointSet.push_back(PtSet2);
|
||
|
addedPairs ++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
cout<<"-Done! added "<<addedPairs<<" pairs."<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::drawTopologyNet()
|
||
|
{
|
||
|
vector<Point2d> coreLocations;
|
||
|
int i, j, k;
|
||
|
//! in the order of '_visitOrser'
|
||
|
for (i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
double x0 = _imgSizeList[imgNo].width/2.0;
|
||
|
double y0 = _imgSizeList[imgNo].height/2.0;
|
||
|
Point2d centroid(x0, y0);
|
||
|
Point2d warpPt;
|
||
|
Utils::pointTransform(_alignModelList[i], centroid, warpPt);
|
||
|
coreLocations.push_back(warpPt);
|
||
|
}
|
||
|
int minX = 999, minY = 999, maxX = 0, maxY = 0;
|
||
|
for (i = 0; i < coreLocations.size(); i ++)
|
||
|
{
|
||
|
Point2d tmpPt = coreLocations[i];
|
||
|
int x = int(fabs(tmpPt.x)+1)*(tmpPt.x < 0 ? -1 : 1);
|
||
|
int y = int(fabs(tmpPt.y)+1)*(tmpPt.y < 0 ? -1 : 1);
|
||
|
if (x > maxX)
|
||
|
maxX = x;
|
||
|
if (x < minX)
|
||
|
minX = x;
|
||
|
if (y > maxY)
|
||
|
maxY = y;
|
||
|
if (y < minY)
|
||
|
minY = y;
|
||
|
}
|
||
|
double width = maxX - minX;
|
||
|
double height = maxY - minY;
|
||
|
int imageRange = 2000; //maximum side_length
|
||
|
int edgeRange = 60;
|
||
|
double cvtScale = imageRange/min(height,width);
|
||
|
int imageRow = height * cvtScale + edgeRange*2; // add an edge space of 20 pixel
|
||
|
int imageCol = width * cvtScale + edgeRange*2;
|
||
|
Mat displayPlane(imageRow, imageCol, CV_8UC3, Scalar(255,255,255));
|
||
|
|
||
|
CvFont font;
|
||
|
double hScale = 1;
|
||
|
double vScale = 1;
|
||
|
cvInitFont(&font,CV_FONT_HERSHEY_PLAIN, hScale,vScale,0,1); //¶¨Òå±ê¼Ç×ÖÌå
|
||
|
vector<Point2i> dotPtList;
|
||
|
//! in the order of '_visitOrser'
|
||
|
for (i = 0; i < coreLocations.size(); i ++)
|
||
|
{
|
||
|
int c = int((coreLocations[i].x-minX) * cvtScale + 1) + edgeRange;
|
||
|
int r = int((coreLocations[i].y-minY) * cvtScale + 1) + edgeRange;
|
||
|
dotPtList.push_back(Point2i(c,r));
|
||
|
circle(displayPlane, Point2i(c,r), 24, Scalar(255,0,0), -1);
|
||
|
// circle(displayPlane, Point2i(c,r), 3, Scalar(255,255,0), -1);
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
char text[100];
|
||
|
sprintf(text,"%d", imgNo);
|
||
|
Point2i dotPt(c+3, r+3);
|
||
|
// cv::putText(displayPlane, text, dotPt, 2, 1, Scalar(0,0,0));
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < _imgNum-1; i ++) //draw all related lines
|
||
|
{
|
||
|
for (j = i+1; j < _imgNum; j ++)
|
||
|
{
|
||
|
int imgNo1 = _visitOrder[i].imgNo;
|
||
|
int imgNo2 = _visitOrder[j].imgNo;
|
||
|
int PtNum = _similarityMat(imgNo1,imgNo2);
|
||
|
if (PtNum != 0)
|
||
|
{
|
||
|
Point2i startPt = dotPtList[i];
|
||
|
Point2i endPt = dotPtList[j];
|
||
|
if (PtNum < 100 || 1)
|
||
|
{
|
||
|
line(displayPlane, startPt, endPt, Scalar(128,128,128), 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
line(displayPlane, startPt, endPt, Scalar(0,255,0), 2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (i = 1; i < _imgNum; i ++) //! draw the related lines in MST
|
||
|
{
|
||
|
int refNo = _visitOrder[i].refNo;
|
||
|
int refIndex = findVisitIndex(refNo);
|
||
|
Point2i startPt = dotPtList[i];
|
||
|
Point2i endPt = dotPtList[refIndex];
|
||
|
line(displayPlane, startPt, endPt, Scalar(0,0,255), 3);
|
||
|
}
|
||
|
string savePath = Utils::baseDir + "/finalTopology.png";
|
||
|
imwrite(savePath, displayPlane);
|
||
|
cout<<"#the topology graph of images is saved!"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::labelGroupNodes()
|
||
|
{
|
||
|
vector<Point2d> coreLocations;
|
||
|
int i, j, k;
|
||
|
//! in the order of '_visitOrser'
|
||
|
for (i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
int imgNo = _visitOrder[i].imgNo;
|
||
|
double x0 = _imgSizeList[imgNo].width/2.0;
|
||
|
double y0 = _imgSizeList[imgNo].height/2.0;
|
||
|
Point2d centroid(x0, y0);
|
||
|
Point2d warpPt;
|
||
|
Utils::pointTransform(_alignModelList[i], centroid, warpPt);
|
||
|
coreLocations.push_back(warpPt);
|
||
|
}
|
||
|
int minX = 999, minY = 999, maxX = 0, maxY = 0;
|
||
|
for (i = 0; i < coreLocations.size(); i ++)
|
||
|
{
|
||
|
Point2d tmpPt = coreLocations[i];
|
||
|
int x = int(fabs(tmpPt.x)+1)*(tmpPt.x < 0 ? -1 : 1);
|
||
|
int y = int(fabs(tmpPt.y)+1)*(tmpPt.y < 0 ? -1 : 1);
|
||
|
if (x > maxX)
|
||
|
maxX = x;
|
||
|
if (x < minX)
|
||
|
minX = x;
|
||
|
if (y > maxY)
|
||
|
maxY = y;
|
||
|
if (y < minY)
|
||
|
minY = y;
|
||
|
}
|
||
|
double width = maxX - minX;
|
||
|
double height = maxY - minY;
|
||
|
int imageRange = 1000; //maximum side_length
|
||
|
int edgeRange = 50;
|
||
|
double cvtScale = imageRange/min(height,width);
|
||
|
int imageRow = height * cvtScale + edgeRange*2; // add an edge space of 20 pixel
|
||
|
int imageCol = width * cvtScale + edgeRange*2;
|
||
|
Mat displayPlane(imageRow, imageCol, CV_8UC3, Scalar(255,255,255));
|
||
|
|
||
|
CvFont font;
|
||
|
double hScale = 1;
|
||
|
double vScale = 1;
|
||
|
cvInitFont(&font,CV_FONT_HERSHEY_PLAIN, hScale,vScale,0,1); //¶¨Òå±ê¼Ç×ÖÌå
|
||
|
vector<Point2i> dotPtList;
|
||
|
//! label aligning group
|
||
|
for (i = 0; i < _groupCusorList.size(); i ++)
|
||
|
{
|
||
|
int sIndex = 0, eIndex = 0;
|
||
|
if (i != 0)
|
||
|
{
|
||
|
sIndex = _groupCusorList[i-1]+1;
|
||
|
eIndex = _groupCusorList[i];
|
||
|
}
|
||
|
int r = rand()%255;
|
||
|
int g = rand()%255;
|
||
|
int b = rand()%255;
|
||
|
for (j = sIndex; j <= eIndex; j ++)
|
||
|
{
|
||
|
int c = int((coreLocations[j].x-minX) * cvtScale + 1) + edgeRange;
|
||
|
int r1 = int((coreLocations[j].y-minY) * cvtScale + 1) + edgeRange;
|
||
|
dotPtList.push_back(Point2i(c,r1));
|
||
|
circle(displayPlane, Point2i(c,r1), 25, Scalar(r,g,b), -1);
|
||
|
int imgNo = _visitOrder[j].imgNo;
|
||
|
char text[100];
|
||
|
sprintf(text,"%d", imgNo);
|
||
|
Point2i dotPt(c+3, r1+3);
|
||
|
cv::putText(displayPlane, text, dotPt, 2, 1, Scalar(0,0,0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < _imgNum-1; i ++) //draw all related lines
|
||
|
{
|
||
|
for (j = i+1; j < _imgNum; j ++)
|
||
|
{
|
||
|
int imgNo1 = _visitOrder[i].imgNo;
|
||
|
int imgNo2 = _visitOrder[j].imgNo;
|
||
|
int PtNum = _similarityMat(imgNo1,imgNo2);
|
||
|
if (PtNum != 0)
|
||
|
{
|
||
|
Point2i startPt = dotPtList[i];
|
||
|
Point2i endPt = dotPtList[j];
|
||
|
if (PtNum < 100)
|
||
|
{
|
||
|
line(displayPlane, startPt, endPt, Scalar(128,128,128), 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
line(displayPlane, startPt, endPt, Scalar(0,255,0), 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (i = 1; i < _imgNum; i ++) //! draw the related lines in MST
|
||
|
{
|
||
|
int refNo = _visitOrder[i].refNo;
|
||
|
int refIndex = findVisitIndex(refNo);
|
||
|
Point2i startPt = dotPtList[i];
|
||
|
Point2i endPt = dotPtList[refIndex];
|
||
|
line(displayPlane, startPt, endPt, Scalar(0,0,255), 2);
|
||
|
}
|
||
|
string savePath = Utils::baseDir + "/groupLabel.jpg";
|
||
|
imwrite(savePath, displayPlane);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::drawSimilarMatrix()
|
||
|
{
|
||
|
int margin = 50;
|
||
|
int imageRow = 800, imageCol = 800;
|
||
|
int unitSize = 800/_imgNum;
|
||
|
CvFont font;
|
||
|
double hScale = 1;
|
||
|
double vScale = 1;
|
||
|
cvInitFont(&font,CV_FONT_HERSHEY_PLAIN, hScale,vScale,0,1); //define the label font
|
||
|
Mat displayPlane(imageRow+2*margin, imageCol+2*margin, CV_8UC3, Scalar(0,0,0));
|
||
|
for (int i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
Point2i startPt_h(margin+i*unitSize, margin); //draw vertical lines
|
||
|
Point2i endPt_h(margin+i*unitSize, margin+unitSize*_imgNum);
|
||
|
line(displayPlane, startPt_h, endPt_h, Scalar(128,128,128), 1);
|
||
|
char text_h[100];
|
||
|
sprintf(text_h,"%d", i+1);
|
||
|
Point2i dotPt1(startPt_h.x, startPt_h.y-10); //draw horizontal labels(the dot is at left-bottom of the label)
|
||
|
cv::putText(displayPlane, text_h, dotPt1, 1, 1, Scalar(255,255,255));
|
||
|
|
||
|
Point2i startPt_v(margin, margin+i*unitSize); //draw horizontal lines
|
||
|
Point2i endPt_v(margin+unitSize*_imgNum, margin+i*unitSize);
|
||
|
line(displayPlane, startPt_v, endPt_v, Scalar(128,128,128), 1);
|
||
|
char text_v[100];
|
||
|
sprintf(text_v,"%d", i+1);
|
||
|
Point2i dotPt2(startPt_v.x-25, startPt_v.y+10); //draw vertical labels
|
||
|
cv::putText(displayPlane, text_v, dotPt2, 1, 1, Scalar(255,255,255));
|
||
|
}
|
||
|
int* numDataPtr = (int*)_similarityMat.data;
|
||
|
int max_match_num = 0, min_match_num = 9999;
|
||
|
for (int i = 0; i < _imgNum-1; i ++)
|
||
|
{
|
||
|
for (int j = i+1; j < _imgNum; j ++)
|
||
|
{
|
||
|
int num = numDataPtr[i*_imgNum+j];
|
||
|
if (num > max_match_num)
|
||
|
{
|
||
|
max_match_num = num;
|
||
|
}
|
||
|
if (num < min_match_num)
|
||
|
{
|
||
|
min_match_num = num;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
double grayScale = (255-64+1)*1.0 / (max_match_num-min_match_num+1);
|
||
|
for (int i = 0; i < _imgNum-1; i ++)
|
||
|
{
|
||
|
for (int j = i+1; j < _imgNum; j ++)
|
||
|
{
|
||
|
Point2i leftTop, rigtBtm;
|
||
|
leftTop.x = margin + i*unitSize;
|
||
|
leftTop.y = margin + j*unitSize;
|
||
|
rigtBtm.x = leftTop.x + unitSize;
|
||
|
rigtBtm.y = leftTop.y + unitSize;
|
||
|
|
||
|
int PtNum = _similarityMat(i,j);
|
||
|
if (PtNum == 0)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
int grayValue = 64 + int((PtNum-min_match_num) * grayScale);
|
||
|
int r, c;
|
||
|
for (c = leftTop.x; c < rigtBtm.x; c ++)
|
||
|
{
|
||
|
for (r = leftTop.y; r < rigtBtm.y; r ++)
|
||
|
{
|
||
|
//! down triangle
|
||
|
displayPlane.at<Vec3b>(r,c)[0] = grayValue;
|
||
|
displayPlane.at<Vec3b>(r,c)[1] = grayValue;
|
||
|
displayPlane.at<Vec3b>(r,c)[2] = grayValue;
|
||
|
//! up triangle
|
||
|
displayPlane.at<Vec3b>(c,r)[0] = grayValue;
|
||
|
displayPlane.at<Vec3b>(c,r)[1] = grayValue;
|
||
|
displayPlane.at<Vec3b>(c,r)[2] = grayValue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
string savePath = Utils::baseDir + "/similarTable.jpg";
|
||
|
imwrite(savePath, displayPlane);
|
||
|
cout<<"the similarity table of images is saved!"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::outputPrecise()
|
||
|
{
|
||
|
cout<<"#Error analyzing ..."<<endl;
|
||
|
double meanBias = 0;
|
||
|
vector<double> deviations;
|
||
|
int cnt = 0;
|
||
|
for (int i = 1; i < _imgNum; i ++)
|
||
|
{
|
||
|
int curNo = _visitOrder[i].imgNo;
|
||
|
Match_Net matchNet = _matchNetList[curNo];
|
||
|
vector<int> relatedImgs = _matchNetList[curNo].relatedImgs;
|
||
|
Mat_<double> homoMat1 = _alignModelList[i];
|
||
|
Mat_<double> homoMat2;
|
||
|
double curBias = 0;
|
||
|
int cnt1 = 0;
|
||
|
for (int j = 0; j < relatedImgs.size(); j ++)
|
||
|
{
|
||
|
int neigIndex = relatedImgs[j];
|
||
|
if (neigIndex > i)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
vector<Point2d> ptSet1, ptSet2;
|
||
|
ptSet1 = matchNet.PointSet[j]; //! points on cur_image
|
||
|
int neigNo = _visitOrder[neigIndex].imgNo;
|
||
|
Match_Net neigMatchNet = _matchNetList[neigNo];
|
||
|
for (int k = 0; k < neigMatchNet.relatedImgs.size(); k ++)
|
||
|
{
|
||
|
if (neigMatchNet.relatedImgs[k] == i)
|
||
|
{
|
||
|
ptSet2 = neigMatchNet.PointSet[k];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
homoMat2 = _alignModelList[neigIndex];
|
||
|
//! using only one third of corresponding for optimization
|
||
|
for (int t = 0; t < ptSet1.size(); t += 3)
|
||
|
{
|
||
|
Point2d mosaicPt1 = Utils::pointTransform(homoMat1, ptSet1[t]);
|
||
|
Point2d mosaicPt2 = Utils::pointTransform(homoMat2, ptSet2[t]);
|
||
|
double bias = sqrt((mosaicPt1.x-mosaicPt2.x)*(mosaicPt1.x-mosaicPt2.x)+(mosaicPt1.y-mosaicPt2.y)*(mosaicPt1.y-mosaicPt2.y));
|
||
|
|
||
|
deviations.push_back(bias);
|
||
|
meanBias += bias;
|
||
|
cnt ++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
meanBias /= cnt;
|
||
|
|
||
|
//! statistic the distribute of error
|
||
|
string savePath = Utils::baseDir + "/precise.txt";
|
||
|
ofstream fout(savePath, ios::out);
|
||
|
if (!fout.is_open())
|
||
|
{
|
||
|
cout<<"Save path not exists!"<<endl;
|
||
|
exit(0);
|
||
|
}
|
||
|
fout<<fixed<<setprecision(4);
|
||
|
fout<<"RME : "<<meanBias<<endl;
|
||
|
double minV = 0, maxV = 10, step = 0.1;
|
||
|
int stepNum = int((maxV-minV)/step);
|
||
|
for (int i = 1; i <= stepNum; i ++)
|
||
|
{
|
||
|
double rightV;
|
||
|
rightV = minV + step*i;
|
||
|
int accuNum = 0;
|
||
|
for (int j = 0; j < deviations.size(); j ++)
|
||
|
{
|
||
|
double error = deviations[j];
|
||
|
if (error <= rightV)
|
||
|
{
|
||
|
accuNum ++;
|
||
|
}
|
||
|
}
|
||
|
double ratio = 1.0*accuNum/deviations.size();
|
||
|
fout<<"0.0-"<<setw(3)<<rightV<<": "<<setw(4)<<ratio<<endl;
|
||
|
}
|
||
|
fout.close();
|
||
|
cout<<"-Completed! with RME : "<<meanBias<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::saveModelParams()
|
||
|
{
|
||
|
cout<<"#Save aligning model params ..."<<endl;
|
||
|
string savePath = Utils::baseDir + "/modelParmas.txt";
|
||
|
ofstream fout(savePath, ios::out);
|
||
|
if (!fout.is_open())
|
||
|
{
|
||
|
cout<<"Save path not exists!"<<endl;
|
||
|
exit(0);
|
||
|
}
|
||
|
for (int i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
int curImgNo = i;
|
||
|
int curIndex = findVisitIndex(curImgNo);
|
||
|
double* dataPtr = (double*)_alignModelList[curIndex].data;
|
||
|
for (int j = 0; j < 8; j ++)
|
||
|
{
|
||
|
fout<<dataPtr[j]<<" ";
|
||
|
}
|
||
|
fout<<endl;
|
||
|
}
|
||
|
cout<<"-Completed!"<<endl;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ImageAligner::loadHomographies()
|
||
|
{
|
||
|
cout<<"#Load aligning model params ..."<<endl;
|
||
|
string filePath = Utils::baseDir + "/modelParmas.txt";
|
||
|
ifstream fin(filePath, ios::in);
|
||
|
if (!fin.is_open())
|
||
|
{
|
||
|
cout<<"File not exists!"<<endl;
|
||
|
exit(0);
|
||
|
}
|
||
|
//! initializing
|
||
|
for (int i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
Mat_<double> homoMat = Mat::eye(3,3,CV_64FC1);
|
||
|
_alignModelList.push_back(homoMat);
|
||
|
}
|
||
|
double u0 = 500.971, v0 = 323.486;
|
||
|
Mat_<double> trans0 = (Mat_<double>(3,3) << 1, 0, -u0,
|
||
|
0, -1, 641-v0,
|
||
|
0, 0, 1);
|
||
|
Mat_<double> trans1 = (Mat_<double>(3,3) << 1, 0, u0,
|
||
|
0, -1, -641+v0,
|
||
|
0, 0, 1);
|
||
|
double kappa = 180;
|
||
|
Mat_<double> Rz = (Mat_<double>(3,3) << cos(kappa), -sin(kappa), 0,
|
||
|
sin(kappa), cos(kappa), 0,
|
||
|
0, 0, 1);
|
||
|
Mat_<double> t1 = (Mat_<double>(3,3) << 1, 0, -u0, 0, 1, -v0, 0, 0, 1);
|
||
|
Mat_<double> t2 = (Mat_<double>(3,3) << 1, 0, u0, 0, 1, v0, 0, 0, 1);
|
||
|
Mat_<double> bar = t2*Rz*t1;
|
||
|
for (int i = 0; i < _imgNum; i ++)
|
||
|
{
|
||
|
Mat_<double> homoMat = Mat::eye(3,3,CV_64FC1);
|
||
|
double* dataPtr = (double*)homoMat.data;
|
||
|
for (int j = 0; j < 8; j ++)
|
||
|
{
|
||
|
double param = 0;
|
||
|
fin >> param;
|
||
|
dataPtr[j] = param;
|
||
|
}
|
||
|
int curImgNo = i;
|
||
|
int curIndex = findVisitIndex(curImgNo);
|
||
|
if ((i/31)%2 == 0) //! rotate 180
|
||
|
{
|
||
|
_alignModelList[curIndex] = trans1*homoMat*trans0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_alignModelList[curIndex] = trans1*homoMat*trans0;
|
||
|
}
|
||
|
}
|
||
|
fin.close();
|
||
|
cout<<"-Completed!"<<endl;
|
||
|
}
|