kopia lustrzana https://github.com/OpenDroneMap/ODM
rodzic
94a83e8e38
commit
1d70d0e6a4
|
@ -0,0 +1 @@
|
|||
*~
|
|
@ -1,848 +0,0 @@
|
|||
#include <string>
|
||||
#include "patchOrganizerS.h"
|
||||
#include "findMatch.h"
|
||||
|
||||
using namespace PMVS3;
|
||||
using namespace Patch;
|
||||
using namespace std;
|
||||
|
||||
Ppatch CpatchOrganizerS::m_MAXDEPTH(new Cpatch());
|
||||
Ppatch CpatchOrganizerS::m_BACKGROUND(new Cpatch());
|
||||
|
||||
CpatchOrganizerS::CpatchOrganizerS(CfindMatch& findMatch) : m_fm(findMatch) {
|
||||
}
|
||||
|
||||
// change the contents of m_images from images to indexes
|
||||
void CpatchOrganizerS::image2index(Cpatch& patch) {
|
||||
// first image has to be target image
|
||||
vector<int> newimages;
|
||||
for (int i = 0; i < (int)patch.m_images.size(); ++i) {
|
||||
const int index = m_fm.m_pss.image2index(patch.m_images[i]);
|
||||
if (index != -1)
|
||||
newimages.push_back(index);
|
||||
}
|
||||
|
||||
patch.m_images.swap(newimages);
|
||||
|
||||
// make sure that the reference image is the tagetting image
|
||||
int exist = -1;
|
||||
for (int j = 0; j < (int)patch.m_images.size(); ++j) {
|
||||
if (patch.m_images[j] < m_fm.m_tnum) {
|
||||
exist = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exist == -1)
|
||||
patch.m_images.clear();
|
||||
else if (exist != 0)
|
||||
swap(patch.m_images[0], patch.m_images[exist]);
|
||||
}
|
||||
|
||||
// change the contents of m_images from indexes to images
|
||||
void CpatchOrganizerS::index2image(Cpatch& patch) {
|
||||
for (int i = 0; i < (int)patch.m_images.size(); ++i)
|
||||
patch.m_images[i] = m_fm.m_pss.m_images[patch.m_images[i]];
|
||||
for (int i = 0; i < (int)patch.m_vimages.size(); ++i)
|
||||
patch.m_vimages[i] = m_fm.m_pss.m_images[patch.m_vimages[i]];
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::init(void) {
|
||||
m_pgrids.clear(); m_pgrids.resize(m_fm.m_tnum);
|
||||
m_vpgrids.clear(); m_vpgrids.resize(m_fm.m_tnum);
|
||||
m_dpgrids.clear(); m_dpgrids.resize(m_fm.m_tnum);
|
||||
m_counts.clear(); m_counts.resize(m_fm.m_tnum);
|
||||
|
||||
m_gwidths.clear(); m_gwidths.resize(m_fm.m_num);
|
||||
m_gheights.clear(); m_gheights.resize(m_fm.m_num);
|
||||
for (int index = 0; index < m_fm.m_num; ++index) {
|
||||
const int gwidth = (m_fm.m_pss.getWidth(index, m_fm.m_level)
|
||||
+ m_fm.m_csize - 1) / m_fm.m_csize;
|
||||
const int gheight = (m_fm.m_pss.getHeight(index, m_fm.m_level)
|
||||
+ m_fm.m_csize - 1) / m_fm.m_csize;
|
||||
m_gwidths[index] = gwidth;
|
||||
m_gheights[index] = gheight;
|
||||
|
||||
if (index < m_fm.m_tnum) {
|
||||
m_pgrids[index].resize(gwidth * gheight);
|
||||
m_vpgrids[index].resize(gwidth * gheight);
|
||||
m_dpgrids[index].resize(gwidth * gheight);
|
||||
m_counts[index].resize(gwidth * gheight);
|
||||
fill(m_dpgrids[index].begin(), m_dpgrids[index].end(), m_MAXDEPTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void CpatchOrganizerS::writePatches(void) {
|
||||
for (int index = 0; index < m_fm.m_tnum; ++index) {
|
||||
const int image = m_fm.m_timages[index];
|
||||
vector<Ppatch> ppatches;
|
||||
collectNonFixPatches(index, ppatches);
|
||||
|
||||
if (ppatches.empty())
|
||||
continue;
|
||||
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "%smodels/%08d.patc%d", m_fm.m_prefix.c_str(), image, m_fm.m_level);
|
||||
|
||||
ofstream ofstr;
|
||||
ofstr.open(buffer);
|
||||
ofstr << "PATCHES" << endl
|
||||
<< (int)ppatches.size() << endl;
|
||||
|
||||
for (int p = 0; p < (int)ppatches.size(); ++p) {
|
||||
Cpatch patch = *ppatches[p];
|
||||
index2image(patch);
|
||||
ofstr << patch << endl;
|
||||
}
|
||||
ofstr.close();
|
||||
|
||||
sprintf(buffer, "%smodels/%08d-%d.ply", m_fm.m_prefix.c_str(), image, m_fm.m_level);
|
||||
writePLY(ppatches, buffer);
|
||||
}
|
||||
|
||||
collectPatches(1);
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "%smodels/m-%08d-%d.ply", m_fm.m_prefix.c_str(),
|
||||
m_fm.m_pss.m_images[0], m_fm.m_level);
|
||||
writePLY(m_ppatches, buffer);
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::writePatches2(const std::string prefix) {
|
||||
collectPatches(1);
|
||||
{
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "%s.ply", prefix.c_str());
|
||||
writePLY(m_ppatches, buffer);
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "%s.patch", prefix.c_str());
|
||||
ofstream ofstr;
|
||||
ofstr.open(buffer);
|
||||
ofstr << "PATCHES" << endl
|
||||
<< (int)m_ppatches.size() << endl;
|
||||
for (int p = 0; p < (int)m_ppatches.size(); ++p) {
|
||||
Cpatch patch = *ppatches[p];
|
||||
index2image(patch);
|
||||
ofstr << patch << endl;
|
||||
}
|
||||
ofstr.close();
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "%s.pset", prefix.c_str());
|
||||
ofstream ofstr;
|
||||
ofstr.open(buffer);
|
||||
for (int p = 0; p < (int)m_ppatches.size(); ++p)
|
||||
ofstr << m_ppatches[p]->m_coord[0] << ' '
|
||||
<< m_ppatches[p]->m_coord[1] << ' '
|
||||
<< m_ppatches[p]->m_coord[2] << ' '
|
||||
<< m_ppatches[p]->m_normal[0] << ' '
|
||||
<< m_ppatches[p]->m_normal[1] << ' '
|
||||
<< m_ppatches[p]->m_normal[2] << endl;
|
||||
ofstr.close();
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::readPatches(void) {
|
||||
// Read-in existing reconstructed points. set m_fix to one for non-targetting images
|
||||
for (int i = 0; i < m_fm.m_tnum; ++i) {
|
||||
const int image = m_fm.m_images[i];
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "%smodels/%08d.patc%d",
|
||||
m_fm.m_prefix.c_str(), image, m_fm.m_level);
|
||||
ifstream ifstr;
|
||||
ifstr.open(buffer);
|
||||
if (!ifstr.is_open())
|
||||
continue;
|
||||
|
||||
string header; int pnum;
|
||||
ifstr >> header >> pnum;
|
||||
cerr << image << ' ' << pnum << " patches" << endl;
|
||||
for (int p = 0; p < pnum; ++p) {
|
||||
Ppatch ppatch(new Cpatch());
|
||||
ifstr >> *ppatch;
|
||||
ppatch->m_fix = 0;
|
||||
ppatch->m_vimages.clear();
|
||||
|
||||
image2index(*ppatch);
|
||||
if (ppatch->m_images.empty())
|
||||
continue;
|
||||
|
||||
// m_vimages must be targetting images
|
||||
#ifdef DEBUG
|
||||
for (int j = 0; j < (int)ppatch->m_vimages.size(); ++j)
|
||||
if (m_fm.m_tnum <= ppatch->m_vimages[j]) {
|
||||
cerr << "Impossible in readPatches. m_vimages must be targetting images" << endl
|
||||
<< "for patches stored in targetting images, if visdata2 have been consistent" << endl;
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
setGrids(*ppatch);
|
||||
addPatch(ppatch);
|
||||
}
|
||||
|
||||
ifstr.close();
|
||||
}
|
||||
|
||||
// For patches in non-targetting images
|
||||
for (int i = m_fm.m_tnum; i < m_fm.m_num; ++i) {
|
||||
const int image = m_fm.m_images[i];
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "%smodels/%08d.patc%d", m_fm.m_prefix.c_str(), image, m_fm.m_level);
|
||||
ifstream ifstr;
|
||||
ifstr.open(buffer);
|
||||
if (!ifstr.is_open())
|
||||
continue;
|
||||
|
||||
string header; int pnum;
|
||||
ifstr >> header >> pnum;
|
||||
cerr << image << ' ' << pnum << " patches" << endl;
|
||||
|
||||
for (int p = 0; p < pnum; ++p) {
|
||||
Ppatch ppatch(new Cpatch());
|
||||
ifstr >> *ppatch;
|
||||
ppatch->m_fix = 1;
|
||||
ppatch->m_vimages.clear();
|
||||
|
||||
image2index(*ppatch);
|
||||
if (ppatch->m_images.empty())
|
||||
continue;
|
||||
|
||||
setGrids(*ppatch);
|
||||
addPatch(ppatch);
|
||||
}
|
||||
|
||||
ifstr.close();
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::collectPatches(const int target) {
|
||||
m_ppatches.clear();
|
||||
|
||||
for (int index = 0; index < m_fm.m_tnum; ++index) {
|
||||
for (int i = 0; i < (int)m_pgrids[index].size(); ++i) {
|
||||
vector<Ppatch>::iterator begin = m_pgrids[index][i].begin();
|
||||
while (begin != m_pgrids[index][i].end()) {
|
||||
(*begin)->m_id = -1;
|
||||
begin++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int index = 0; index < m_fm.m_tnum; ++index) {
|
||||
for (int i = 0; i < (int)m_pgrids[index].size(); ++i) {
|
||||
vector<Ppatch>::iterator begin = m_pgrids[index][i].begin();
|
||||
while (begin != m_pgrids[index][i].end()) {
|
||||
if ((*begin)->m_id == -1) {
|
||||
(*begin)->m_id = count++;
|
||||
|
||||
if (target == 0 || (*begin)->m_fix == 0)
|
||||
m_ppatches.push_back(*begin);
|
||||
}
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::collectPatches(std::priority_queue<Patch::Ppatch,
|
||||
std::vector<Patch::Ppatch>,
|
||||
P_compare>& pqpatches) {
|
||||
for (int index = 0; index < m_fm.m_tnum; ++index) {
|
||||
for (int i = 0; i < (int)m_pgrids[index].size(); ++i) {
|
||||
vector<Ppatch>::iterator begin = m_pgrids[index][i].begin();
|
||||
while (begin != m_pgrids[index][i].end()) {
|
||||
if ((*begin)->m_flag == 0) {
|
||||
(*begin)->m_flag = 1;
|
||||
pqpatches.push(*begin);
|
||||
}
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::collectPatches(const int index,
|
||||
std::priority_queue<Patch::Ppatch, std::vector<Patch::Ppatch>,
|
||||
P_compare>& pqpatches) {
|
||||
pthread_rwlock_wrlock(&m_fm.m_imageLocks[index]);
|
||||
for (int i = 0; i < (int)m_pgrids[index].size(); ++i) {
|
||||
vector<Ppatch>::iterator begin = m_pgrids[index][i].begin();
|
||||
vector<Ppatch>::iterator end = m_pgrids[index][i].end();
|
||||
|
||||
while (begin != end) {
|
||||
if ((*begin)->m_images[0] == index && (*begin)->m_flag == 0) {
|
||||
(*begin)->m_flag = 1;
|
||||
pqpatches.push(*begin);
|
||||
}
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
pthread_rwlock_unlock(&m_fm.m_imageLocks[index]);
|
||||
}
|
||||
|
||||
// Should be used only for writing
|
||||
void CpatchOrganizerS::collectNonFixPatches(const int index,
|
||||
std::vector<Patch::Ppatch>& ppatches) {
|
||||
pthread_rwlock_wrlock(&m_fm.m_imageLocks[index]);
|
||||
for (int i = 0; i < (int)m_pgrids[index].size(); ++i) {
|
||||
vector<Ppatch>::iterator begin = m_pgrids[index][i].begin();
|
||||
vector<Ppatch>::iterator end = m_pgrids[index][i].end();
|
||||
|
||||
while (begin != end) {
|
||||
if ((*begin)->m_images[0] == index && (*begin)->m_fix == 0) {
|
||||
ppatches.push_back(*begin);
|
||||
}
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
pthread_rwlock_unlock(&m_fm.m_imageLocks[index]);
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::clearFlags(void) {
|
||||
vector<Ppatch>::iterator bppatch = m_ppatches.begin();
|
||||
vector<Ppatch>::iterator eppatch = m_ppatches.end();
|
||||
|
||||
while (bppatch != eppatch) {
|
||||
(*bppatch)->m_flag = 0;
|
||||
++bppatch;
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::clearCounts(void) {
|
||||
for (int index = 0; index < m_fm.m_tnum; ++index) {
|
||||
vector<unsigned char>::iterator begin = m_counts[index].begin();
|
||||
vector<unsigned char>::iterator end = m_counts[index].end();
|
||||
while (begin != end) {
|
||||
*begin = (unsigned char)0;
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::addPatch(Patch::Ppatch& ppatch) {
|
||||
// First handle m_vimages
|
||||
vector<int>::iterator bimage = ppatch->m_images.begin();
|
||||
vector<int>::iterator eimage = ppatch->m_images.end();
|
||||
vector<Vec2i>::iterator bgrid = ppatch->m_grids.begin();
|
||||
while (bimage != eimage) {
|
||||
const int index = *bimage;
|
||||
if (m_fm.m_tnum <= index) {
|
||||
++bimage; ++bgrid;
|
||||
continue;
|
||||
}
|
||||
|
||||
const int index2 = (*bgrid)[1] * m_gwidths[index] + (*bgrid)[0];
|
||||
pthread_rwlock_wrlock(&m_fm.m_imageLocks[index]);
|
||||
m_pgrids[index][index2].push_back(ppatch);
|
||||
pthread_rwlock_unlock(&m_fm.m_imageLocks[index]);
|
||||
++bimage;
|
||||
++bgrid;
|
||||
}
|
||||
|
||||
// If depth, set vimages
|
||||
if (m_fm.m_depth == 0)
|
||||
return;
|
||||
|
||||
bimage = ppatch->m_vimages.begin();
|
||||
eimage = ppatch->m_vimages.end();
|
||||
bgrid = ppatch->m_vgrids.begin();
|
||||
|
||||
while (bimage != eimage) {
|
||||
const int index = *bimage;
|
||||
const int index2 = (*bgrid)[1] * m_gwidths[index] + (*bgrid)[0];
|
||||
pthread_rwlock_wrlock(&m_fm.m_imageLocks[index]);
|
||||
m_vpgrids[index][index2].push_back(ppatch);
|
||||
pthread_rwlock_unlock(&m_fm.m_imageLocks[index]);
|
||||
++bimage;
|
||||
++bgrid;
|
||||
}
|
||||
|
||||
updateDepthMaps(ppatch);
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::updateDepthMaps(Ppatch& ppatch) {
|
||||
for (int image = 0; image < m_fm.m_tnum; ++image) {
|
||||
const Vec3f icoord = m_fm.m_pss.project(image, ppatch->m_coord, m_fm.m_level);
|
||||
|
||||
const float fx = icoord[0] / m_fm.m_csize;
|
||||
const int xs[2] = {(int)floor(fx), (int)ceil(fx)};
|
||||
const float fy = icoord[1] / m_fm.m_csize;
|
||||
const int ys[2] = {(int)floor(fy), (int)ceil(fy)};
|
||||
|
||||
const float depth = m_fm.m_pss.m_photos[image].m_oaxis * ppatch->m_coord;
|
||||
|
||||
pthread_rwlock_wrlock(&m_fm.m_imageLocks[image]);
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (xs[i] < 0 || m_gwidths[image] <= xs[i] ||
|
||||
ys[j] < 0 || m_gheights[image] <= ys[j])
|
||||
continue;
|
||||
|
||||
const int index = ys[j] * m_gwidths[image] + xs[i];
|
||||
if (m_dpgrids[image][index] == m_MAXDEPTH)
|
||||
m_dpgrids[image][index] = ppatch;
|
||||
else {
|
||||
const float dtmp = m_fm.m_pss.m_photos[image].m_oaxis *
|
||||
m_dpgrids[image][index]->m_coord;
|
||||
|
||||
if (depth < dtmp)
|
||||
m_dpgrids[image][index] = ppatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_rwlock_unlock(&m_fm.m_imageLocks[image]);
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::setGridsImages(Patch::Cpatch& patch,
|
||||
const std::vector<int>& images) const {
|
||||
patch.m_images.clear();
|
||||
patch.m_grids.clear();
|
||||
vector<int>::const_iterator bimage = images.begin();
|
||||
vector<int>::const_iterator eimage = images.end();
|
||||
while (bimage != eimage) {
|
||||
const Vec3f icoord = m_fm.m_pss.project(*bimage, patch.m_coord, m_fm.m_level);
|
||||
const int ix = ((int)floor(icoord[0] + 0.5f)) / m_fm.m_csize;
|
||||
const int iy = ((int)floor(icoord[1] + 0.5f)) / m_fm.m_csize;
|
||||
if (0 <= ix && ix < m_gwidths[*bimage] &&
|
||||
0 <= iy && iy < m_gheights[*bimage]) {
|
||||
patch.m_images.push_back(*bimage);
|
||||
patch.m_grids.push_back(Vec2i(ix, iy));
|
||||
}
|
||||
++bimage;
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::setGrids(Ppatch& ppatch) const{
|
||||
setGrids(*ppatch);
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::setGrids(Cpatch& patch) const{
|
||||
patch.m_grids.clear();
|
||||
for (int i = 0; i < (int)patch.m_images.size(); ++i) {
|
||||
const int image = patch.m_images[i];
|
||||
Vec3f icoord = m_fm.m_pss.project(image, patch.m_coord, m_fm.m_level);
|
||||
const int ix = ((int)floor(icoord[0] + 0.5f)) / m_fm.m_csize;
|
||||
const int iy = ((int)floor(icoord[1] + 0.5f)) / m_fm.m_csize;
|
||||
patch.m_grids.push_back(TVec2<int>(ix, iy));
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::setVImagesVGrids(Ppatch& ppatch) {
|
||||
setVImagesVGrids(*ppatch);
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::setVImagesVGrids(Cpatch& patch) {
|
||||
vector<int> used;
|
||||
used.resize(m_fm.m_tnum);
|
||||
fill(used.begin(), used.end(), 0);
|
||||
|
||||
vector<int>::iterator bimage = patch.m_images.begin();
|
||||
vector<int>::iterator eimage = patch.m_images.end();
|
||||
while (bimage != eimage) {
|
||||
if ((*bimage) < m_fm.m_tnum)
|
||||
used[*(bimage)] = 1;
|
||||
++bimage;
|
||||
}
|
||||
|
||||
bimage = patch.m_vimages.begin();
|
||||
eimage = patch.m_vimages.end();
|
||||
while (bimage != eimage)
|
||||
used[*(bimage++)] = 1;
|
||||
|
||||
for (int image = 0; image < m_fm.m_tnum; ++image) {
|
||||
if (used[image])
|
||||
continue;
|
||||
|
||||
int ix, iy;
|
||||
if (isVisible0(patch, image, ix, iy,
|
||||
m_fm.m_neighborThreshold, 1) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_fm.m_pss.getEdge(patch.m_coord, image, m_fm.m_level) == 0)
|
||||
continue;
|
||||
|
||||
patch.m_vimages.push_back(image);
|
||||
patch.m_vgrids.push_back(TVec2<int>(ix, iy));
|
||||
}
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::removePatch(const Ppatch& ppatch) {
|
||||
for (int i = 0; i < (int)ppatch->m_images.size(); ++i) {
|
||||
const int image = ppatch->m_images[i];
|
||||
if (m_fm.m_tnum <= image)
|
||||
continue;
|
||||
|
||||
const int& ix = ppatch->m_grids[i][0];
|
||||
const int& iy = ppatch->m_grids[i][1];
|
||||
const int index = iy * m_gwidths[image] + ix;
|
||||
m_pgrids[image][index].erase(remove(m_pgrids[image][index].begin(),
|
||||
m_pgrids[image][index].end(),
|
||||
ppatch),
|
||||
m_pgrids[image][index].end());
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)ppatch->m_vimages.size(); ++i) {
|
||||
const int image = ppatch->m_vimages[i];
|
||||
#ifdef DEBUG
|
||||
if (m_fm.m_tnum <= image) {
|
||||
cerr << "Impossible in removePatch. m_vimages must be targetting images" << endl;
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
const int& ix = ppatch->m_vgrids[i][0];
|
||||
const int& iy = ppatch->m_vgrids[i][1];
|
||||
const int index = iy * m_gwidths[image] + ix;
|
||||
m_vpgrids[image][index].erase(remove(m_vpgrids[image][index].begin(),
|
||||
m_vpgrids[image][index].end(),
|
||||
ppatch),
|
||||
m_vpgrids[image][index].end());
|
||||
}
|
||||
}
|
||||
|
||||
int CpatchOrganizerS::isVisible0(const Cpatch& patch, const int image,
|
||||
int& ix, int& iy,
|
||||
const float strict, const int lock) {
|
||||
const Vec3f icoord =
|
||||
m_fm.m_pss.project(image, patch.m_coord, m_fm.m_level);
|
||||
ix = ((int)floor(icoord[0] + 0.5f)) / m_fm.m_csize;
|
||||
iy = ((int)floor(icoord[1] + 0.5f)) / m_fm.m_csize;
|
||||
|
||||
return isVisible(patch, image, ix, iy, strict, lock);
|
||||
}
|
||||
|
||||
int CpatchOrganizerS::isVisible(const Cpatch& patch, const int image,
|
||||
const int& ix, const int& iy,
|
||||
const float strict, const int lock) {
|
||||
const int& gwidth = m_gwidths[image];
|
||||
const int& gheight = m_gheights[image];
|
||||
|
||||
if (ix < 0 || gwidth <= ix || iy < 0 || gheight <= iy)
|
||||
return 0;
|
||||
|
||||
if (m_fm.m_depth == 0)
|
||||
return 1;
|
||||
|
||||
int ans = 0;
|
||||
Ppatch dppatch = m_MAXDEPTH;
|
||||
const int index = iy * gwidth + ix;
|
||||
|
||||
if (lock)
|
||||
pthread_rwlock_rdlock(&m_fm.m_imageLocks[image]);
|
||||
|
||||
if (m_dpgrids[image][index] == m_MAXDEPTH)
|
||||
ans = 1;
|
||||
else
|
||||
dppatch = m_dpgrids[image][index];
|
||||
|
||||
if (lock)
|
||||
pthread_rwlock_unlock(&m_fm.m_imageLocks[image]);
|
||||
|
||||
if (ans == 1)
|
||||
return 1;
|
||||
|
||||
|
||||
Vec4f ray = patch.m_coord - m_fm.m_pss.m_photos[image].m_center;
|
||||
unitize(ray);
|
||||
const float diff = ray * (patch.m_coord - dppatch->m_coord);
|
||||
const float factor = min(2.0, 2.0 + ray * patch.m_normal);
|
||||
|
||||
if (diff < m_fm.m_optim.getUnit(image, patch.m_coord) * m_fm.m_csize * strict * factor)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::findNeighbors(const Patch::Cpatch& patch,
|
||||
std::vector<Patch::Ppatch>& neighbors,
|
||||
const int lock, const float scale,
|
||||
const int margin,
|
||||
const int skipvis) {
|
||||
const float radius = 1.5 * margin * m_fm.m_expand.computeRadius(patch);
|
||||
|
||||
vector<int>::const_iterator bimage = patch.m_images.begin();
|
||||
vector<int>::const_iterator eimage = patch.m_images.end();
|
||||
vector<Vec2i>::const_iterator bgrid = patch.m_grids.begin();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (patch.m_images.empty()) {
|
||||
cerr << "Empty patches in findCloses" << endl;
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
float unit = 0.0f;
|
||||
for (int i = 0; i < (int)patch.m_images.size(); ++i)
|
||||
unit += m_fm.m_optim.getUnit(patch.m_images[i], patch.m_coord);
|
||||
unit /= (int)patch.m_images.size();
|
||||
unit *= m_fm.m_csize;
|
||||
|
||||
while (bimage != eimage) {
|
||||
if (m_fm.m_tnum <= *bimage) {
|
||||
++bimage;
|
||||
++bgrid;
|
||||
continue;
|
||||
}
|
||||
const int image = *bimage;
|
||||
const int& ix = (*bgrid)[0];
|
||||
const int& iy = (*bgrid)[1];
|
||||
if (lock)
|
||||
pthread_rwlock_rdlock(&m_fm.m_imageLocks[image]);
|
||||
for (int j = -margin; j <= margin; ++j) {
|
||||
const int ytmp = iy + j;
|
||||
if (ytmp < 0 || m_fm.m_pos.m_gheights[image] <= ytmp)
|
||||
continue;
|
||||
for (int i = -margin; i <= margin; ++i) {
|
||||
const int xtmp = ix + i;
|
||||
if (xtmp < 0 || m_fm.m_pos.m_gwidths[image] <= xtmp)
|
||||
continue;
|
||||
const int index = ytmp * m_fm.m_pos.m_gwidths[image] + xtmp;
|
||||
vector<Ppatch>::const_iterator bpatch =
|
||||
m_fm.m_pos.m_pgrids[image][index].begin();
|
||||
vector<Ppatch>::const_iterator epatch =
|
||||
m_fm.m_pos.m_pgrids[image][index].end();
|
||||
while (bpatch != epatch) {
|
||||
if (m_fm.isNeighborRadius(patch, **bpatch, unit,
|
||||
m_fm.m_neighborThreshold * scale,
|
||||
radius))
|
||||
neighbors.push_back(*bpatch);
|
||||
++bpatch;
|
||||
}
|
||||
bpatch = m_fm.m_pos.m_vpgrids[image][index].begin();
|
||||
epatch = m_fm.m_pos.m_vpgrids[image][index].end();
|
||||
while (bpatch != epatch) {
|
||||
if (m_fm.isNeighborRadius(patch, **bpatch, unit,
|
||||
m_fm.m_neighborThreshold * scale,
|
||||
radius))
|
||||
neighbors.push_back(*bpatch);
|
||||
++bpatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lock)
|
||||
pthread_rwlock_unlock(&m_fm.m_imageLocks[image]);
|
||||
|
||||
++bimage;
|
||||
++bgrid;
|
||||
}
|
||||
|
||||
if (skipvis == 0) {
|
||||
bimage = patch.m_vimages.begin();
|
||||
eimage = patch.m_vimages.end();
|
||||
bgrid = patch.m_vgrids.begin();
|
||||
|
||||
while (bimage != eimage) {
|
||||
const int image = *bimage;
|
||||
const int& ix = (*bgrid)[0];
|
||||
const int& iy = (*bgrid)[1];
|
||||
if (lock)
|
||||
pthread_rwlock_rdlock(&m_fm.m_imageLocks[image]);
|
||||
for (int j = -margin; j <= margin; ++j) {
|
||||
const int ytmp = iy + j;
|
||||
if (ytmp < 0 || m_fm.m_pos.m_gheights[image] <= ytmp)
|
||||
continue;
|
||||
for (int i = -margin; i <= margin; ++i) {
|
||||
const int xtmp = ix + i;
|
||||
if (xtmp < 0 || m_fm.m_pos.m_gwidths[image] <= xtmp)
|
||||
continue;
|
||||
const int index = ytmp * m_fm.m_pos.m_gwidths[image] + xtmp;
|
||||
vector<Ppatch>::const_iterator bpatch =
|
||||
m_fm.m_pos.m_pgrids[image][index].begin();
|
||||
vector<Ppatch>::const_iterator epatch =
|
||||
m_fm.m_pos.m_pgrids[image][index].end();
|
||||
while (bpatch != epatch) {
|
||||
if (m_fm.isNeighborRadius(patch, **bpatch, unit,
|
||||
m_fm.m_neighborThreshold * scale,
|
||||
radius))
|
||||
neighbors.push_back(*bpatch);
|
||||
++bpatch;
|
||||
}
|
||||
bpatch = m_fm.m_pos.m_vpgrids[image][index].begin();
|
||||
epatch = m_fm.m_pos.m_vpgrids[image][index].end();
|
||||
while (bpatch != epatch) {
|
||||
if (m_fm.isNeighborRadius(patch, **bpatch, unit,
|
||||
m_fm.m_neighborThreshold * scale,
|
||||
radius))
|
||||
neighbors.push_back(*bpatch);
|
||||
++bpatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lock)
|
||||
pthread_rwlock_unlock(&m_fm.m_imageLocks[image]);
|
||||
|
||||
++bimage;
|
||||
++bgrid;
|
||||
}
|
||||
}
|
||||
|
||||
sort(neighbors.begin(), neighbors.end());
|
||||
neighbors.erase(unique(neighbors.begin(), neighbors.end()), neighbors.end());
|
||||
}
|
||||
|
||||
float CpatchOrganizerS::computeUnit(const Patch::Cpatch& patch) const{
|
||||
float unit = 0.0f;
|
||||
for (int i = 0; i < (int)patch.m_images.size(); ++i)
|
||||
unit += m_fm.m_optim.getUnit(patch.m_images[i], patch.m_coord);
|
||||
unit /= (int)patch.m_images.size();
|
||||
unit *= m_fm.m_csize;
|
||||
return unit;
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::setScales(Patch::Cpatch& patch) const {
|
||||
const float unit = m_fm.m_optim.getUnit(patch.m_images[0], patch.m_coord);
|
||||
const float unit2 = 2.0f * unit;
|
||||
Vec4f ray = patch.m_coord - m_fm.m_pss.m_photos[patch.m_images[0]].m_center;
|
||||
unitize(ray);
|
||||
|
||||
const int inum = min(m_fm.m_tau, (int)patch.m_images.size());
|
||||
|
||||
// First compute, how many pixel difference per unit along vertical
|
||||
//for (int i = 1; i < (int)patch.m_images.size(); ++i) {
|
||||
for (int i = 1; i < inum; ++i) {
|
||||
Vec3f diff = m_fm.m_pss.project(patch.m_images[i], patch.m_coord, m_fm.m_level) -
|
||||
m_fm.m_pss.project(patch.m_images[i], patch.m_coord - ray * unit2, m_fm.m_level);
|
||||
patch.m_dscale += norm(diff);
|
||||
}
|
||||
|
||||
// set m_dscale to the vertical distance where average pixel move is half pixel
|
||||
//patch.m_dscale /= (int)patch.m_images.size() - 1;
|
||||
patch.m_dscale /= inum - 1;
|
||||
patch.m_dscale = unit2 / patch.m_dscale;
|
||||
|
||||
patch.m_ascale = atan(patch.m_dscale / (unit * m_fm.m_wsize / 2.0f));
|
||||
}
|
||||
|
||||
// write out results
|
||||
void CpatchOrganizerS::writePLY(const std::vector<Ppatch>& patches,
|
||||
const std::string filename) {
|
||||
ofstream ofstr;
|
||||
ofstr.open(filename.c_str());
|
||||
ofstr << "ply" << endl
|
||||
<< "format ascii 1.0" << endl
|
||||
<< "element vertex " << (int)patches.size() << endl
|
||||
<< "property float x" << endl
|
||||
<< "property float y" << endl
|
||||
<< "property float z" << endl
|
||||
<< "property float nx" << endl
|
||||
<< "property float ny" << endl
|
||||
<< "property float nz" << endl
|
||||
<< "property uchar diffuse_red" << endl
|
||||
<< "property uchar diffuse_green" << endl
|
||||
<< "property uchar diffuse_blue" << endl
|
||||
<< "end_header" << endl;
|
||||
|
||||
vector<Ppatch>::const_iterator bpatch = patches.begin();
|
||||
vector<Ppatch>::const_iterator bend = patches.end();
|
||||
|
||||
while (bpatch != bend) {
|
||||
// Get color
|
||||
Vec3i color;
|
||||
|
||||
const int mode = 0;
|
||||
// 0: color from images
|
||||
// 1: fix
|
||||
// 2: angle
|
||||
if (mode == 0) {
|
||||
int denom = 0;
|
||||
Vec3f colorf;
|
||||
for (int i = 0; i < (int)(*bpatch)->m_images.size(); ++i) {
|
||||
const int image = (*bpatch)->m_images[i];
|
||||
colorf += m_fm.m_pss.getColor((*bpatch)->m_coord, image, m_fm.m_level);
|
||||
denom++;
|
||||
}
|
||||
colorf /= denom;
|
||||
color[0] = min(255,(int)floor(colorf[0] + 0.5f));
|
||||
color[1] = min(255,(int)floor(colorf[1] + 0.5f));
|
||||
color[2] = min(255,(int)floor(colorf[2] + 0.5f));
|
||||
}
|
||||
else if (mode == 1) {
|
||||
if ((*bpatch)->m_tmp == 1.0f) {
|
||||
color[0] = 255;
|
||||
color[1] = 0;
|
||||
color[2] = 0;
|
||||
}
|
||||
else {
|
||||
color[0] = 255;
|
||||
color[1] = 255;
|
||||
color[2] = 255;
|
||||
}
|
||||
}
|
||||
else if (mode == 2) {
|
||||
float angle = 0.0f;
|
||||
vector<int>::iterator bimage = (*bpatch)->m_images.begin();
|
||||
vector<int>::iterator eimage = (*bpatch)->m_images.end();
|
||||
|
||||
while (bimage != eimage) {
|
||||
const int index = *bimage;
|
||||
Vec4f ray = m_fm.m_pss.m_photos[index].m_center - (*bpatch)->m_coord;
|
||||
ray[3] = 0.0f;
|
||||
unitize(ray);
|
||||
|
||||
angle += acos(ray * (*bpatch)->m_normal);
|
||||
++bimage;
|
||||
}
|
||||
|
||||
angle = angle / (M_PI / 2.0f);
|
||||
float r, g, b;
|
||||
Image::Cimage::gray2rgb(angle, r, g, b);
|
||||
color[0] = (int)(r * 255.0f);
|
||||
color[1] = (int)(g * 255.0f);
|
||||
color[2] = (int)(b * 255.0f);
|
||||
}
|
||||
|
||||
ofstr << (*bpatch)->m_coord[0] << ' '
|
||||
<< (*bpatch)->m_coord[1] << ' '
|
||||
<< (*bpatch)->m_coord[2] << ' '
|
||||
<< (*bpatch)->m_normal[0] << ' '
|
||||
<< (*bpatch)->m_normal[1] << ' '
|
||||
<< (*bpatch)->m_normal[2] << ' '
|
||||
<< color[0] << ' ' << color[1] << ' ' << color[2] << endl;
|
||||
++bpatch;
|
||||
}
|
||||
ofstr.close();
|
||||
}
|
||||
|
||||
void CpatchOrganizerS::writePLY(const std::vector<Ppatch>& patches,
|
||||
const std::string filename,
|
||||
const std::vector<Vec3i>& colors) {
|
||||
ofstream ofstr;
|
||||
ofstr.open(filename.c_str());
|
||||
ofstr << "ply" << endl
|
||||
<< "format ascii 1.0" << endl
|
||||
<< "element vertex " << (int)patches.size() << endl
|
||||
<< "property float x" << endl
|
||||
<< "property float y" << endl
|
||||
<< "property float z" << endl
|
||||
<< "property float nx" << endl
|
||||
<< "property float ny" << endl
|
||||
<< "property float nz" << endl
|
||||
<< "property uchar diffuse_red" << endl
|
||||
<< "property uchar diffuse_green" << endl
|
||||
<< "property uchar diffuse_blue" << endl
|
||||
<< "end_header" << endl;
|
||||
|
||||
vector<Ppatch>::const_iterator bpatch = patches.begin();
|
||||
vector<Ppatch>::const_iterator bend = patches.end();
|
||||
vector<Vec3i>::const_iterator colorb = colors.begin();
|
||||
|
||||
while (bpatch != bend) {
|
||||
ofstr << (*bpatch)->m_coord[0] << ' '
|
||||
<< (*bpatch)->m_coord[1] << ' '
|
||||
<< (*bpatch)->m_coord[2] << ' '
|
||||
<< (*bpatch)->m_normal[0] << ' '
|
||||
<< (*bpatch)->m_normal[1] << ' '
|
||||
<< (*bpatch)->m_normal[2] << ' '
|
||||
<< *colorb << endl;
|
||||
++bpatch;
|
||||
++colorb;
|
||||
}
|
||||
ofstr.close();
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Header: assert.hpp */
|
||||
/* */
|
||||
/* Accompanies STANN Version 0.5 Beta */
|
||||
/* Aug 05, 2008 */
|
||||
/* */
|
||||
/* Copyright 2007, 2008 */
|
||||
/* Michael Connor and Piyush Kumar */
|
||||
/* Florida State University */
|
||||
/* Tallahassee FL, 32306-4532 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef REVIVER_ASSERT_HPP
|
||||
#define REVIVER_ASSERT_HPP
|
||||
|
||||
#include <iostream>
|
||||
/*!
|
||||
\file
|
||||
\brief Implementation of assert functions
|
||||
This file contains an assert function implementation
|
||||
*/
|
||||
|
||||
/*!
|
||||
\brief Assert function
|
||||
This function prints error messages along with file and line numbers
|
||||
\param b bool to be checked
|
||||
\param desc Error message
|
||||
\param line Line number
|
||||
\param file File name
|
||||
\return True is there is no error
|
||||
*/
|
||||
bool MyAssertFunction( bool b, char* desc, int line, char* file){
|
||||
if (b) return true;
|
||||
std::cerr << "\n\nAssertion Failure\n";
|
||||
std::cerr << "Description : " << desc << std::endl;
|
||||
std::cerr << "Filename : " << file << std::endl;
|
||||
std::cerr << "Line No : " << line << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if defined( _DEBUG )
|
||||
#define Assert( exp, description ) MyAssertFunction( (int)(exp), description, __LINE__, __FILE__ )
|
||||
#else
|
||||
#define Assert( exp, description )
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
|
@ -1,126 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Header: bruteNN.hpp */
|
||||
/* */
|
||||
/* Accompanies STANN Version 0.5 Beta */
|
||||
/* Aug 05, 2008 */
|
||||
/* */
|
||||
/* Copyright 2007, 2008 */
|
||||
/* Michael Connor and Piyush Kumar */
|
||||
/* Florida State University */
|
||||
/* Tallahassee FL, 32306-4532 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
/*!
|
||||
\file
|
||||
\brief Brute force nearest neighbor search implementation
|
||||
This file contains a simple brute force NN algorithm implementation.
|
||||
It is very innefficient and should be used only for accuracy tests.
|
||||
*/
|
||||
#include <vector>
|
||||
|
||||
#include <qknn.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*!
|
||||
\brief A Brute force NN search class
|
||||
This class is a simple brute force algorithm for computing nearest neighbors.
|
||||
It is very innefficient and should be used only for accuracy tests.
|
||||
*/
|
||||
template<typename Point>
|
||||
class bruteNN
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Constructor
|
||||
Constructs a brute force nearest neighbor search structure out
|
||||
of the given data points.
|
||||
\param *points Pointer to list of input points
|
||||
\param N number of input points
|
||||
*/
|
||||
bruteNN(Point *points, long int N);
|
||||
/*!
|
||||
\brief Destructor
|
||||
*/
|
||||
~bruteNN();
|
||||
/*!
|
||||
\brief Nearest neighbor search function
|
||||
|
||||
This function returns the nearest k neighbors from the data
|
||||
structure to the given query point. The return vector contains
|
||||
the indexes to the answer points in the original data array passed
|
||||
at construction time.
|
||||
\param q Query point
|
||||
\param k number of neighbors to search for
|
||||
\param nn_idx Vector in which answer is written
|
||||
*/
|
||||
void ksearch(Point q, int k,
|
||||
vector<long unsigned int> &nn_idx);
|
||||
/*!
|
||||
\brief Nearest neighbor search function
|
||||
|
||||
This function returns the nearest k neighbors from the data
|
||||
structure to the given query point, as well as the squared
|
||||
distance to the query point. The return vector contains
|
||||
the indexes to the answer points in the original data array
|
||||
passed at construction time.
|
||||
\param q Query point
|
||||
\param k number of neighbors to search for
|
||||
\param nn_idx Vector in which answer is written
|
||||
\param d_index Vector in which square distances are written
|
||||
*/
|
||||
void ksearch(Point q, int k,
|
||||
vector<long unsigned int> &nn_idx,
|
||||
vector<double> &d_index);
|
||||
|
||||
private:
|
||||
|
||||
vector<Point> points;
|
||||
};
|
||||
|
||||
template<typename Point>
|
||||
bruteNN<Point>::bruteNN(Point *p, long int N)
|
||||
{
|
||||
points.resize(N);
|
||||
for(int i=0;i < N;++i)
|
||||
{
|
||||
points[i] = p[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
bruteNN<Point>::~bruteNN()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void bruteNN<Point>::ksearch(Point q, int k,
|
||||
vector<long unsigned int> &nn_idx)
|
||||
{
|
||||
qknn que;
|
||||
double distance;
|
||||
que.set_size(k);
|
||||
for(unsigned int i=0;i < points.size();++i)
|
||||
{
|
||||
distance = q.sqr_dist(points[i]);
|
||||
que.update(distance, i);
|
||||
}
|
||||
que.answer(nn_idx);
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void bruteNN<Point>::ksearch(Point q, int k,
|
||||
vector<long unsigned int> &nn_idx, vector<double> &d_indx)
|
||||
{
|
||||
qknn que;
|
||||
double distance;
|
||||
for(int i=0;i < points.size();++i)
|
||||
{
|
||||
distance = q.sqr_dist(points[i]);
|
||||
que.update(i, distance);
|
||||
}
|
||||
que.answer(nn_idx, d_indx);
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Header: bsearch.hpp */
|
||||
/* */
|
||||
/* Accompanies STANN Version 0.5 Beta */
|
||||
/* Aug 05, 2008 */
|
||||
/* */
|
||||
/* Copyright 2007, 2008 */
|
||||
/* Michael Connor and Piyush Kumar */
|
||||
/* Florida State University */
|
||||
/* Tallahassee FL, 32306-4532 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __SFCNN_BSEARCH__
|
||||
#define __SFCNN_BSEARCH__
|
||||
|
||||
#include <vector>
|
||||
#include <zorder_lt.hpp>
|
||||
|
||||
/*! \file
|
||||
\brief Binary search functions
|
||||
This file contains binary search functions for z-order operations.
|
||||
*/
|
||||
|
||||
//! Binary search function
|
||||
/*!
|
||||
This function executes a binary search on a vector of pointers to points
|
||||
\param A Vector of pointers to search
|
||||
\param *q Pointer to query point
|
||||
\param lt A less_than comparetor
|
||||
\return If found: index of point. Otherwise: index of first smaller point
|
||||
*/
|
||||
template<typename Point>
|
||||
long int BinarySearch(vector<Point *> &A, Point *q, zorder_lt<Point> lt)
|
||||
{
|
||||
long int low = 0;
|
||||
long int high = A.size()-1;
|
||||
long int middle;
|
||||
|
||||
while(low <= high)
|
||||
{
|
||||
middle = (low+high)/2;
|
||||
if(q == A[middle])
|
||||
return middle;
|
||||
else if(lt(q, A[middle]))
|
||||
high = middle-1;
|
||||
else
|
||||
low = middle+1;
|
||||
}
|
||||
return middle;
|
||||
}
|
||||
|
||||
//! A Binary Search function
|
||||
/*!
|
||||
This function conducts a binary search for two points at the same time.
|
||||
\param A Reference to the vector of points being searched
|
||||
\param q1 pointer to first point to be searched for
|
||||
\param q2 pointer to second point to be searched for
|
||||
\param lt less than comparetor
|
||||
\param p1 reference to return value for q1 location
|
||||
\param p2 reference to return value for q2 location
|
||||
*/
|
||||
|
||||
template<typename Point>
|
||||
void PairBinarySearch(vector<Point> &A, Point q1,
|
||||
Point q2, zorder_lt<Point> lt, int &p1, int &p2)
|
||||
{
|
||||
int low_q1=0;
|
||||
int low_q2=0;
|
||||
int high_q1 = A.size()-1;
|
||||
int high_q2 = A.size()-1;
|
||||
int middle = 0;
|
||||
int middle_store;
|
||||
|
||||
p1 = -2;
|
||||
p2 = -2;
|
||||
|
||||
while((low_q1 == low_q2) && (high_q1 == high_q2) && (p1 == -2) && (p2 == -2))
|
||||
{
|
||||
middle = (low_q1+high_q1)/2;
|
||||
if(q1 == A[middle])
|
||||
p1 = middle;
|
||||
else if(lt(q1, A[middle]))
|
||||
high_q1 = middle-1;
|
||||
else
|
||||
low_q1 = middle+1;
|
||||
if(q2 == A[middle])
|
||||
p2 = middle;
|
||||
else if(lt(q2, A[middle]))
|
||||
high_q2 = middle-1;
|
||||
else
|
||||
low_q2 = middle+1;
|
||||
}
|
||||
middle_store = middle;
|
||||
while(low_q1 <= high_q1)
|
||||
{
|
||||
middle = (low_q1+high_q1)/2;
|
||||
if(q1 == A[middle])
|
||||
break;
|
||||
else if(lt(q1, A[middle]))
|
||||
high_q1 = middle-1;
|
||||
else
|
||||
low_q1 = middle+1;
|
||||
}
|
||||
p1 = middle;
|
||||
middle = middle_store;
|
||||
while(low_q2 <= high_q2)
|
||||
{
|
||||
middle = (low_q2+high_q2)/2;
|
||||
if(q2 == A[middle])
|
||||
break;
|
||||
else if(lt(q2, A[middle]))
|
||||
high_q2 = middle-1;
|
||||
else
|
||||
low_q2 = middle+1;
|
||||
}
|
||||
p2 = middle;
|
||||
}
|
||||
|
||||
//! A binary search Function.
|
||||
/*
|
||||
This function executes a binary search on a vector of points
|
||||
\param A Vector of points to search
|
||||
\param q Query point
|
||||
\param lt A less_than comparetor
|
||||
\return If found: index of point. Otherwise: index of first smaller point
|
||||
*/
|
||||
template<typename Point>
|
||||
long int BinarySearch(vector<Point> &A, Point q, zorder_lt<Point> lt)
|
||||
{
|
||||
long int low = 0;
|
||||
long int high = A.size()-1;
|
||||
long int middle = 0;
|
||||
|
||||
while(low <= high)
|
||||
{
|
||||
middle = (low+high)/2;
|
||||
if(q == A[middle])
|
||||
return middle;
|
||||
else if(lt(q, A[middle]))
|
||||
high = middle-1;
|
||||
else
|
||||
low = middle+1;
|
||||
}
|
||||
return middle;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,498 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Header: sfcnn.hpp */
|
||||
/* */
|
||||
/* Accompanies STANN Version 0.5 Beta */
|
||||
/* Aug 05, 2008 */
|
||||
/* */
|
||||
/* Copyright 2007, 2008 */
|
||||
/* Michael Connor and Piyush Kumar */
|
||||
/* Florida State University */
|
||||
/* Tallahassee FL, 32306-4532 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef __SFCNN___
|
||||
#define __SFCNN___
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <pair_iter.hpp>
|
||||
#include <qknn.hpp>
|
||||
#include <zorder_lt.hpp>
|
||||
#include <bsearch.hpp>
|
||||
/*!
|
||||
\mainpage STANN Doxygen Index Page
|
||||
|
||||
This Doxygen API is intended for users interested in modifying
|
||||
the STANN library. For instructions on using STANN, see the
|
||||
STANN webpage at http://www.compgeom.com/~stann or the README.txt
|
||||
file located in the main directory of the STANN distribution.
|
||||
|
||||
The API is still being updated. For requests/comments/errors,
|
||||
please contact us at stann @ compgeom dot com
|
||||
*/
|
||||
|
||||
/*!
|
||||
\file
|
||||
\brief Space filling curve nearest neighbor search
|
||||
This file contains the implementation of a space filling curve
|
||||
nearest neighbor search data structure
|
||||
*/
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*!
|
||||
\brief A space filling curve nearest neighbor class.
|
||||
|
||||
This is the workhorse class for the sfcnn class.
|
||||
The Space Filling Curve Nearest Neighbor (SFCNN) algorithm sorts the
|
||||
input data set into 2-order Morton ordering. Nearest neighbors are then
|
||||
calculated based on that curve. The algorithm has a runtime of O(ln(N)),
|
||||
a construction time of O(Nlog(N)), and a space requirement of
|
||||
O(N). The query functions of the algorithm are thread-safe.
|
||||
*/
|
||||
template <typename Point>
|
||||
class sfcnn_work
|
||||
{
|
||||
template<typename P, unsigned int D, typename N> friend class sfcnn;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructor
|
||||
*/
|
||||
sfcnn_work();
|
||||
|
||||
/*!
|
||||
\brief Destructor
|
||||
*/
|
||||
~sfcnn_work();
|
||||
|
||||
private:
|
||||
/*!
|
||||
\brief Nearest Neighbor search function
|
||||
Searches for the k nearest neighbors to the point q. The answer
|
||||
vector returned will contain the indexes to the answer points
|
||||
This function is thread-safe.
|
||||
\param q The query point
|
||||
\param k The number of neighbors to return
|
||||
\param nn_idx Answer vector
|
||||
\param eps Error tolerence, default of 0.0.
|
||||
\param sl Unused, for backwards compatibility
|
||||
*/
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, float eps = 0);
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, vector<double> &dist, float eps = 0);
|
||||
|
||||
vector<Point> points;
|
||||
vector<long unsigned int> pointers;
|
||||
zorder_lt<Point> lt;
|
||||
|
||||
|
||||
|
||||
float eps;
|
||||
typename Point::__NumType max, min;
|
||||
|
||||
void compute_bounding_box(Point q, Point &q1, Point &q2, double r);
|
||||
void sfcnn_work_init(int num_threads);
|
||||
|
||||
void ksearch_common(Point q, unsigned int k, long unsigned int j, qknn &que, float Eps);
|
||||
|
||||
inline void recurse(int s, int n, Point q,
|
||||
qknn &ans, Point &q1, Point &q2, int bb, int bt);
|
||||
|
||||
};
|
||||
|
||||
template<typename Point>
|
||||
sfcnn_work<Point>::sfcnn_work()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void sfcnn_work<Point>::sfcnn_work_init(int num_threads)
|
||||
{
|
||||
max = numeric_limits<typename Point::__NumType>::max();
|
||||
min = numeric_limits<typename Point::__NumType>::min();
|
||||
|
||||
pair_iter<typename vector<Point>::iterator,
|
||||
typename vector<long unsigned int>::iterator> a(points.begin(), pointers.begin()),
|
||||
b(points.end(), pointers.end());
|
||||
sort(a,b,lt);
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
sfcnn_work<Point>::~sfcnn_work()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void sfcnn_work<Point>::recurse(int s, // Starting index
|
||||
int n, // Number of points
|
||||
Point q, // Query point
|
||||
qknn &ans, // Answer que
|
||||
Point &bound_box_lower_corner,
|
||||
Point &bound_box_upper_corner,
|
||||
int initial_scan_lower_range,
|
||||
int initial_scan_upper_range)
|
||||
{
|
||||
if(n < 4)
|
||||
{
|
||||
if(n == 0) return;
|
||||
|
||||
bool update=false;
|
||||
for(int i=0;i < n;++i)
|
||||
{
|
||||
if((s+i >= initial_scan_lower_range)
|
||||
&& (s+i < initial_scan_upper_range))
|
||||
continue;
|
||||
update = ans.update(points[s+i].sqr_dist(q), pointers[s+i]) || update;
|
||||
}
|
||||
if(update)
|
||||
compute_bounding_box(q, bound_box_lower_corner, bound_box_upper_corner, sqrt(ans.topdist()));
|
||||
return;
|
||||
}
|
||||
|
||||
if((s+n/2 >= initial_scan_lower_range) && (s+n/2 < initial_scan_upper_range))
|
||||
{
|
||||
}
|
||||
else if(ans.update(points[s+n/2].sqr_dist(q), pointers[s+n/2]))
|
||||
compute_bounding_box(q, bound_box_lower_corner, bound_box_upper_corner, sqrt(ans.topdist()));
|
||||
|
||||
double dsqb = lt.dist_sq_to_quad_box(q,points[s], points[s+n-1]);
|
||||
|
||||
//cout << "dsqb: " << dsqb << endl;
|
||||
//cout << "dist: " << ans.topdist() << endl;
|
||||
//cout << "p1 : " << points[s] << endl;
|
||||
//cout << "p2 : " << points[s+n-1] << endl;
|
||||
if(dsqb > ans.topdist())
|
||||
return;
|
||||
|
||||
|
||||
if(lt(q,points[s+n/2]))
|
||||
{
|
||||
//search_queue.push(pair<int, int>(s, n/2));
|
||||
recurse(s, n/2, q, ans,
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
initial_scan_lower_range,
|
||||
initial_scan_upper_range);
|
||||
if(lt(points[s+n/2],bound_box_upper_corner))
|
||||
//search_queue.push(pair<int, int>(s+n/2+1, n-n/2-1));
|
||||
recurse(s+n/2+1,n-n/2-1, q, ans,
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
initial_scan_lower_range,
|
||||
initial_scan_upper_range);
|
||||
}
|
||||
else
|
||||
{
|
||||
recurse(s+n/2+1, n-n/2-1, q, ans,
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
initial_scan_lower_range,
|
||||
initial_scan_upper_range);
|
||||
//search_queue.push(pair<int, int>(s+n/2+1, n-n/2-1));
|
||||
if(lt(bound_box_lower_corner,points[s+n/2]))
|
||||
//search_queue.push(pair<int, int>(s, n/2));
|
||||
recurse(s, n/2, q, ans,
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
initial_scan_lower_range,
|
||||
initial_scan_upper_range);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void sfcnn_work<Point>::compute_bounding_box(Point q, Point &q1, Point &q2, double R)
|
||||
{
|
||||
typename Point::__NumType radius;
|
||||
radius = (typename Point::__NumType) ceil(R);
|
||||
for(unsigned int i=0;i<Point::__DIM;++i)
|
||||
{
|
||||
if(q[i] < (min+radius)) q1[i] = min;
|
||||
else q1[i] = q[i]-radius;
|
||||
|
||||
if(q[i] > (max-radius)) q2[i] = max;
|
||||
else q2[i] = q[i]+radius;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void sfcnn_work<Point>::ksearch_common(Point q, unsigned int k, long unsigned int query_point_index, qknn &que, float Eps)
|
||||
{
|
||||
Point bound_box_lower_corner, bound_box_upper_corner;
|
||||
Point low, high;
|
||||
|
||||
que.set_size(k);
|
||||
eps=1.0+Eps;
|
||||
if(query_point_index >= (k)) query_point_index -= (k);
|
||||
else query_point_index=0;
|
||||
|
||||
int initial_scan_upper_range=query_point_index+2*k+1;
|
||||
if(initial_scan_upper_range > (int)points.size())
|
||||
initial_scan_upper_range = points.size();
|
||||
|
||||
low = points[query_point_index];
|
||||
high = points[initial_scan_upper_range-1];
|
||||
for(int i=query_point_index;i<initial_scan_upper_range;++i)
|
||||
{
|
||||
que.update(points[i].sqr_dist(q), pointers[i]);
|
||||
}
|
||||
compute_bounding_box(q, bound_box_lower_corner, bound_box_upper_corner, sqrt(que.topdist()));
|
||||
|
||||
if(lt(bound_box_upper_corner, high) && lt(low,bound_box_lower_corner))
|
||||
{
|
||||
//cout << "Inital search break!" << endl;
|
||||
//cout << "Bb1: " << bound_box_lower_corner << endl;
|
||||
//cout << "Bb2: " << bound_box_upper_corner << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//Recurse through the entire set
|
||||
recurse(0, points.size(), q, que,
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
query_point_index,
|
||||
initial_scan_upper_range);
|
||||
//cout << "Bb1: " << bound_box_lower_corner << endl;
|
||||
//cout << "Bb2: " << bound_box_upper_corner << endl;
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void sfcnn_work<Point>::ksearch(Point q, unsigned int k,
|
||||
vector<long unsigned int> &nn_idx, float Eps)
|
||||
{
|
||||
long unsigned int query_point_index;
|
||||
qknn que;
|
||||
query_point_index = BinarySearch(points, q, lt);
|
||||
ksearch_common(q, k, query_point_index, que, Eps);
|
||||
que.answer(nn_idx);
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void sfcnn_work<Point>::ksearch(Point q, unsigned int k,
|
||||
vector<long unsigned int> &nn_idx, vector<double> &dist, float Eps)
|
||||
{
|
||||
long unsigned int query_point_index;
|
||||
qknn que;
|
||||
query_point_index = BinarySearch(points, q, lt);
|
||||
ksearch_common(q, k, query_point_index, que, Eps);
|
||||
que.answer(nn_idx, dist);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Nearest Neighbor search class
|
||||
|
||||
This class is a wrapper class for the sfcnn_work class.
|
||||
There are several template specializations for this class
|
||||
that select the appropriate seperated float type to be used
|
||||
for various floating point coordinate types.
|
||||
\param Point Data type that stores user points
|
||||
\param Dim Dimension of user points
|
||||
\param NumType Data type that stores coordinates of user points
|
||||
*/
|
||||
template <typename Point, unsigned int Dim, typename NumType>
|
||||
class sfcnn
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Default Constructor
|
||||
*/
|
||||
sfcnn(){};
|
||||
/*!
|
||||
\brief Constructor
|
||||
|
||||
Constructs a nearest neighbor data structure using the
|
||||
given data points.
|
||||
\param *points Pointer to the first data point
|
||||
\param N number of data points
|
||||
\param num_threads Currently unused. (multiple processor construction soon!)
|
||||
*/
|
||||
sfcnn(Point *points, long int N, int num_threads=1)
|
||||
{
|
||||
sfcnn_init(points,N,num_threads);
|
||||
};
|
||||
~sfcnn(){};
|
||||
|
||||
/*!
|
||||
\brief Nearest Neighbor search function
|
||||
|
||||
Searches for the k nearest neighbors to the point q. The answer
|
||||
vector returned will contain the indexes to the answer points
|
||||
This function is thread-safe.
|
||||
\param q The query point
|
||||
\param k The number of neighbors to return
|
||||
\param nn_idx Answer vector
|
||||
\param eps Error tolerence, default of 0.0.
|
||||
*/
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, float eps = 0)
|
||||
{
|
||||
NN.ksearch(q,k,nn_idx,eps);
|
||||
};
|
||||
/*!
|
||||
\brief Nearest Neighbor search function
|
||||
|
||||
Searches for the k nearest neighbors to the point q. The answer
|
||||
vector returned will contain the indexes to the answer points.
|
||||
The distance vector contains the square distances to the answer points.
|
||||
This function is thread-safe.
|
||||
\param q The query point
|
||||
\param k The number of neighbors to return
|
||||
\param nn_idx Answer vector
|
||||
\param dist Distance vector
|
||||
\param eps Error tolerence, default of 0.0.
|
||||
*/
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, vector<double> &dist, float eps=0)
|
||||
{
|
||||
NN.ksearch(q,k,nn_idx,dist,eps);
|
||||
};
|
||||
private:
|
||||
sfcnn_work<reviver::dpoint<NumType, Dim> > NN;
|
||||
void sfcnn_init(Point *points, long int N, int num_threads=1)
|
||||
{
|
||||
NN.points.resize(N);
|
||||
NN.pointers.resize(N);
|
||||
|
||||
for(long int i=0;i < N;++i)
|
||||
{
|
||||
NN.pointers[i] = (i);
|
||||
for(unsigned int j=0;j < Dim;++j)
|
||||
NN.points[i][j] = points[i][j];
|
||||
}
|
||||
NN.sfcnn_work_init(num_threads);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename Point, unsigned int Dim>
|
||||
class sfcnn <Point, Dim, float>
|
||||
{
|
||||
public:
|
||||
sfcnn(){};
|
||||
sfcnn(Point *points, long int N, int num_threads=1)
|
||||
{
|
||||
sfcnn_init(points,N,num_threads);
|
||||
};
|
||||
~sfcnn(){};
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, float eps = 0)
|
||||
{
|
||||
reviver::dpoint<sep_float<float>, Dim> Q;
|
||||
for(unsigned int i=0;i < Dim;++i)
|
||||
Q[i] = q[i];
|
||||
NN.ksearch(Q,k,nn_idx,eps);
|
||||
};
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, vector<double> &dist, float eps=0)
|
||||
{
|
||||
reviver::dpoint<sep_float<float>, Dim> Q;
|
||||
for(unsigned int i=0;i < Dim;++i)
|
||||
Q[i] = q[i];
|
||||
NN.ksearch(Q,k,nn_idx,dist,eps);
|
||||
};
|
||||
;
|
||||
private:
|
||||
sfcnn_work<reviver::dpoint<sep_float<float>, Dim> > NN;
|
||||
void sfcnn_init(Point *points, long int N, int num_threads=1)
|
||||
{
|
||||
NN.points.resize(N);
|
||||
NN.pointers.resize(N);
|
||||
|
||||
for(long int i=0;i < N;++i)
|
||||
{
|
||||
NN.pointers[i] = i;
|
||||
for(unsigned int j=0;j < Dim;++j)
|
||||
{
|
||||
NN.points[i][j] = points[i][j];
|
||||
}
|
||||
}
|
||||
NN.sfcnn_work_init(num_threads);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename Point, unsigned int Dim>
|
||||
class sfcnn <Point, Dim, double>
|
||||
{
|
||||
public:
|
||||
sfcnn(){};
|
||||
sfcnn(Point *points, long int N, int num_threads=1)
|
||||
{
|
||||
sfcnn_init(points,N,num_threads);
|
||||
};
|
||||
~sfcnn(){};
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, float eps = 0)
|
||||
{
|
||||
reviver::dpoint<sep_float<double>, Dim> Q;
|
||||
for(unsigned int i=0;i < Dim;++i)
|
||||
Q[i] = q[i];
|
||||
NN.ksearch(Q,k,nn_idx,eps);
|
||||
};
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, vector<double> &dist, float eps=0)
|
||||
{
|
||||
reviver::dpoint<sep_float<double>, Dim> Q;
|
||||
for(unsigned int i=0;i < Dim;++i)
|
||||
Q[i] = q[i];
|
||||
NN.ksearch(Q,k,nn_idx,dist,eps);
|
||||
};
|
||||
private:
|
||||
void sfcnn_init(Point *points, long int N, int num_threads=1)
|
||||
{
|
||||
NN.points.resize(N);
|
||||
NN.pointers.resize(N);
|
||||
|
||||
for(long int i=0;i < N;++i)
|
||||
{
|
||||
NN.pointers[i] = i;
|
||||
for(unsigned int j=0;j < Dim;++j)
|
||||
NN.points[i][j] = points[i][j];
|
||||
}
|
||||
NN.sfcnn_work_init(num_threads);
|
||||
};
|
||||
sfcnn_work<reviver::dpoint<sep_float<double>, Dim> > NN;
|
||||
};
|
||||
|
||||
template <typename Point, unsigned int Dim>
|
||||
class sfcnn <Point, Dim, long double>
|
||||
{
|
||||
public:
|
||||
sfcnn(){};
|
||||
sfcnn(Point *points, long int N, int num_threads=1)
|
||||
{
|
||||
sfcnn_init(points,N,num_threads);
|
||||
};
|
||||
~sfcnn(){};
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, float eps = 0)
|
||||
{
|
||||
reviver::dpoint<sep_float<long double>, Dim> Q;
|
||||
for(unsigned int i=0;i < Dim;++i)
|
||||
Q[i] = q[i];
|
||||
NN.ksearch(Q,k,nn_idx,eps);
|
||||
};
|
||||
void ksearch(Point q, unsigned int k, vector<long unsigned int> &nn_idx, vector<double> &dist, float eps=0)
|
||||
{
|
||||
reviver::dpoint<sep_float<long double>, Dim> Q;
|
||||
for(unsigned int i=0;i < Dim;++i)
|
||||
Q[i] = q[i];
|
||||
NN.ksearch(Q,k,nn_idx,dist,eps);
|
||||
};
|
||||
private:
|
||||
void sfcnn_init(Point *points, long int N, int num_threads=1)
|
||||
{
|
||||
NN.points.resize(N);
|
||||
NN.pointers.resize(N);
|
||||
|
||||
for(long int i=0;i < N;++i)
|
||||
{
|
||||
NN.pointers[i] = i;
|
||||
for(unsigned int j=0;j < Dim;++j)
|
||||
NN.points[i][j] = points[i][j];
|
||||
}
|
||||
NN.sfcnn_work_init(num_threads);
|
||||
};
|
||||
sfcnn_work<reviver::dpoint<sep_float<long double>, Dim> > NN;
|
||||
};
|
||||
#endif
|
|
@ -1,396 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Header: sfcnn_knng.hpp */
|
||||
/* */
|
||||
/* Accompanies STANN Version 0.5 Beta */
|
||||
/* Aug 05, 2008 */
|
||||
/* */
|
||||
/* Copyright 2007, 2008 */
|
||||
/* Michael Connor and Piyush Kumar */
|
||||
/* Florida State University */
|
||||
/* Tallahassee FL, 32306-4532 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __KNNGRAPH__
|
||||
#define __KNNGRAPH__
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
|
||||
#include <pthread.h>
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include <pair_iter.hpp>
|
||||
#include <qknn.hpp>
|
||||
#include <zorder_lt.hpp>
|
||||
#include <bsearch.hpp>
|
||||
|
||||
|
||||
/*!
|
||||
\file sfcnn_knng.hpp
|
||||
\brief Implements K-Nearest Neighbor Graph construction using SFC nearest neighbor algorithm. Construction is done in parallel using OpenMP.
|
||||
*/
|
||||
|
||||
using namespace std;
|
||||
|
||||
template <typename Point>
|
||||
class sfcnn_knng_work
|
||||
{
|
||||
public:
|
||||
|
||||
sfcnn_knng_work(){};
|
||||
~sfcnn_knng_work(){};
|
||||
|
||||
void sfcnn_knng_work_init(long int N, unsigned int k, int num_threads);
|
||||
|
||||
vector<vector<long unsigned int> > answer;
|
||||
vector<Point> points;
|
||||
vector<long unsigned int> pointers;
|
||||
|
||||
private:
|
||||
void compute_bounding_box(Point q, Point &q1, Point &q2, double r);
|
||||
void recurse(int s, // Starting index
|
||||
int n, // Number of points
|
||||
long int q, // Query point
|
||||
qknn &ans, // Answer que
|
||||
Point &bound_box_lower_corner,
|
||||
Point &bound_box_upper_corner,
|
||||
int initial_scan_lower_range,
|
||||
int initial_scan_upper_range,
|
||||
zorder_lt<Point> <);
|
||||
|
||||
typename Point::__NumType max, min;
|
||||
};
|
||||
|
||||
|
||||
template<typename Point>
|
||||
void sfcnn_knng_work<Point>::sfcnn_knng_work_init(long int N, unsigned int k, int num_threads)
|
||||
{
|
||||
zorder_lt<Point> lt;
|
||||
Point bound_box_lower_corner,
|
||||
bound_box_upper_corner;
|
||||
double distance;
|
||||
long int range_b;
|
||||
long int range_e;
|
||||
|
||||
max = numeric_limits<typename Point::__NumType>::max();
|
||||
min = numeric_limits<typename Point::__NumType>::min();
|
||||
answer.resize(N);
|
||||
|
||||
#ifdef _OPENMP
|
||||
long int chunk = N/num_threads;
|
||||
omp_set_num_threads(num_threads);
|
||||
#endif
|
||||
|
||||
pair_iter<typename vector<Point>::iterator,
|
||||
typename vector<long unsigned int>::iterator> a(points.begin(), pointers.begin()),
|
||||
b(points.end(), pointers.end());
|
||||
sort(a,b,lt);
|
||||
|
||||
vector<qknn> que;
|
||||
que.resize(N);
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel private(distance, range_b, range_e)
|
||||
#endif
|
||||
{
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for schedule(static, chunk)
|
||||
#endif
|
||||
for(long int i=0;i < N;++i)
|
||||
{
|
||||
range_b = i-k;
|
||||
if(range_b < 0) range_b = 0;
|
||||
range_e = i+k+1;
|
||||
if(range_e > N) range_e = N;
|
||||
que[i].set_size(k);
|
||||
for(long int j=range_b;j < i;++j)
|
||||
{
|
||||
distance = points[i].sqr_dist(points[j]);
|
||||
que[i].update(distance, pointers[j]);
|
||||
}
|
||||
for(long int j=i+1;j < range_e;++j)
|
||||
{
|
||||
distance = points[i].sqr_dist(points[j]);
|
||||
que[i].update(distance, pointers[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel private(distance, range_b, range_e, bound_box_lower_corner, bound_box_upper_corner)
|
||||
#endif
|
||||
{
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for schedule(static, chunk)
|
||||
#endif
|
||||
for(long int i=0;i < N;++i)
|
||||
{
|
||||
range_b = i-k;
|
||||
if(range_b < 0) range_b = 0;
|
||||
range_e = i+k+1;
|
||||
if(range_e > N) range_e = N;
|
||||
compute_bounding_box(points[i], bound_box_lower_corner, bound_box_upper_corner, sqrt(que[i].topdist()));
|
||||
|
||||
if(!lt(bound_box_upper_corner, points[range_e]) || !lt(points[range_b], bound_box_lower_corner))
|
||||
{
|
||||
recurse(0, points.size(), i, que[i],
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
range_b,
|
||||
range_e,
|
||||
lt);
|
||||
|
||||
}
|
||||
que[i].answer(answer[pointers[i]]);
|
||||
}
|
||||
}
|
||||
points.clear();
|
||||
pointers.clear();
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void sfcnn_knng_work<Point>::compute_bounding_box(Point q, Point &q1, Point &q2, double R)
|
||||
{
|
||||
typename Point::__NumType radius;
|
||||
radius = (typename Point::__NumType) ceil(R);
|
||||
for(unsigned int i=0;i<Point::__DIM;++i)
|
||||
{
|
||||
|
||||
if(q[i] < (min+radius)) q1[i] = min;
|
||||
else q1[i] = q[i]-radius;
|
||||
|
||||
if(q[i] > (max-radius)) q2[i] = max;
|
||||
else q2[i] = q[i]+radius;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Point>
|
||||
void sfcnn_knng_work<Point>::recurse(int s, // Starting index
|
||||
int n, // Number of points
|
||||
long int q,
|
||||
qknn &ans, // Answer que
|
||||
Point &bound_box_lower_corner,
|
||||
Point &bound_box_upper_corner,
|
||||
int initial_scan_lower_range,
|
||||
int initial_scan_upper_range,
|
||||
zorder_lt<Point> <)
|
||||
{
|
||||
double distance;
|
||||
if(n < 4)
|
||||
{
|
||||
if(n == 0) return;
|
||||
|
||||
bool update=false;
|
||||
for(int i=0;i < n;++i)
|
||||
{
|
||||
if((s+i >= initial_scan_lower_range)
|
||||
&& (s+i < initial_scan_upper_range))
|
||||
continue;
|
||||
distance = points[q].sqr_dist(points[s+i]);
|
||||
update = ans.update(distance, pointers[s+i]) || update;
|
||||
}
|
||||
if(update)
|
||||
compute_bounding_box(points[q], bound_box_lower_corner, bound_box_upper_corner, sqrt(ans.topdist()));
|
||||
return;
|
||||
}
|
||||
|
||||
if((s+n/2 >= initial_scan_lower_range) && (s+n/2 < initial_scan_upper_range))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = points[q].sqr_dist(points[s+n/2]);
|
||||
if(ans.update(distance, pointers[s+n/2]))
|
||||
compute_bounding_box(points[q], bound_box_lower_corner, bound_box_upper_corner, sqrt(ans.topdist()));
|
||||
}
|
||||
|
||||
if((lt.dist_sq_to_quad_box(points[q],points[s], points[s+n-1])) > ans.topdist())
|
||||
return;
|
||||
|
||||
|
||||
if(lt(points[q],points[s+n/2]))
|
||||
{
|
||||
recurse(s, n/2, q, ans,
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
initial_scan_lower_range,
|
||||
initial_scan_upper_range,
|
||||
lt);
|
||||
if(lt(points[s+n/2],bound_box_upper_corner))
|
||||
recurse(s+n/2+1,n-n/2-1, q, ans,
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
initial_scan_lower_range,
|
||||
initial_scan_upper_range,
|
||||
lt);
|
||||
}
|
||||
else
|
||||
{
|
||||
recurse(s+n/2+1, n-n/2-1, q, ans,
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
initial_scan_lower_range,
|
||||
initial_scan_upper_range,
|
||||
lt);
|
||||
if(lt(bound_box_lower_corner,points[s+n/2]))
|
||||
recurse(s, n/2, q, ans,
|
||||
bound_box_lower_corner,
|
||||
bound_box_upper_corner,
|
||||
initial_scan_lower_range,
|
||||
initial_scan_upper_range,
|
||||
lt);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Point, unsigned int Dim, typename NumType>
|
||||
class sfcnn_knng
|
||||
{
|
||||
public:
|
||||
sfcnn_knng(){};
|
||||
sfcnn_knng(Point *points, long int N, unsigned int k, int num_threads=1)
|
||||
{
|
||||
sfcnn_knng_init(points,N,k,num_threads);
|
||||
};
|
||||
~sfcnn_knng(){};
|
||||
vector<long unsigned int>& operator[](long unsigned int i)
|
||||
{
|
||||
return NN.answer[i];
|
||||
};
|
||||
private:
|
||||
void sfcnn_knng_init(Point *points, long int N, unsigned int k, int num_threads=1)
|
||||
{
|
||||
NN.points.resize(N);
|
||||
NN.pointers.resize(N);
|
||||
#ifdef _OPENMP
|
||||
long int chunk = N/num_threads;
|
||||
omp_set_num_threads(num_threads);
|
||||
#pragma omp parallel for schedule(static, chunk)
|
||||
#endif
|
||||
for(int i=0;i < N;++i)
|
||||
{
|
||||
NN.pointers[i] = (i);
|
||||
for(unsigned int j=0;j < Dim;++j)
|
||||
NN.points[i][j] = points[i][j];
|
||||
}
|
||||
NN.sfcnn_knng_work_init(N, k, num_threads);
|
||||
};
|
||||
sfcnn_knng_work<reviver::dpoint<NumType, Dim> > NN;
|
||||
};
|
||||
|
||||
template <typename Point, unsigned int Dim>
|
||||
class sfcnn_knng <Point, Dim, float>
|
||||
{
|
||||
public:
|
||||
sfcnn_knng(){};
|
||||
sfcnn_knng(Point *points, long int N, unsigned int k, int num_threads=1)
|
||||
{
|
||||
sfcnn_knng_init(points,N,k,num_threads);
|
||||
};
|
||||
~sfcnn_knng(){};
|
||||
vector<long unsigned int>& operator[](long unsigned int i)
|
||||
{
|
||||
return NN.answer[i];
|
||||
};
|
||||
private:
|
||||
void sfcnn_knng_init(Point *points, long int N, unsigned int k, int num_threads=1)
|
||||
{
|
||||
NN.points.resize(N);
|
||||
NN.pointers.resize(N);
|
||||
|
||||
#ifdef _OPENMP
|
||||
long int chunk = N/num_threads;
|
||||
omp_set_num_threads(num_threads);
|
||||
#pragma omp parallel for schedule(static, chunk)
|
||||
#endif
|
||||
for(int i=0;i < N;++i)
|
||||
{
|
||||
NN.pointers[i] = i;
|
||||
for(unsigned int j=0;j < Dim;++j)
|
||||
{
|
||||
NN.points[i][j] = points[i][j];
|
||||
}
|
||||
}
|
||||
NN.sfcnn_knng_work_init(N,k,num_threads);
|
||||
};
|
||||
sfcnn_knng_work<reviver::dpoint<sep_float<float>, Dim> > NN;
|
||||
};
|
||||
|
||||
template <typename Point, unsigned int Dim>
|
||||
class sfcnn_knng <Point, Dim, double>
|
||||
{
|
||||
public:
|
||||
sfcnn_knng(){};
|
||||
sfcnn_knng(Point *points, long int N, unsigned int k, int num_threads=1)
|
||||
{
|
||||
sfcnn_knng_init(points,N,k,num_threads);
|
||||
};
|
||||
~sfcnn_knng(){};
|
||||
vector<long unsigned int>& operator[](long unsigned int i)
|
||||
{
|
||||
return NN.answer[i];
|
||||
};
|
||||
private:
|
||||
void sfcnn_knng_init(Point *points, long int N, unsigned int k, int num_threads=1)
|
||||
{
|
||||
NN.points.resize(N);
|
||||
NN.pointers.resize(N);
|
||||
|
||||
#ifdef _OPENMP
|
||||
long int chunk = N/num_threads;
|
||||
omp_set_num_threads(num_threads);
|
||||
#pragma omp parallel for schedule(static, chunk)
|
||||
#endif
|
||||
for(int i=0;i < N;++i)
|
||||
{
|
||||
NN.pointers[i] = i;
|
||||
for(unsigned int j=0;j < Dim;++j)
|
||||
NN.points[i][j] = points[i][j];
|
||||
}
|
||||
NN.sfcnn_knng_work_init(N,k,num_threads);
|
||||
};
|
||||
sfcnn_knng_work<reviver::dpoint<sep_float<double>, Dim> > NN;
|
||||
};
|
||||
|
||||
template <typename Point, unsigned int Dim>
|
||||
class sfcnn_knng <Point, Dim, long double>
|
||||
{
|
||||
public:
|
||||
sfcnn_knng(){};
|
||||
sfcnn_knng(Point *points, long int N, unsigned int k, int num_threads=1)
|
||||
{
|
||||
sfcnn_knng_init(points,N,k,num_threads);
|
||||
};
|
||||
~sfcnn_knng(){};
|
||||
vector<long unsigned int>& operator[](long unsigned int i)
|
||||
{
|
||||
return NN.answer[i];
|
||||
};
|
||||
private:
|
||||
void sfcnn_knng_init(Point *points, long int N, unsigned int k, int num_threads=1)
|
||||
{
|
||||
NN.points.resize(N);
|
||||
NN.pointers.resize(N);
|
||||
|
||||
#ifdef _OPENMP
|
||||
long int chunk = N/num_threads;
|
||||
omp_set_num_threads(num_threads);
|
||||
#pragma omp parallel for schedule(static, chunk)
|
||||
#endif
|
||||
for(int i=0;i < N;++i)
|
||||
{
|
||||
NN.pointers[i] = i;
|
||||
for(unsigned int j=0;j < Dim;++j)
|
||||
NN.points[i][j] = points[i][j];
|
||||
}
|
||||
NN.sfcnn_knng_work_init(N,k,num_threads);
|
||||
};
|
||||
sfcnn_knng_work<reviver::dpoint<sep_float<long double>, Dim> > NN;
|
||||
};
|
||||
#endif
|
|
@ -1,143 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Header: test.hpp */
|
||||
/* */
|
||||
/* Accompanies STANN Version 0.5 Beta */
|
||||
/* Aug 05, 2008 */
|
||||
/* */
|
||||
/* Copyright 2007, 2008 */
|
||||
/* Michael Connor and Piyush Kumar */
|
||||
/* Florida State University */
|
||||
/* Tallahassee FL, 32306-4532 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef STANN_TEST
|
||||
#define STANN_TEST
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <bruteNN.hpp>
|
||||
#include <dpoint.hpp>
|
||||
#include <rand.hpp>
|
||||
#include <sfcnn.hpp>
|
||||
#include <sfcnn_knng.hpp>
|
||||
|
||||
using namespace std;
|
||||
/*! \file test.hpp
|
||||
\brief Header file for the test.cpp program.*/
|
||||
|
||||
template<typename Point, typename T>
|
||||
Point newRandomPoint(T Min, T Max)
|
||||
{
|
||||
double d;
|
||||
Point a;
|
||||
double max, min;
|
||||
|
||||
max = (double) Max / (double) numeric_limits<T>::max();
|
||||
min = (double) Min / (double) numeric_limits<T>::max();
|
||||
for(unsigned int i=0;i < Point::__DIM;++i)
|
||||
{
|
||||
d = __drand48__();
|
||||
d = d*(max-min)-max;
|
||||
d *= (double) numeric_limits<T>::max();
|
||||
d *= -1;
|
||||
a[i] = (T) d;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
template<typename T, unsigned DIM>
|
||||
bool testNN(unsigned int Size, unsigned int k, T min, T max)
|
||||
{
|
||||
typedef reviver::dpoint<T, DIM> Point;
|
||||
vector<Point> data;
|
||||
vector<Point> query;
|
||||
vector<long unsigned int> sfcnn_ans;
|
||||
vector<long unsigned int> bf_ans;
|
||||
|
||||
data.resize(Size);
|
||||
query.resize(Size);
|
||||
|
||||
for(unsigned int i=0;i < data.size();++i)
|
||||
{
|
||||
data[i] = newRandomPoint<Point, T>(min, max);
|
||||
query[i] = newRandomPoint<Point, T>(min, max);
|
||||
}
|
||||
|
||||
bruteNN<Point> BF(&data[0], data.size());
|
||||
sfcnn<Point, DIM, T> SFC(&data[0], data.size());
|
||||
|
||||
for(unsigned int i=0;i < data.size();++i)
|
||||
{
|
||||
BF.ksearch(query[i], k, bf_ans);
|
||||
SFC.ksearch(query[i], k, sfcnn_ans);
|
||||
|
||||
for(unsigned int j=0;j < Point::__DIM;++j)
|
||||
{
|
||||
if(bf_ans[j] != sfcnn_ans[j])
|
||||
{
|
||||
/*
|
||||
cerr << "SFCNN:" << endl;
|
||||
for(unsigned int q=0;q < sfcnn_ans.size();++q)
|
||||
{
|
||||
cerr << sfcnn_ans[q] << endl;
|
||||
}
|
||||
cerr << "BF:" << endl;
|
||||
for(unsigned int q=0;q < bf_ans.size();++q)
|
||||
{
|
||||
cerr << bf_ans[q] << endl;
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, unsigned DIM>
|
||||
bool testKNNG(unsigned int Size, unsigned int k, T min, T max, int num_threads)
|
||||
{
|
||||
typedef reviver::dpoint<T, DIM> Point;
|
||||
vector<Point> data;
|
||||
vector<long unsigned int> bf_ans;
|
||||
|
||||
data.resize(Size);
|
||||
|
||||
for(unsigned int i=0;i < data.size();++i)
|
||||
{
|
||||
data[i] = newRandomPoint<Point, T>(min, max);
|
||||
}
|
||||
|
||||
bruteNN<Point> BF(&data[0], data.size());
|
||||
sfcnn_knng<Point, DIM, T> SFC(&data[0], data.size(), k, num_threads);
|
||||
|
||||
for(unsigned int i=0;i < data.size();++i)
|
||||
{
|
||||
BF.ksearch(data[i], k+1, bf_ans);
|
||||
for(unsigned int j=1;j < k+1;++j)
|
||||
{
|
||||
if(bf_ans[j] != SFC[i][j-1])
|
||||
{
|
||||
|
||||
cerr << "SFCNN:" << endl;
|
||||
for(unsigned int q=0;q < SFC[i].size();++q)
|
||||
{
|
||||
cerr << SFC[i][q] << endl;
|
||||
}
|
||||
cerr << "BF:" << endl;
|
||||
for(unsigned int q=0;q < bf_ans.size();++q)
|
||||
{
|
||||
cerr << bf_ans[q] << endl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -1,275 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Header: zorder_lt.hpp */
|
||||
/* */
|
||||
/* Accompanies STANN Version 0.5 Beta */
|
||||
/* Aug 05, 2008 */
|
||||
/* */
|
||||
/* Copyright 2007, 2008 */
|
||||
/* Michael Connor and Piyush Kumar */
|
||||
/* Florida State University */
|
||||
/* Tallahassee FL, 32306-4532 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef __SFCNN_ZORDER_LT__
|
||||
#define __SFCNN_ZORDER_LT__
|
||||
|
||||
#include <dpoint.hpp>
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
#include <zorder_type_traits.hpp>
|
||||
#include <sep_float.hpp>
|
||||
#include <pair_iter.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<typename Point>
|
||||
class zorder_lt;
|
||||
template<typename Point, typename CType, typename sign_trait, typename integral_trait, typename sep_trait>
|
||||
class zorder_lt_worker;
|
||||
|
||||
//Z Order spec for unsigned integral types
|
||||
template<typename Point, typename CType>
|
||||
class zorder_lt_worker <Point, CType, zorder_f, zorder_t, zorder_f>
|
||||
{
|
||||
public:
|
||||
zorder_lt_worker(){;}
|
||||
~zorder_lt_worker(){;}
|
||||
bool operator()(const Point &p, const Point &q)
|
||||
{
|
||||
return lt_func(p,q);
|
||||
}
|
||||
|
||||
double dist_sq_to_quad_box(Point &q, Point &p1, Point &p2)
|
||||
{
|
||||
unsigned int j;
|
||||
int i;
|
||||
CType x,y;
|
||||
double z;
|
||||
z=0;
|
||||
for(j=x=0;j < Point::__DIM;++j)
|
||||
{
|
||||
y = p1[j]^p2[j];
|
||||
if(less_msb(x, y))
|
||||
{
|
||||
x = y;
|
||||
}
|
||||
}
|
||||
frexp((float)x, &i);
|
||||
for(j=0;j < Point::__DIM;++j)
|
||||
{
|
||||
x = (((p1)[j])>>i)<<i;
|
||||
y = x+(1 << i);
|
||||
if(q[j] < x)
|
||||
z+= pow(((double) q[j]-(double) x), 2.0);
|
||||
else if(q[j] > y)
|
||||
z+= pow(((double) q[j]-(double) y), 2.0);
|
||||
}
|
||||
//cout << q << endl << p1 << endl << p2 << endl << z << endl;
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
bool lt_func(const Point &p, const Point &q)
|
||||
{
|
||||
CType j,x,y,k;
|
||||
for(j=k=x=0;k < Point::__DIM;++k)
|
||||
{
|
||||
y = (p[k])^(q[k]);
|
||||
if(less_msb(x,y))
|
||||
{
|
||||
j=k;
|
||||
x=y;
|
||||
}
|
||||
}
|
||||
return p[j] < q[j];
|
||||
}
|
||||
|
||||
bool less_msb(CType x, CType y)
|
||||
{
|
||||
return (x < y) && (x < (x^y));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//Z Order spec for signed integral types
|
||||
template<typename Point, typename CType>
|
||||
class zorder_lt_worker <Point, CType, zorder_t, zorder_t, zorder_f>
|
||||
{
|
||||
public:
|
||||
zorder_lt_worker(){;}
|
||||
~zorder_lt_worker(){;}
|
||||
bool operator()(const Point &p, const Point &q)
|
||||
{
|
||||
return lt_func(p,q);
|
||||
}
|
||||
|
||||
double dist_sq_to_quad_box(Point &q, Point &p1, Point &p2)
|
||||
{
|
||||
unsigned int j;
|
||||
int i;
|
||||
CType x,y;
|
||||
double z, X, Y;
|
||||
|
||||
x = numeric_limits<CType>::min();
|
||||
for(j=0;j < Point::__DIM;++j)
|
||||
{
|
||||
if((p1[j] < 0) != (p2[j] < 0))
|
||||
{
|
||||
//cout << "Break out" << endl;
|
||||
//cout << "P1: " << p1 << endl << "P2: " << p2 << endl;
|
||||
return 0;
|
||||
}
|
||||
y = p1[j]^p2[j];
|
||||
if(less_msb(x,y)) x = y;
|
||||
}
|
||||
frexp((double)x, &i);
|
||||
//cout << "i: " << i << endl;
|
||||
//int exp;
|
||||
for(z=j=0;j < Point::__DIM;++j)
|
||||
{
|
||||
X = (p1[j]>>i)<<i;
|
||||
//frexp(p1[j], &exp);
|
||||
//cout << "p1[j]" << (p1[j] >> i) << endl;
|
||||
//cout << "exp: " << exp << endl;
|
||||
//cout << "X: " << X << endl;
|
||||
Y = X+(1 << i);
|
||||
if(q[j] < X)
|
||||
z+=pow(((double) X - (double) q[j]), 2.0);
|
||||
else if(q[j] > Y)
|
||||
z+=pow(((double) q[j] - (double) Y), 2.0);
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
private:
|
||||
bool lt_func(const Point &p, const Point &q)
|
||||
{
|
||||
CType j,x,y;
|
||||
unsigned int k;
|
||||
x = numeric_limits<CType>::min();
|
||||
for(j=k=0;k < Point::__DIM;++k)
|
||||
{
|
||||
if((p[k] < 0) != (q[k] < 0))
|
||||
return p[k] < q[k];
|
||||
y = (p[k])^(q[k]);
|
||||
if(less_msb(x,y))
|
||||
{
|
||||
j=k;
|
||||
x=y;
|
||||
}
|
||||
}
|
||||
return p[j] < q[j];
|
||||
}
|
||||
|
||||
bool less_msb(CType x, CType y)
|
||||
{
|
||||
return (x < y) && (x < (x^y));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//Z Order spec for seperated floating point types
|
||||
template<typename Point, typename CType>
|
||||
class zorder_lt_worker <Point, CType, zorder_t, zorder_f, zorder_t>
|
||||
{
|
||||
public:
|
||||
zorder_lt_worker()
|
||||
{
|
||||
}
|
||||
~zorder_lt_worker(){;}
|
||||
bool operator()(const Point &p, const Point &q)
|
||||
{
|
||||
return lt_func(p,q);
|
||||
}
|
||||
double dist_sq_to_quad_box(Point &q, Point &p1, Point &p2)
|
||||
{
|
||||
unsigned int j;
|
||||
int x,y;
|
||||
double box_edge_1, box_edge_2;
|
||||
double z;
|
||||
typename CType::flt_type box_dist;
|
||||
|
||||
z = 0;
|
||||
x = 0;
|
||||
//cout << "X: " << x << endl;
|
||||
for(j=0;j < Point::__DIM;++j)
|
||||
{
|
||||
if((p1[j].get_flt() < 0) != (p2[j].get_flt() < 0))
|
||||
return 0;
|
||||
y = msdb(p1[j], p2[j]);
|
||||
if(y > x)
|
||||
{
|
||||
x = y;
|
||||
}
|
||||
}
|
||||
box_dist = pow(2.0,x);
|
||||
for(j=0;j < Point::__DIM;++j)
|
||||
{
|
||||
//cout << "p1[j]/2**i: " << floor(p1[j] / box_dist) << endl;
|
||||
//box_edge_1 = p1[j].get_flt() - fmod(p1[j].get_flt(),box_dist);
|
||||
box_edge_1 = floor(p1[j] / box_dist) * box_dist;
|
||||
//cout << "Box1: " << box_edge_1 << endl;
|
||||
box_edge_2 = box_edge_1+box_dist;
|
||||
|
||||
if(q[j].get_flt() < box_edge_1)
|
||||
z+=(q[j].get_flt()-box_edge_1)*(q[j].get_flt()-box_edge_1);
|
||||
else if(q[j].get_flt() > box_edge_2)
|
||||
z+= (q[j].get_flt()-box_edge_2)*(q[j].get_flt()-box_edge_2);
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
private:
|
||||
bool lt_func(const Point &p, const Point &q)
|
||||
{
|
||||
int y,x;
|
||||
unsigned int k,j;
|
||||
j = 0;
|
||||
x = 0;
|
||||
for(k=0;k < Point::__DIM;++k)
|
||||
{
|
||||
if((p[k].get_flt() < 0) != (q[k].get_flt() < 0))
|
||||
return p[k].get_flt() < q[k].get_flt();
|
||||
y = msdb(p[k], q[k]);
|
||||
if(x < y)
|
||||
{
|
||||
j = k;
|
||||
x = y;
|
||||
}
|
||||
}
|
||||
return p[j] < q[j];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Point>
|
||||
class zorder_lt
|
||||
{
|
||||
public:
|
||||
zorder_lt()
|
||||
{
|
||||
zorder_traits<typename Point::__NumType>::check_type();
|
||||
}
|
||||
~zorder_lt(){;}
|
||||
bool operator()(const Point &p, const Point &q)
|
||||
{
|
||||
return lt(p, q);
|
||||
}
|
||||
bool operator()(const Mypair<typename vector<Point>::iterator,typename vector<long unsigned int>::iterator> &p, const Mypair<typename vector<Point>::iterator, typename vector<long unsigned int>::iterator> &q)
|
||||
{
|
||||
return lt(p.val1, q.val1);
|
||||
}
|
||||
double dist_sq_to_quad_box(Point &q, Point &p1, Point &p2)
|
||||
{
|
||||
return lt.dist_sq_to_quad_box(q,p1,p2);
|
||||
}
|
||||
private:
|
||||
zorder_lt_worker<Point, typename Point::__NumType, typename zorder_traits<typename Point::__NumType>::is_signed, typename zorder_traits<typename Point::__NumType>::is_integral, typename zorder_traits<typename Point::__NumType>::is_seperated> lt;
|
||||
};
|
||||
#endif
|
|
@ -1,208 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Header: zorder_type_traits.hpp */
|
||||
/* */
|
||||
/* Accompanies STANN Version 0.5 Beta */
|
||||
/* Aug 05, 2008 */
|
||||
/* */
|
||||
/* Copyright 2007, 2008 */
|
||||
/* Michael Connor and Piyush Kumar */
|
||||
/* Florida State University */
|
||||
/* Tallahassee FL, 32306-4532 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef __ZORDER_TYPE_TRAITS__
|
||||
#define __ZORDER_TYPE_TRAITS__
|
||||
|
||||
#include <iostream>
|
||||
#include <sep_float.hpp>
|
||||
using namespace std;
|
||||
|
||||
struct zorder_t {};
|
||||
struct zorder_f {};
|
||||
|
||||
template<typename TYPE>
|
||||
class zorder_traits
|
||||
{
|
||||
public:
|
||||
static void check_type()
|
||||
{
|
||||
//cerr << "Error: Type traits not defined." << endl;
|
||||
//cerr << "Please ensure the appropriate type is added to zorder_traits.hpp" << endl;
|
||||
//cerr << "and contact author for update." << endl;
|
||||
//exit(1);
|
||||
}
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_t is_integral;
|
||||
typedef int unsigned_type;
|
||||
typedef unsigned int signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <int>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_t is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef unsigned int unsigned_type;
|
||||
typedef int signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <unsigned int>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_f is_signed;
|
||||
typedef zorder_t is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef unsigned int unsigned_type;
|
||||
typedef int signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <char>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_t is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef unsigned char unsigned_type;
|
||||
typedef char signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <unsigned char>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_f is_signed;
|
||||
typedef zorder_t is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef unsigned char unsigned_type;
|
||||
typedef char signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <short>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_t is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef unsigned short unsigned_type;
|
||||
typedef short signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <unsigned short>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_f is_signed;
|
||||
typedef zorder_t is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef unsigned short unsigned_type;
|
||||
typedef unsigned short signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <long>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_t is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef long unsigned int unsigned_type;
|
||||
typedef long int signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <unsigned long>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_f is_signed;
|
||||
typedef zorder_t is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef long unsigned int unsigned_type;
|
||||
typedef long unsigned int signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <float>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_f is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef float unsigned_type;
|
||||
typedef float signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <double>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_f is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef double unsigned_type;
|
||||
typedef double signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <long double>
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_f is_integral;
|
||||
typedef zorder_f is_seperated;
|
||||
typedef long double unsigned_type;
|
||||
typedef long double signed_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <sep_float<float> >
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_f is_integral;
|
||||
typedef zorder_t is_seperated;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <sep_float<double> >
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_f is_integral;
|
||||
typedef zorder_t is_seperated;
|
||||
};
|
||||
|
||||
template<>
|
||||
class zorder_traits <sep_float<long double> >
|
||||
{
|
||||
public:
|
||||
static void check_type(){};
|
||||
typedef zorder_t is_signed;
|
||||
typedef zorder_f is_integral;
|
||||
typedef zorder_t is_seperated;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,530 +0,0 @@
|
|||
// PCL
|
||||
#include <pcl/io/obj_io.h>
|
||||
#include <pcl/common/transforms.h>
|
||||
|
||||
// Modified PCL
|
||||
#include "modifiedPclFunctions.hpp"
|
||||
|
||||
// This
|
||||
#include "Georef.hpp"
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, const GeorefSystem &geo)
|
||||
{
|
||||
return os << geo.system_ << " " << static_cast<int>(geo.falseEasting_) << " " << static_cast<int>(geo.falseNorthing_);
|
||||
}
|
||||
|
||||
GeorefCamera::GeorefCamera()
|
||||
:focalLength_(0.0), k1_(0.0), k2_(0.0), transform_(NULL), position_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
GeorefCamera::GeorefCamera(const GeorefCamera &other)
|
||||
: focalLength_(other.focalLength_), k1_(other.k1_), k2_(other.k2_),
|
||||
easting_(other.easting_), northing_(other.northing_), altitude_(other.altitude_),
|
||||
transform_(NULL), position_(NULL)
|
||||
{
|
||||
if(NULL != other.transform_)
|
||||
{
|
||||
transform_ = new Eigen::Affine3f(*other.transform_);
|
||||
}
|
||||
if(NULL != other.position_)
|
||||
{
|
||||
position_ = new Eigen::Vector3f(*other.position_);
|
||||
}
|
||||
}
|
||||
|
||||
GeorefCamera::~GeorefCamera()
|
||||
{
|
||||
if(NULL != transform_)
|
||||
{
|
||||
delete transform_;
|
||||
transform_ = NULL;
|
||||
}
|
||||
if(NULL != position_)
|
||||
{
|
||||
delete position_;
|
||||
position_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void GeorefCamera::extractCamera(std::ifstream &bundleStream)
|
||||
{
|
||||
// Extract intrinsic parameters.
|
||||
bundleStream >> focalLength_ >> k1_ >> k2_;
|
||||
|
||||
Eigen::Vector3f t;
|
||||
Eigen::Matrix3f rot;
|
||||
Eigen::Affine3f transform;
|
||||
|
||||
bundleStream >> transform(0,0); // Read rotation (0,0) from bundle file
|
||||
bundleStream >> transform(0,1); // Read rotation (0,1) from bundle file
|
||||
bundleStream >> transform(0,2); // Read rotation (0,2) from bundle file
|
||||
|
||||
bundleStream >> transform(1,0); // Read rotation (1,0) from bundle file
|
||||
bundleStream >> transform(1,1); // Read rotation (1,1) from bundle file
|
||||
bundleStream >> transform(1,2); // Read rotation (1,2) from bundle file
|
||||
|
||||
bundleStream >> transform(2,0); // Read rotation (2,0) from bundle file
|
||||
bundleStream >> transform(2,1); // Read rotation (2,1) from bundle file
|
||||
bundleStream >> transform(2,2); // Read rotation (2,2) from bundle file
|
||||
|
||||
bundleStream >> t(0); // Read translation (0,3) from bundle file
|
||||
bundleStream >> t(1); // Read translation (1,3) from bundle file
|
||||
bundleStream >> t(2); // Read translation (2,3) from bundle file
|
||||
|
||||
rot = transform.matrix().topLeftCorner<3,3>();
|
||||
|
||||
// Calculate translation according to -R't and store in vector.
|
||||
t = -rot.transpose()*t;
|
||||
|
||||
transform(0,3) = t(0);
|
||||
transform(1,3) = t(1);
|
||||
transform(2,3) = t(2);
|
||||
|
||||
// Set transform and position.
|
||||
if(NULL != transform_)
|
||||
{
|
||||
delete transform_;
|
||||
transform_ = NULL;
|
||||
}
|
||||
|
||||
transform_ = new Eigen::Affine3f(transform);
|
||||
|
||||
if(NULL != position_)
|
||||
{
|
||||
delete position_;
|
||||
position_ = NULL;
|
||||
}
|
||||
position_ = new Eigen::Vector3f(t);
|
||||
}
|
||||
|
||||
void GeorefCamera::extractCameraGeoref(std::istringstream &coordStream)
|
||||
{
|
||||
coordStream >> easting_ >> northing_ >> altitude_;
|
||||
}
|
||||
|
||||
Vec3 GeorefCamera::getPos()
|
||||
{
|
||||
return Vec3((*position_)(0),(*position_)(1),(*position_)(2));
|
||||
}
|
||||
|
||||
Vec3 GeorefCamera::getReferencedPos()
|
||||
{
|
||||
return Vec3(easting_,northing_,altitude_);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, const GeorefCamera &cam)
|
||||
{
|
||||
os << "Focal, k1, k2 : " << cam.focalLength_ << ", " << cam.k1_ << ", " << cam.k2_ << "\n";
|
||||
if(NULL != cam.transform_)
|
||||
{
|
||||
os << "Transform :\n" << cam.transform_->matrix() << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
os << "Transform :\nNULL\n";
|
||||
}
|
||||
if(NULL != cam.position_)
|
||||
{
|
||||
os << "Position :\n" << cam.position_->matrix() << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
os << "Position :\nNULL\n";
|
||||
}
|
||||
os << "east, north, alt : " << cam.easting_ << ", " << cam.northing_ << ", " << cam.altitude_ << '\n';
|
||||
return os;
|
||||
}
|
||||
|
||||
Georef::Georef()
|
||||
{
|
||||
log_.setIsPrintingInCout(true);
|
||||
|
||||
bundleFilename_ = "";
|
||||
coordFilename_ = "";
|
||||
inputObjFilename_ = "";
|
||||
outputObjFilename_ = "";
|
||||
}
|
||||
|
||||
Georef::~Georef()
|
||||
{
|
||||
}
|
||||
|
||||
int Georef::run(int argc, char *argv[])
|
||||
{
|
||||
try
|
||||
{
|
||||
parseArguments(argc, argv);
|
||||
makeGeoreferencedModel();
|
||||
}
|
||||
catch (const GeorefException& e)
|
||||
{
|
||||
log_ << e.what() << "\n";
|
||||
log_.print(logFile_);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log_ << "Error in Georef:\n";
|
||||
log_ << e.what() << "\n";
|
||||
log_.print(logFile_);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
log_ << "Unknown error, terminating:\n";
|
||||
log_.print(logFile_);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
log_.print(logFile_);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void Georef::parseArguments(int argc, char *argv[])
|
||||
{
|
||||
bool outputSpecified = false;
|
||||
|
||||
logFile_ = std::string(argv[0]) + "_log.txt";
|
||||
log_ << logFile_ << "\n";
|
||||
|
||||
// If no arguments were passed, print help.
|
||||
if (argc == 1)
|
||||
{
|
||||
printHelp();
|
||||
}
|
||||
|
||||
log_ << "Arguments given\n";
|
||||
for(int argIndex = 1; argIndex < argc; ++argIndex)
|
||||
{
|
||||
log_ << argv[argIndex] << '\n';
|
||||
}
|
||||
|
||||
log_ << '\n';
|
||||
for(int argIndex = 1; argIndex < argc; ++argIndex)
|
||||
{
|
||||
// The argument to be parsed.
|
||||
std::string argument = std::string(argv[argIndex]);
|
||||
|
||||
if(argument == "-help")
|
||||
{
|
||||
printHelp();
|
||||
}
|
||||
else if(argument == "-verbose")
|
||||
{
|
||||
log_.setIsPrintingInCout(true);
|
||||
}
|
||||
else if(argument == "-bundleFile" && argIndex < argc)
|
||||
{
|
||||
argIndex++;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
bundleFilename_ = std::string(argv[argIndex]);
|
||||
log_ << "Reading cameras from: " << bundleFilename_ << "\n";
|
||||
}
|
||||
else if(argument == "-coordFile" && argIndex < argc)
|
||||
{
|
||||
argIndex++;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
coordFilename_ = std::string(argv[argIndex]);
|
||||
log_ << "Reading cameras georeferenced positions from: " << coordFilename_ << "\n";
|
||||
}
|
||||
else if(argument == "-inputFile" && argIndex < argc)
|
||||
{
|
||||
argIndex++;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
inputObjFilename_ = std::string(argv[argIndex]);
|
||||
log_ << "Reading textured mesh from: " << inputObjFilename_ << "\n";
|
||||
}
|
||||
else if(argument == "-outputFile" && argIndex < argc)
|
||||
{
|
||||
argIndex++;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
outputObjFilename_ = std::string(argv[argIndex]);
|
||||
log_ << "Writing output to: " << outputObjFilename_ << "\n";
|
||||
outputSpecified = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
printHelp();
|
||||
throw GeorefException("Unrecognised argument '" + argument + "'");
|
||||
}
|
||||
}
|
||||
|
||||
if(!outputSpecified)
|
||||
{
|
||||
makeDefaultOutput();
|
||||
}
|
||||
}
|
||||
|
||||
void Georef::printHelp()
|
||||
{
|
||||
bool printInCoutPop = log_.isPrintingInCout();
|
||||
log_.setIsPrintingInCout(true);
|
||||
|
||||
log_ << "Georef.exe\n\n";
|
||||
|
||||
log_ << "Purpose:" << "\n";
|
||||
log_ << "Create an orthograpical photo from an oriented textured mesh." << "\n";
|
||||
|
||||
log_ << "Usage:" << "\n";
|
||||
log_ << "The program requires a path to a camera bundle file, a camera georeference coords file, and an input OBJ mesh file. All other input parameters are optional." << "\n\n";
|
||||
|
||||
log_ << "The following flags are available\n";
|
||||
log_ << "Call the program with flag \"-help\", or without parameters to print this message, or check any generated log file.\n";
|
||||
log_ << "Call the program with flag \"-verbose\", to print log messages in the standard output stream as well as in the log file.\n\n";
|
||||
|
||||
log_ << "Parameters are specified as: \"-<argument name> <argument>\", (without <>), and the following parameters are configureable: " << "\n";
|
||||
log_ << "\"-bundleFile <path>\" (mandatory)" << "\n";
|
||||
log_ << "\"Input cameras bundle file.\n\n";
|
||||
|
||||
log_ << "\"-coordFile <path>\" (mandatory)" << "\n";
|
||||
log_ << "\"Input cameras geroreferenced coords file.\n\n";
|
||||
|
||||
log_ << "\"-inputFile <path>\" (mandatory)" << "\n";
|
||||
log_ << "\"Input obj file that must contain a textured mesh.\n\n";
|
||||
|
||||
log_ << "\"-outputFile <path>\" (optional, default <inputFile>_geo)" << "\n";
|
||||
log_ << "\"Output obj file that will contain the georeferenced texture mesh.\n\n";
|
||||
|
||||
log_.setIsPrintingInCout(printInCoutPop);
|
||||
}
|
||||
|
||||
void Georef::makeDefaultOutput()
|
||||
{
|
||||
if(inputObjFilename_.empty())
|
||||
{
|
||||
throw GeorefException("Tried to generate default ouptut file without having an input file.");
|
||||
}
|
||||
|
||||
std::string tmp = inputObjFilename_;
|
||||
size_t findPos = tmp.find_last_of(".");
|
||||
|
||||
if(std::string::npos == findPos)
|
||||
{
|
||||
throw GeorefException("Tried to generate default ouptut file, could not find .obj in the input file:\n\'"+inputObjFilename_+"\'");
|
||||
}
|
||||
|
||||
tmp = tmp.substr(0, findPos);
|
||||
|
||||
outputObjFilename_ = tmp + "_geo.obj";
|
||||
log_ << "Writing output to: " << outputObjFilename_ << "\n";
|
||||
}
|
||||
|
||||
void Georef::makeGeoreferencedModel()
|
||||
{
|
||||
// Read translations from bundle file
|
||||
std::ifstream bundleStream(bundleFilename_.c_str());
|
||||
if (!bundleStream.good())
|
||||
{
|
||||
throw GeorefException("Failed opening " + bundleFilename_ + " for reading." + '\n');
|
||||
}
|
||||
|
||||
// Read Cameras.
|
||||
std::string bundleLine;
|
||||
std::getline(bundleStream, bundleLine); // Read past bundle version comment
|
||||
int numCameras, numPoints;
|
||||
bundleStream >> numCameras >> numPoints;
|
||||
for (int i=0; i<numCameras; ++i)
|
||||
{
|
||||
cameras_.push_back(GeorefCamera());
|
||||
cameras_.back().extractCamera(bundleStream);
|
||||
}
|
||||
|
||||
// Read coords from coord file generated by extract_utm tool
|
||||
std::ifstream coordStream(coordFilename_.c_str());
|
||||
if (!coordStream.good())
|
||||
{
|
||||
throw GeorefException("Failed opening " + coordFilename_ + " for reading." + '\n');
|
||||
}
|
||||
|
||||
std::string coordString;
|
||||
std::getline(coordStream, georefSystem_.system_); // System
|
||||
{
|
||||
std::getline(coordStream, coordString); // Flase easting & northing.
|
||||
std::stringstream ss(coordString);
|
||||
|
||||
ss >> georefSystem_.falseEasting_ >> georefSystem_.falseNorthing_;
|
||||
}
|
||||
|
||||
log_ << '\n';
|
||||
log_ << "Geographical reference system\n";
|
||||
log_ << georefSystem_ << '\n';
|
||||
|
||||
// The number of cameras in the coords file.
|
||||
size_t nGeorefCameras = 0;
|
||||
|
||||
// Read the georefernced position for all cameras.
|
||||
while (std::getline(coordStream, coordString))
|
||||
{
|
||||
if(nGeorefCameras >= cameras_.size())
|
||||
{
|
||||
throw GeorefException("Error to many cameras in \'" + coordFilename_ + "\' coord file.\n");
|
||||
}
|
||||
|
||||
std::istringstream istr(coordString);
|
||||
cameras_[nGeorefCameras].extractCameraGeoref(istr);
|
||||
|
||||
++nGeorefCameras;
|
||||
}
|
||||
coordStream.close();
|
||||
|
||||
if(nGeorefCameras < cameras_.size())
|
||||
{
|
||||
throw GeorefException("Not enough cameras in \'" + coordFilename_ + "\' coord file.\n");
|
||||
}
|
||||
|
||||
// The optimal camera triplet.
|
||||
size_t cam0, cam1, cam2;
|
||||
|
||||
log_ << '\n';
|
||||
log_ << "Choosing optimal camera triplet...\n";
|
||||
chooseBestCameraTriplet(cam0, cam1, cam2);
|
||||
log_ << "... optimal camera triplet chosen:\n";
|
||||
log_ << cam0 << ", " << cam1 << ", " << cam2 << '\n';
|
||||
log_ << '\n';
|
||||
FindTransform transFinal;
|
||||
transFinal.findTransform(cameras_[cam0].getPos(), cameras_[cam1].getPos(), cameras_[cam2].getPos(),
|
||||
cameras_[cam0].getReferencedPos(), cameras_[cam1].getReferencedPos(), cameras_[cam2].getReferencedPos());
|
||||
log_ << "Final transform:\n";
|
||||
log_ << transFinal.transform_ << '\n';
|
||||
|
||||
// The tranform used to move the chosen area into the ortho photo.
|
||||
Eigen::Transform<float, 3, Eigen::Affine> transform;
|
||||
|
||||
transform(0, 0) = static_cast<float>(transFinal.transform_.r1c1_);
|
||||
transform(1, 0) = static_cast<float>(transFinal.transform_.r2c1_);
|
||||
transform(2, 0) = static_cast<float>(transFinal.transform_.r3c1_);
|
||||
transform(3, 0) = static_cast<float>(transFinal.transform_.r4c1_);
|
||||
|
||||
transform(0, 1) = static_cast<float>(transFinal.transform_.r1c2_);
|
||||
transform(1, 1) = static_cast<float>(transFinal.transform_.r2c2_);
|
||||
transform(2, 1) = static_cast<float>(transFinal.transform_.r3c2_);
|
||||
transform(3, 1) = static_cast<float>(transFinal.transform_.r4c2_);
|
||||
|
||||
transform(0, 2) = static_cast<float>(transFinal.transform_.r1c3_);
|
||||
transform(1, 2) = static_cast<float>(transFinal.transform_.r2c3_);
|
||||
transform(2, 2) = static_cast<float>(transFinal.transform_.r3c3_);
|
||||
transform(3, 2) = static_cast<float>(transFinal.transform_.r4c3_);
|
||||
|
||||
transform(0, 3) = static_cast<float>(transFinal.transform_.r1c4_);
|
||||
transform(1, 3) = static_cast<float>(transFinal.transform_.r2c4_);
|
||||
transform(2, 3) = static_cast<float>(transFinal.transform_.r3c4_);
|
||||
transform(3, 3) = static_cast<float>(transFinal.transform_.r4c4_);
|
||||
|
||||
log_ << '\n';
|
||||
log_ << "Reading mesh file...\n";
|
||||
// The textureds mesh.e
|
||||
pcl::TextureMesh mesh;
|
||||
pcl::io::loadOBJFile(inputObjFilename_, mesh);
|
||||
log_ << ".. mesh file read.\n";
|
||||
|
||||
// Contains the vertices of the mesh.
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr meshCloud (new pcl::PointCloud<pcl::PointXYZ>);
|
||||
pcl::fromPCLPointCloud2 (mesh.cloud, *meshCloud);
|
||||
|
||||
log_ << '\n';
|
||||
log_ << "Applying transform to mesh...\n";
|
||||
// Move the mesh into position.
|
||||
pcl::transformPointCloud(*meshCloud, *meshCloud, transform);
|
||||
log_ << ".. mesh transformed.\n";
|
||||
|
||||
// Update the mesh.
|
||||
pcl::toPCLPointCloud2 (*meshCloud, mesh.cloud);
|
||||
|
||||
|
||||
// Iterate over each part of the mesh (one per material), to make texture file paths relative the .mtl file.
|
||||
for(size_t t = 0; t < mesh.tex_materials.size(); ++t)
|
||||
{
|
||||
// The material of the current submesh.
|
||||
pcl::TexMaterial& material = mesh.tex_materials[t];
|
||||
|
||||
size_t find = material.tex_file.find_last_of("/\\");
|
||||
if(std::string::npos != find)
|
||||
{
|
||||
material.tex_file = material.tex_file.substr(find + 1);
|
||||
}
|
||||
}
|
||||
|
||||
log_ << '\n';
|
||||
log_ << "Saving mesh file to \'" << outputObjFilename_ << "\'...\n";
|
||||
saveOBJFile(outputObjFilename_, mesh, 8);
|
||||
log_ << ".. mesh file saved.\n";
|
||||
|
||||
printGeorefSystem();
|
||||
}
|
||||
|
||||
void Georef::chooseBestCameraTriplet(size_t &cam0, size_t &cam1, size_t &cam2)
|
||||
{
|
||||
double minTotError = std::numeric_limits<double>::infinity();
|
||||
|
||||
for(size_t t = 0; t < cameras_.size(); ++t)
|
||||
{
|
||||
for(size_t s = t; s < cameras_.size(); ++s)
|
||||
{
|
||||
for(size_t p = s; p < cameras_.size(); ++p)
|
||||
{
|
||||
FindTransform trans;
|
||||
trans.findTransform(cameras_[t].getPos(), cameras_[s].getPos(), cameras_[p].getPos(),
|
||||
cameras_[t].getReferencedPos(), cameras_[s].getReferencedPos(), cameras_[p].getReferencedPos());
|
||||
|
||||
// The total error for the curren camera triplet.
|
||||
double totError = 0.0;
|
||||
|
||||
for(size_t r = 0; r < cameras_.size(); ++r)
|
||||
{
|
||||
totError += trans.error(cameras_[r].getPos(), cameras_[r].getReferencedPos());
|
||||
}
|
||||
|
||||
if(minTotError > totError)
|
||||
{
|
||||
minTotError = totError;
|
||||
cam0 = t;
|
||||
cam1 = s;
|
||||
cam2 = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_ << "Mean georeference error " << minTotError / static_cast<double>(cameras_.size()) << '\n';
|
||||
}
|
||||
|
||||
void Georef::printGeorefSystem()
|
||||
{
|
||||
if(outputObjFilename_.empty())
|
||||
{
|
||||
throw GeorefException("Output file path empty!.");
|
||||
}
|
||||
|
||||
std::string tmp = outputObjFilename_;
|
||||
size_t findPos = tmp.find_last_of(".");
|
||||
|
||||
if(std::string::npos == findPos)
|
||||
{
|
||||
throw GeorefException("Tried to generate default ouptut file, could not find .obj in the output file:\n\'"+outputObjFilename_+"\'");
|
||||
}
|
||||
|
||||
tmp = tmp.substr(0, findPos);
|
||||
|
||||
tmp = tmp + "_georef_system.txt";
|
||||
log_ << '\n';
|
||||
log_ << "Saving georeference system file to \'" << tmp << "\'...\n";
|
||||
std::ofstream geoStream(tmp.c_str());
|
||||
geoStream << georefSystem_ << std::endl;
|
||||
geoStream.close();
|
||||
log_ << "... georeference system saved.\n";
|
||||
}
|
||||
|
|
@ -1,361 +0,0 @@
|
|||
#include "OdmMeshing.hpp"
|
||||
|
||||
|
||||
OdmMeshing::OdmMeshing() : log_(false)
|
||||
{
|
||||
meshCreator_ = pcl::Poisson<pcl::PointNormal>::Ptr(new pcl::Poisson<pcl::PointNormal>());
|
||||
points_ = pcl::PointCloud<pcl::PointNormal>::Ptr(new pcl::PointCloud<pcl::PointNormal>());
|
||||
mesh_ = pcl::PolygonMeshPtr(new pcl::PolygonMesh);
|
||||
decimatedMesh_ = pcl::PolygonMeshPtr(new pcl::PolygonMesh);
|
||||
|
||||
// Set default values
|
||||
outputFile_ = "";
|
||||
logFilePath_ = "";
|
||||
|
||||
maxVertexCount_ = 0;
|
||||
treeDepth_ = 0;
|
||||
|
||||
solverDivide_ = 9.0;
|
||||
samplesPerNode_ = 1.0;
|
||||
decimationFactor_ = 0.0;
|
||||
|
||||
logFilePath_ = "odm_meshing_log.txt";
|
||||
log_ << logFilePath_ << "\n";
|
||||
}
|
||||
|
||||
OdmMeshing::~OdmMeshing()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int OdmMeshing::run(int argc, char **argv)
|
||||
{
|
||||
// If no arguments were passed, print help and return early.
|
||||
if (argc <= 1)
|
||||
{
|
||||
printHelp();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseArguments(argc, argv);
|
||||
|
||||
loadPoints();
|
||||
|
||||
createMesh();
|
||||
|
||||
decimateMesh();
|
||||
|
||||
writePlyFile();
|
||||
|
||||
}
|
||||
catch (const OdmMeshingException& e)
|
||||
{
|
||||
log_.setIsPrintingInCout(true);
|
||||
log_ << e.what() << "\n";
|
||||
log_.printToFile(logFilePath_);
|
||||
log_ << "For more detailed information, see log file." << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log_.setIsPrintingInCout(true);
|
||||
log_ << "Error in OdmMeshing:\n";
|
||||
log_ << e.what() << "\n";
|
||||
log_.printToFile(logFilePath_);
|
||||
log_ << "For more detailed information, see log file." << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
log_.setIsPrintingInCout(true);
|
||||
log_ << "Unknwon error in OdmMeshing:\n";
|
||||
log_.printToFile(logFilePath_);
|
||||
log_ << "For more detailed information, see log file." << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
log_.printToFile(logFilePath_);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void OdmMeshing::parseArguments(int argc, char **argv)
|
||||
{
|
||||
|
||||
for(int argIndex = 1; argIndex < argc; ++argIndex)
|
||||
{
|
||||
// The argument to be parsed.
|
||||
std::string argument = std::string(argv[argIndex]);
|
||||
|
||||
if(argument == "-help")
|
||||
{
|
||||
printHelp();
|
||||
}
|
||||
else if(argument == "-verbose")
|
||||
{
|
||||
log_.setIsPrintingInCout(true);
|
||||
}
|
||||
else if(argument == "-maxVertexCount" && argIndex < argc)
|
||||
{
|
||||
++argIndex;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
std::stringstream ss(argv[argIndex]);
|
||||
ss >> maxVertexCount_;
|
||||
if (ss.bad())
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
|
||||
}
|
||||
log_ << "Vertex count was manually set to: " << maxVertexCount_ << "\n";
|
||||
}
|
||||
else if(argument == "-octreeDepth" && argIndex < argc)
|
||||
{
|
||||
++argIndex;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
std::stringstream ss(argv[argIndex]);
|
||||
ss >> treeDepth_;
|
||||
if (ss.bad())
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
|
||||
}
|
||||
log_ << "Octree depth was manually set to: " << treeDepth_ << "\n";
|
||||
}
|
||||
else if(argument == "-solverDivide" && argIndex < argc)
|
||||
{
|
||||
++argIndex;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
std::stringstream ss(argv[argIndex]);
|
||||
ss >> solverDivide_;
|
||||
if (ss.bad())
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
|
||||
}
|
||||
log_ << "Numerical solver divisions was manually set to: " << treeDepth_ << "\n";
|
||||
}
|
||||
else if(argument == "-samplesPerNode" && argIndex < argc)
|
||||
{
|
||||
++argIndex;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
std::stringstream ss(argv[argIndex]);
|
||||
ss >> samplesPerNode_;
|
||||
if (ss.bad())
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
|
||||
}
|
||||
log_ << "The number of samples per octree node was manually set to: " << samplesPerNode_ << "\n";
|
||||
}
|
||||
else if(argument == "-inputFile" && argIndex < argc)
|
||||
{
|
||||
++argIndex;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
inputFile_ = std::string(argv[argIndex]);
|
||||
std::ifstream testFile(inputFile_.c_str(), std::ios::binary);
|
||||
if (!testFile.is_open())
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' has a bad value. (file not accessible)");
|
||||
}
|
||||
testFile.close();
|
||||
log_ << "Reading point cloud at: " << inputFile_ << "\n";
|
||||
}
|
||||
else if(argument == "-outputFile" && argIndex < argc)
|
||||
{
|
||||
++argIndex;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
outputFile_ = std::string(argv[argIndex]);
|
||||
std::ofstream testFile(outputFile_.c_str());
|
||||
if (!testFile.is_open())
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' has a bad value.");
|
||||
}
|
||||
testFile.close();
|
||||
log_ << "Writing output to: " << outputFile_ << "\n";
|
||||
}
|
||||
else if(argument == "-logFile" && argIndex < argc)
|
||||
{
|
||||
++argIndex;
|
||||
if (argIndex >= argc)
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
}
|
||||
logFilePath_ = std::string(argv[argIndex]);
|
||||
std::ofstream testFile(outputFile_.c_str());
|
||||
if (!testFile.is_open())
|
||||
{
|
||||
throw OdmMeshingException("Argument '" + argument + "' has a bad value.");
|
||||
}
|
||||
testFile.close();
|
||||
log_ << "Writing log information to: " << logFilePath_ << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
printHelp();
|
||||
throw OdmMeshingException("Unrecognised argument '" + argument + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OdmMeshing::loadPoints()
|
||||
{
|
||||
|
||||
if(pcl::io::loadPLYFile<pcl::PointNormal> (inputFile_.c_str(), *points_.get()) == -1) {
|
||||
throw OdmMeshingException("Error when reading points and normals from:\n" + inputFile_ + "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
log_ << "Successfully loaded " << points_->size() << " points with corresponding normals from file.\n";
|
||||
}
|
||||
}
|
||||
|
||||
void OdmMeshing::printHelp()
|
||||
{
|
||||
bool printInCoutPop = log_.isPrintingInCout();
|
||||
log_.setIsPrintingInCout(true);
|
||||
|
||||
log_ << "OpenDroneMapMeshing.exe\n\n";
|
||||
|
||||
log_ << "Purpose:" << "\n";
|
||||
log_ << "Create a mesh from an oriented point cloud (points with normals) using the Poisson surface reconstruction method." << "\n";
|
||||
|
||||
log_ << "Usage:" << "\n";
|
||||
log_ << "The program requires a path to an input PLY point cloud file, all other input parameters are optional." << "\n\n";
|
||||
|
||||
log_ << "The following flags are available\n";
|
||||
log_ << "Call the program with flag \"-help\", or without parameters to print this message, or check any generated log file.\n";
|
||||
log_ << "Call the program with flag \"-verbose\", to print log messages in the standard output stream as well as in the log file.\n\n";
|
||||
|
||||
log_ << "Parameters are specified as: \"-<argument name> <argument>\", (without <>), and the following parameters are configureable: " << "\n";
|
||||
log_ << "\"-inputFile <path>\" (mandatory)" << "\n";
|
||||
log_ << "\"Input ascii ply file that must contain a point cloud with normals.\n\n";
|
||||
|
||||
log_ << "\"-outputFile <path>\" (optional, default: odm_mesh.ply)" << "\n";
|
||||
log_ << "\"Target file in which the mesh is saved.\n\n";
|
||||
|
||||
log_ << "\"-logFile <path>\" (optional, default: odm_meshing_log.txt)" << "\n";
|
||||
log_ << "\"Target file in which the mesh is saved.\n\n";
|
||||
|
||||
log_ << "\"-maxVertexCount <integer>\" (optional, default: 100,000)" << "\n";
|
||||
log_ << "Desired final vertex count (after decimation), set to 0 to disable decimation.\n\n";
|
||||
|
||||
log_ << "\"-treeDepth <integer>\" (optional, default: 0 (automatic))" << "\n";
|
||||
log_ << "Controls octree depth used for poisson reconstruction. Recommended values (9-11).\n"
|
||||
<< "Increasing the value on this parameter will raise initial vertex count."
|
||||
<< "If omitted or zero, the depth is calculated automatically from the input point count.\n\n";
|
||||
|
||||
log_ << "\"-samplesPerNode <float>\" (optional, default: 1)" << "\n";
|
||||
log_ << "Average number of samples (points) per octree node. Increasing this value might help if data is very noisy.\n\n";
|
||||
|
||||
log_ << "\"-solverDivide <integer>\" (optional, default: 9)" << "\n";
|
||||
log_ << "Ocree depth at which the Laplacian equation is solved in the surface reconstruction step.\n";
|
||||
log_ << "Increasing this value increases computation times slightly but helps reduce memory usage.\n\n";
|
||||
|
||||
log_.setIsPrintingInCout(printInCoutPop);
|
||||
}
|
||||
|
||||
void OdmMeshing::createMesh()
|
||||
{
|
||||
|
||||
// Attempt to calculate the depth of the tree if unspecified
|
||||
if (treeDepth_ == 0)
|
||||
{
|
||||
treeDepth_ = calcTreeDepth(points_->size());
|
||||
}
|
||||
|
||||
log_ << "Octree depth used for reconstruction is: " << treeDepth_ << "\n";
|
||||
log_ << "Estimated initial vertex count: " << pow(4, treeDepth_) << "\n\n";
|
||||
|
||||
meshCreator_->setDepth(treeDepth_);
|
||||
meshCreator_->setSamplesPerNode(samplesPerNode_);
|
||||
meshCreator_->setInputCloud(points_);
|
||||
|
||||
// Guarantee manifold mesh.
|
||||
meshCreator_->setManifold(true);
|
||||
|
||||
// Begin reconstruction
|
||||
meshCreator_->reconstruct(*mesh_.get());
|
||||
|
||||
log_ << "Reconstruction complete:\n";
|
||||
log_ << "Vertex count: " << mesh_->cloud.width << "\n";
|
||||
log_ << "Triangle count: " << mesh_->polygons.size() << "\n\n";
|
||||
|
||||
}
|
||||
|
||||
void OdmMeshing::decimateMesh()
|
||||
{
|
||||
if (maxVertexCount_ <= 0)
|
||||
{
|
||||
log_ << "Vertex count not specified, decimation cancelled.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (maxVertexCount_ > mesh_->cloud.height*mesh_->cloud.width)
|
||||
{
|
||||
log_ << "Vertex count in mesh lower than initially generated mesh, unable to decimate.\n";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
decimatedMesh_ = pcl::PolygonMeshPtr(new pcl::PolygonMesh);
|
||||
|
||||
double reductionFactor = 1.0 - double(maxVertexCount_)/double(mesh_->cloud.height*mesh_->cloud.width);
|
||||
|
||||
log_ << "Decimating mesh, removing " << reductionFactor*100 << " percent of vertices.\n";
|
||||
|
||||
pcl::MeshQuadricDecimationVTK decimator;
|
||||
decimator.setInputMesh(mesh_);
|
||||
decimator.setTargetReductionFactor(reductionFactor);
|
||||
decimator.process(*decimatedMesh_.get());
|
||||
|
||||
log_ << "Decimation complete.\n";
|
||||
log_ << "Decimated vertex count: " << decimatedMesh_->cloud.width << "\n";
|
||||
log_ << "Decimated triangle count: " << decimatedMesh_->polygons.size() << "\n\n";
|
||||
|
||||
mesh_ = decimatedMesh_;
|
||||
}
|
||||
}
|
||||
|
||||
int OdmMeshing::calcTreeDepth(size_t nPoints)
|
||||
{
|
||||
// Assume points are located (roughly) in a plane.
|
||||
double squareSide = std::sqrt(double(nPoints));
|
||||
|
||||
// Calculate octree depth such that if points were equally distributed in
|
||||
// a quadratic plane, there would be at least 1 point per octree node.
|
||||
int depth = 0;
|
||||
while(std::pow<double>(2,depth) < squareSide/2)
|
||||
{
|
||||
depth++;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
void OdmMeshing::writePlyFile()
|
||||
{
|
||||
log_ << "Saving mesh to file.\n";
|
||||
if (pcl::io::savePLYFile(outputFile_.c_str(), *mesh_.get()) == -1) {
|
||||
throw OdmMeshingException("Error when saving mesh to file:\n" + outputFile_ + "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
log_ << "Successfully wrote mesh to:\n"
|
||||
<< outputFile_ << "\n";
|
||||
}
|
||||
}
|
Plik diff jest za duży
Load Diff
Ładowanie…
Reference in New Issue