Spaces:
Running
on
Zero
Running
on
Zero
/* | |
* Copyright (C) 2020, Inria | |
* GRAPHDECO research group, https://team.inria.fr/graphdeco | |
* All rights reserved. | |
* | |
* This software is free for non-commercial, research and evaluation use | |
* under the terms of the LICENSE.md file. | |
* | |
* For inquiries contact [email protected] and/or [email protected] | |
*/ | |
/// \todo TODO: make shorter | |
namespace sibr { | |
ULRV2View::~ULRV2View( ) | |
{ | |
_altMesh.reset(); | |
} | |
ULRV2View::ULRV2View( const sibr::BasicIBRScene::Ptr& ibrScene, uint render_w, uint render_h ) : | |
_scene(ibrScene), | |
sibr::ViewBase(render_w, render_h), | |
_renderMode(ULRV2View::RenderMode::NORMAL), _singleCamId(0) | |
{ | |
_altMesh.reset(); | |
_altMesh = nullptr; | |
_numDistUlr = 4, _numAnglUlr = 0; | |
std::cerr << "[ULR] setting number of images to blend "<< _numDistUlr << " " << _numAnglUlr << std::endl; | |
_ulr.reset(new ULRV2Renderer(ibrScene->cameras()->inputCameras(), render_w, render_h, _numDistUlr + _numAnglUlr)); | |
uint w = render_w; | |
uint h = render_h; | |
_poissonRT.reset(new RenderTargetRGBA(w, h, SIBR_CLAMP_UVS)); | |
_blendRT.reset(new RenderTargetRGBA(w, h, SIBR_CLAMP_UVS)); | |
_poisson.reset(new PoissonRenderer(w,h)); | |
_poisson->enableFix() = true; | |
_inputRTs = ibrScene->renderTargets()->inputImagesRT(); | |
testAltlULRShader = false; | |
} | |
void ULRV2View::onRenderIBR( sibr::IRenderTarget& dst, const sibr::Camera& eye ) { | |
// Select subset of input images for ULR | |
//std::vector<uint> imgs_ulr = chosen_cameras(eye); | |
std::vector<uint> imgs_ulr = chosen_cameras_angdist(eye); | |
_scene->cameras()->debugFlagCameraAsUsed(imgs_ulr); | |
//std::cout << imgs_ulr.size() << " " << std::flush; | |
if (_renderMode == RenderMode::ONLY_ONE_CAM) { | |
for (auto i : imgs_ulr) { | |
//std::cout << i << " "; | |
} | |
int id_cam = std::max(0, std::min((int)imgs_ulr.size()-1, _singleCamId)); | |
int cam = imgs_ulr[id_cam]; | |
imgs_ulr = std::vector<uint>(1, cam); | |
//std::cout << " -> ulr debug single cam, id : " << _singleCamId << ", cam : "; | |
//for (auto i : imgs_ulr) { | |
//std::cout << i << " "; | |
//} | |
//std::cout << std::endl; | |
} else if(_renderMode == RenderMode::LEAVE_ONE_OUT) { | |
std::vector<uint> new_imgs_ulr; | |
for(const auto & i : imgs_ulr) { | |
if(int(i) != _singleCamId) { | |
new_imgs_ulr.emplace_back(i); | |
} | |
} | |
imgs_ulr = new_imgs_ulr; | |
} | |
if (_noPoissonBlend) { | |
_ulr->process( | |
imgs_ulr, | |
eye, | |
_scene, | |
_altMesh, | |
_inputRTs, | |
dst); | |
} else { | |
_ulr->process( | |
/* input -- images chosen */ imgs_ulr, | |
/* input -- camera position */ eye, | |
/* input -- scene */ _scene, | |
/* input -- alt mesh if available */ _altMesh, | |
/* input -- input RTs -- can be RGB or alpha */ _inputRTs, | |
/* output */ *_blendRT); | |
_poisson->process( | |
_blendRT, | |
_poissonRT); | |
blit(*_poissonRT, dst); | |
} | |
} | |
void ULRV2View::onUpdate(Input & input) | |
{ | |
if (input.key().isReleased(sibr::Key::Tab)) { | |
testAltlULRShader = !testAltlULRShader; | |
if (testAltlULRShader) { | |
_ulr->setupULRshader("ulr_v2_alt"); | |
} else { | |
_ulr->setupULRshader(); | |
} | |
std::cout << "ULR using " << (testAltlULRShader ? "all cams" : "standard ulr") << std::endl; | |
} | |
} | |
void ULRV2View::onGUI() { | |
const std::string guiName = "ULRV2 Settings (" + name() + ")"; | |
if(ImGui::Begin(guiName.c_str())) { | |
ImGui::PushScaledItemWidth(80); | |
const bool v1_changed = ImGui::InputInt("#Dist", &_numDistUlr, 1, 10); | |
ImGui::SameLine(); | |
const bool v2_changed = ImGui::InputInt("#Angle", &_numAnglUlr, 1, 10); | |
ImGui::PopItemWidth(); | |
if (v1_changed || v2_changed) { | |
setNumBlend(_numDistUlr, _numAnglUlr); | |
} | |
ImGui::Checkbox("Disable Poisson", &_noPoissonBlend); | |
ImGui::Checkbox("Poisson fix", &_poisson->enableFix()); | |
ImGui::PushScaledItemWidth(120); | |
ImGui::InputFloat("Epsilon occlusion", &_ulr->epsilonOcclusion(), 0.001f, 0.01f); | |
ImGui::Combo("Rendering mode", (int*)(&_renderMode), "Standard\0One image\0Leave one out\0\0"); | |
if (ImGui::InputInt("Selected image", &_singleCamId, 1, 10)) { | |
_renderMode = RenderMode::ONLY_ONE_CAM; | |
} | |
_singleCamId = sibr::clamp(_singleCamId, 0, (int)_scene->cameras()->inputCameras().size() - 1); | |
//ImGui::SliderInt("Selected image", &_singleCamId, 0, scene().inputCameras().size() - 1); | |
ImGui::PopItemWidth(); | |
} | |
ImGui::End(); | |
} | |
void ULRV2View::computeVisibilityMap(const sibr::ImageL32F & depthMap, sibr::ImageRGBA & out) | |
{ | |
const float threshold_3d = 2.5f; | |
const std::vector<sibr::Vector2i> shifts = { { 1,0 },{ 0,1 },{ -1,0 },{ 0,-1 } }; | |
sibr::ImageL8 edgeMap(depthMap.w(), depthMap.h(), 255); | |
for (uint i = 0; i < depthMap.h(); i++) { | |
for (uint j = 0; j < depthMap.w(); j++) { | |
sibr::Vector2i pos(j, i); | |
float currentDepth = depthMap(pos).x(); | |
for (const auto & shift : shifts) { | |
Vector2i npos = pos + shift; | |
if (!depthMap.isInRange(npos)) { continue; } | |
if (std::abs(depthMap(npos).x() - currentDepth) > threshold_3d) { | |
edgeMap(pos).x() = 0; | |
break; | |
} | |
} | |
} | |
} | |
cv::Mat distance(depthMap.h(), depthMap.w(), CV_32FC1); | |
cv::distanceTransform(edgeMap.toOpenCVnonConst(), distance, cv::DIST_L2, cv::DIST_MASK_PRECISE); | |
sibr::ImageL32F outF; | |
outF.fromOpenCV(distance); | |
out = sibr::convertL32FtoRGBA(outF); | |
} | |
// ----------------------------------------------------------------------- | |
std::vector<uint> ULRV2View::chosen_cameras(const sibr::Camera& eye) { | |
std::vector<uint> imgs_id; | |
std::multimap<float,uint> distMap; // distance wise closest input cameras | |
std::multimap<float,uint> dang; // angular distance from inputs to novel camera | |
for (uint i=0; i< _scene->cameras()->inputCameras().size(); i++ ) { | |
const sibr::InputCamera& inputCam = *_scene->cameras()->inputCameras()[i]; | |
if (inputCam.isActive()) { | |
// Convert following to Eigen versions | |
float dist = sibr::distance(inputCam.position(), eye.position()); | |
float angle = sibr::dot(inputCam.dir(),eye.dir()); | |
distMap.insert(std::make_pair(dist,i)); // sort distances in increasing order | |
dang.insert(std::make_pair( acos(angle),i)); // sort angles in increasing order | |
} | |
} | |
for (uint i=0; i< _scene->cameras()->inputCameras().size(); i++) { | |
const sibr::InputCamera& inputCam = *_scene->cameras()->inputCameras()[i]; | |
if (inputCam.isActive() && distMap.size() <= (_numDistUlr+_numAnglUlr)/2 ) { | |
float dist = sibr::distance(inputCam.position(),eye.position()); | |
distMap.insert(std::make_pair(dist,i)); // sort distances in increasing order | |
} | |
} | |
std::multimap<float,uint>::const_iterator d_it(distMap.begin()); // select the _numDistUlr closest cameras | |
for (int i=0; d_it!=distMap.end() && i<_numDistUlr; d_it++,i++) { | |
imgs_id.push_back(d_it->second); | |
} | |
std::multimap<float,uint>::const_iterator a_it(dang.begin()); // select the NUM_ANG_ULR closest cameras | |
for (int i=0; a_it!=dang.end() && i<_numAnglUlr; a_it++,i++) { | |
imgs_id.push_back(a_it->second); | |
} | |
std::sort( imgs_id.begin(), imgs_id.end() ); // Avoid repetitions | |
imgs_id.erase( std::unique( imgs_id.begin(), imgs_id.end() ), imgs_id.end() ); | |
SIBR_ASSERT(imgs_id.size() <= _numDistUlr + _numAnglUlr); | |
return imgs_id; | |
} | |
std::vector<uint> ULRV2View::chosen_cameras_angdist(const sibr::Camera & eye) | |
{ | |
const auto & cams = _scene->cameras()->inputCameras(); | |
std::vector<uint> out; | |
// sort angle / dist combined | |
struct camAng | |
{ | |
camAng() {} | |
camAng(float a, float d, int i) : ang(a), dist(d), id(i) {} | |
float ang, dist; | |
int id; | |
static bool compare(const camAng & a, const camAng & b) { return a.ang / a.dist > b.ang / b.dist; } | |
}; | |
int total_size = _numAnglUlr + _numDistUlr; | |
std::vector<camAng> allAng; | |
for (int id = 0; id < (int)cams.size(); ++id) { | |
const auto & cam = *cams[id]; | |
float angle = sibr::dot(cam.dir(),eye.dir()); | |
// reject back facing | |
if( angle > 0.001 && cam.isActive()) { | |
float dist = (cam.position() - eye.position()).norm(); | |
allAng.push_back(camAng(angle, dist, id)); | |
} | |
} | |
std::vector<bool> wasChosen(cams.size(), false); | |
std::sort(allAng.begin(), allAng.end(), camAng::compare); | |
for (int id = 0; id < std::min((int)allAng.size(), total_size); ++id) { | |
out.push_back(allAng[id].id); | |
wasChosen[allAng[id].id] = true; | |
} | |
for (int id = 0; id < (int)cams.size(); ++id) { | |
if (!wasChosen[id] && out.size() < total_size && cams[id]->isActive()) { | |
out.push_back(id); | |
} | |
} | |
return out; | |
} | |
std::vector<uint> ULRV2View::chosen_camerasNew(const sibr::Camera & eye) | |
{ | |
const auto & cams = _scene->cameras()->inputCameras(); | |
struct camDist | |
{ | |
camDist() {} | |
camDist(float d, int i) : dist(d), id(i) {} | |
float dist; | |
int id; | |
static bool compare(const camDist & a, const camDist & b) { return a.dist < b.dist; } | |
}; | |
std::vector<camDist> allDist; | |
for (int id = 0; id < (int)cams.size(); ++id) { | |
const auto & cam = *cams[id]; | |
allDist.push_back(camDist((cam.position() - eye.position()).norm(), id)); | |
} | |
std::sort(allDist.begin(), allDist.end(), camDist::compare); | |
std::vector<uint> out; | |
for (int id = 0; id < std::min((int)cams.size(),(int)_numDistUlr); ++id) { | |
out.push_back(allDist[id].id); | |
} | |
return out; | |
} | |
void ULRV2View::setNumBlend(short int dist, short int angle) | |
{ | |
// Backup masks. | |
auto copyMasks = _ulr->getMasks(); | |
_numDistUlr = dist, _numAnglUlr = angle; | |
std::cerr << "[ULR] setting number of images to blend " << _numDistUlr << " " << _numAnglUlr << std::endl; | |
_ulr.reset(new ULRV2Renderer(_scene->cameras()->inputCameras(), _scene->cameras()->inputCameras()[0]->w(), _scene->cameras()->inputCameras()[0]->h(), _numDistUlr + _numAnglUlr)); | |
_ulr->setMasks(copyMasks); | |
} | |
void ULRV2View::loadMasks(const sibr::BasicIBRScene::Ptr& ibrScene, int w, int h, const std::string& maskDir, const std::string& preFileName, const std::string& postFileName | |
) { | |
std::string finalMaskDir = (maskDir == "" ? ibrScene->data()->basePathName() + "/masks/" : maskDir); | |
std::string finalPostFileName = (postFileName == "" ? "-mask.jpg" : postFileName); | |
_ulr->loadMasks(ibrScene, finalMaskDir, preFileName, finalPostFileName, w, h); | |
} | |
void ULRV2View::setMasks( const std::vector<RenderTargetLum::Ptr>& masks ) { | |
_ulr->setMasks(masks); | |
} | |
} /*namespace sibr*/ | |