Skip to content

Commit 000e983

Browse files
committed
bni normal integration optimized for 0 discontinuity, few small bug fixed.
1 parent 61a2db9 commit 000e983

10 files changed

+117
-85
lines changed

relight-cli/rtibuilder.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,8 @@ size_t RtiBuilder::savePTM(const std::string &output) {
10681068
//second reading.
10691069
imageset.restart();
10701070

1071+
nworkers = QThread::idealThreadCount();
1072+
10711073
vector<Worker *> workers(height, nullptr);
10721074
for(size_t i = 0; i < nworkers; i++) {
10731075
workers[i] = new Worker(*this);

relightlab/CMakeLists.txt

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ set(CMAKE_AUTOUIC ON)
1515
set(CMAKE_AUTORCC ON)
1616

1717
set(OPENCV_RELIGHT_LIBS opencv_core opencv_imgcodecs opencv_imgproc opencv_video)
18-
18+
add_compile_definitions(WITH_OPENCV)
19+
1920
if (APPLE)
2021
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum OS X deployment version" FORCE)
2122
SET(CMAKE_INSTALL_RPATH $ORIGIN/../Frameworks)
2223
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
2324
#else()
24-
# add_compile_definitions(WITH_OPENCV)
25+
#
2526
endif()
2627

2728

relightlab/main.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1+
2+
#include "relightapp.h"
3+
#include "mainwindow.h"
4+
15
#include <QApplication>
26

37
#include <QVBoxLayout>
48
#include <QPushButton>
59
#include <QLabel>
610
#include <QImageReader>
711

8-
#include "relightapp.h"
9-
#include "mainwindow.h"
10-
11-
#include <locale.h>
12-
1312
#include <iostream>
13+
#include <locale.h>
1414
using namespace std;
1515

1616
#define RELIGHT_STRINGIFY0(v) #v

relightlab/normalsplan.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ NormalsSurfaceRow::NormalsSurfaceRow(NormalsParameters &_parameters, QFrame *par
164164
QHBoxLayout *bni_parameter = new QHBoxLayout;
165165
bni_parameter->addWidget(new QLabel("Discontinuity propensity."));
166166
bni_parameter->addWidget(bni_k = new QDoubleSpinBox);
167-
bni_k->setRange(0.01, 50);
167+
bni_k->setRange(0.00, 50);
168168
bni_k->setValue(parameters.bni_k);
169169

170170
bni_layout->addLayout(bni_parameter);

relightlab/processqueue.h

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ class ProcessQueue: public QThread {
1919
Q_OBJECT
2020
public:
2121
~ProcessQueue();
22-
int nthreads = 4;
2322

2423
Task *task = nullptr; //task is removed from the queue when executing.
2524
bool stopped = false;

relightlab/relightlab.pro

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ CONFIG += c++17
66
#target_link_libraries( ${APP_NAME} Qt5::Svg )
77

88
DEFINES += QT_DEPRECATED_WARNINGS
9-
DEFINES += _USE_MATH_DEFINES #WITH_OPENCV
9+
DEFINES += _USE_MATH_DEFINES WITH_OPENCV
1010
DEFINES += NOMINMAX
1111

1212
INCLUDEPATH += ../external/
@@ -16,17 +16,17 @@ win32:INCLUDEPATH += ../external/libjpeg-turbo-2.0.6/include \
1616
../src/
1717
win32:LIBS += ../external/libjpeg-turbo-2.0.6/lib/jpeg-static.lib
1818

19+
unix::QMAKE_CXXFLAGS = -fopenmp
1920
unix:INCLUDEPATH += ../external/eigen-3.3.9/ /usr/include/opencv4
20-
unix:LIBS += -ljpeg -ltiff -lgomp
21-
#unix:LIBS += -lopencv_core -lopencv_imgcodecs -lopencv_imgproc -lopencv_video
22-
21+
unix:LIBS += -ljpeg -ltiff
22+
unix:LIBS += -lopencv_core -lopencv_imgcodecs -lopencv_imgproc -lopencv_video
23+
unix::LIBS += -fopenmp #-lgomp
2324

2425
mac:INCLUDEPATH += /usr/local/Cellar/jpeg-turbo/3.1.0/include \
2526
/usr/local/include \
2627
/usr/local/include/eigen3
2728
mac:LIBS += -L/usr/local/Cellar/jpeg-turbo/3.1.0/lib/ -ljpeg
2829
mac:LIBS += -framework Accelerate
29-
#mac:QMAKE_CXXFLAGS += -fopenmp
3030
mac:QMAKE_CXXFLAGS += -Xpreprocessor -I/usr/local/include #fopenmp -lomp
3131
# mac:QMAKE_LFLAGS += -lomp
3232
mac:LIBS += -L /usr/local/lib /usr/local/lib/libomp.dylib

src/bni_normal_integration.cpp

+91-68
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,92 @@ std::vector<float> bni_pyramid(std::function<bool(QString s, int n)> progressed,
283283
h = result.h;
284284
return result.heights;
285285
}
286+
#include <Eigen/SparseCholesky>
287+
288+
289+
Eigen::VectorXd bni_integrate_iterative(std::function<bool(QString s, int n)> progressed, Eigen::SparseMatrix<double> &A, Eigen::VectorXd &b, Eigen::SparseMatrix<double> W,
290+
double k,
291+
double tolerance, double solver_tolerance,
292+
int max_iterations, int max_solver_iterations) {
293+
294+
int n = b.size()/4;
295+
296+
Eigen::VectorXd z = Eigen::VectorXd::Zero(n);
297+
298+
Eigen::MatrixXd tmp = A*z - b;
299+
double energy = (tmp.transpose() * W * tmp)(0);
300+
double start_energy = energy;
301+
if(isnan(energy)) {
302+
throw "Computational problems.";
303+
}
304+
305+
cout << "Energy : " << energy << endl;
306+
307+
vector<Triple> triples;
308+
for(int i = 0; i < max_iterations; i++) {
309+
310+
Eigen::SparseMatrix<double> A_mat = A.transpose()*W*A;
311+
Eigen::VectorXd b_vec = A.transpose()*W*b;
312+
313+
Eigen::ConjugateGradient<Eigen::SparseMatrix<double>> solver;
314+
315+
solver.compute(A_mat);
316+
solver.setTolerance(solver_tolerance);
317+
solver.setMaxIterations(max_solver_iterations);
318+
z = solver.solveWithGuess(b_vec, z);
319+
if (solver.info() != Eigen::Success) {
320+
double finalResidual = solver.error();
321+
cerr << "Max iter reached with error: " << finalResidual << endl;
322+
}
323+
324+
// Get the number of iterations
325+
int numIterations = solver.iterations();
326+
std::cout << "Number of iterations: " << numIterations << " error: " << solver.error() << " tolerance: " << solver_tolerance << std::endl;
327+
328+
329+
if(k == 0)
330+
break;
331+
332+
Eigen::VectorXd wu = ((A.block(n, 0, n, n)*z).array().pow(2) -
333+
(A.block(0, 0, n, n)*z).array().pow(2)).unaryExpr([k](double x) { return sigmoid(x, k); });
334+
Eigen::VectorXd wv = ((A.block(n*3, 0, n, n)*z).array().pow(2) -
335+
(A.block(n*2, 0, n, n)*z).array().pow(2)).unaryExpr([k](double x) { return sigmoid(x, k); });
336+
337+
triples.clear();
338+
for(int i = 0; i < n; i++) {
339+
triples.push_back(Triple(i, i, wu(i)));
340+
triples.push_back(Triple(i+n, i+n, 1.0 - wu(i)));
341+
triples.push_back(Triple(i+n*2, i+n*2, wv(i)));
342+
triples.push_back(Triple(i+n*3, i+n*3, 1 - wv(i)));
343+
}
344+
W.setFromTriplets(triples.begin(), triples.end());
345+
346+
double energy_old = energy;
347+
tmp = A*z - b;
348+
energy = (tmp.transpose() * W * tmp)(0);
349+
cout << "Energy: " << energy << endl;
350+
351+
double relative_energy = fabs(energy - energy_old) / energy_old;
352+
double total_progress = fabs(energy - start_energy) / start_energy;
353+
if(progressed) {
354+
bool proceed = progressed("Integrating normals...", 100*(1 - (log(relative_energy) - log(tolerance))/(log(total_progress) - log(tolerance))));
355+
if(!proceed) break;
356+
}
357+
if(relative_energy < tolerance)
358+
break;
359+
}
360+
return z;
361+
}
362+
363+
Eigen::VectorXd bni_integrate_direct(Eigen::SparseMatrix<double> &A, Eigen::VectorXd &b, Eigen::SparseMatrix<double> &W) {
364+
Eigen::SparseMatrix<double> A_mat = A.transpose()*W*A;
365+
Eigen::VectorXd b_vec = A.transpose()*W*b;
366+
367+
Eigen::SimplicialLDLT<Eigen::SparseMatrix<double> > solver;
368+
solver.compute(A_mat);
369+
return solver.solve(b_vec);
370+
}
371+
286372

287373
void bni_integrate(std::function<bool(QString s, int n)> progressed, int w, int h, std::vector<float> &normalmap, std::vector<float> &heights,
288374
double k,
@@ -361,77 +447,14 @@ void bni_integrate(std::function<bool(QString s, int n)> progressed, int w, int
361447
triples.push_back(Triple(i, i, 0.5));
362448
W.setFromTriplets(triples.begin(), triples.end());
363449

364-
Eigen::VectorXd z = Eigen::VectorXd::Zero(n);
365-
//for(int i = 0; i < n; i++)
366-
// z(i) = heights[i];
367-
368-
Eigen::MatrixXd tmp = A*z - b;
369-
double energy = (tmp.transpose() * W * tmp)(0);
370-
double start_energy = energy;
371-
if(isnan(energy)) {
372-
throw "Accidentaccio!";
373-
}
374-
375-
cout << "Energy : " << energy << endl;
376-
377-
for(int i = 0; i < max_iterations; i++) {
378-
379-
Eigen::SparseMatrix<double> A_mat = A.transpose()*W*A;
380-
Eigen::VectorXd b_vec = A.transpose()*W*b;
381-
382-
Eigen::ConjugateGradient<Eigen::SparseMatrix<double>> solver;
383-
384-
//Eigen::LeastSquaresConjugateGradient<Eigen::SparseMatrix<double>> solver;
385-
//Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > solver;
386-
solver.compute(A_mat);
387-
solver.setTolerance(solver_tolerance);
388-
solver.setMaxIterations(max_solver_iterations);
389-
390-
z = solver.solveWithGuess(b_vec, z);
391-
if (solver.info() != Eigen::Success) {
392-
double finalResidual = solver.error();
393-
cerr << "Max iter reached with error: " << finalResidual << endl;
394-
// return std::vector<double>();
395-
}
396-
397-
// Get the number of iterations
398-
int numIterations = solver.iterations();
399-
std::cout << "Number of iterations: " << numIterations << " error: " << solver.error() << " tolerance: " << solver_tolerance << std::endl;
400-
450+
Eigen::VectorXd z;
401451

402-
if(k == 0)
403-
break;
452+
if(k == 0.0)
453+
z = bni_integrate_direct(A, b, W);
454+
else
455+
z = bni_integrate_iterative(progressed, A, b, W, k, tolerance, solver_tolerance, max_iterations, max_solver_iterations);
404456

405-
Eigen::VectorXd wu = ((A.block(n, 0, n, n)*z).array().pow(2) -
406-
(A.block(0, 0, n, n)*z).array().pow(2)).unaryExpr([k](double x) { return sigmoid(x, k); });
407-
Eigen::VectorXd wv = ((A.block(n*3, 0, n, n)*z).array().pow(2) -
408-
(A.block(n*2, 0, n, n)*z).array().pow(2)).unaryExpr([k](double x) { return sigmoid(x, k); });
409-
410-
triples.clear();
411-
for(int i = 0; i < n; i++) {
412-
triples.push_back(Triple(i, i, wu(i)));
413-
triples.push_back(Triple(i+n, i+n, 1.0 - wu(i)));
414-
triples.push_back(Triple(i+n*2, i+n*2, wv(i)));
415-
triples.push_back(Triple(i+n*3, i+n*3, 1 - wv(i)));
416-
}
417-
W.setFromTriplets(triples.begin(), triples.end());
418-
419-
double energy_old = energy;
420-
tmp = A*z - b;
421-
energy = (tmp.transpose() * W * tmp)(0);
422-
cout << "Energy: " << energy << endl;
423-
424-
double relative_energy = fabs(energy - energy_old) / energy_old;
425-
double total_progress = fabs(energy - start_energy) / start_energy;
426-
if(progressed) {
427-
bool proceed = progressed("Integrating normals...", 100*(1 - (log(relative_energy) - log(tolerance))/(log(total_progress) - log(tolerance))));
428-
if(!proceed) break;
429-
}
430-
if(relative_energy < tolerance)
431-
break;
432-
}
433457
heights.resize(w*h);
434458
for(int i = 0; i < w*h; i++)
435459
heights[i] = z(i);
436-
//memcpy(&depthmap[0], z.data(), n*8);
437460
}

src/bni_normal_integration.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ void bni_integrate(std::function<bool(QString s, int n)> progressed,
1515
double tolerance = 1e-5,
1616
double solver_tolerance = 1e-5,
1717
int max_iterations = 10,
18-
int max_solver_iterations = 5000);
18+
int max_solver_iterations = 500);
1919

2020
std::vector<float> bni_pyramid(std::function<bool(QString s, int n)> progressed,
2121
int &w, int &h, std::vector<float> &normalmap,
2222
double k = 2.0,
2323
double tolerance = 1e-5,
2424
double solver_tolerance = 1e-5,
25-
int max_iterations = 150,
26-
int max_solver_iterations = 5000,
25+
int max_iterations = 15,
26+
int max_solver_iterations = 500,
2727
int scale = 0);
2828

2929
bool savePly(const QString &filename, size_t w, size_t h, std::vector<float> &z);

src/dome.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ void Dome::fromSpheres(std::vector<Image> &images, std::vector<Sphere *> &sphere
6969
case Dome::LIGHTS3D:
7070
computeParallaxPositions(images, spheres, lens, positions3d);
7171
directions = positions3d;
72+
positionsSphere.resize(directions.size());
7273
for(size_t i = 0; i < directions.size(); i++) {
7374
float len = directions[i].norm();
7475
directions[i] /= len;

src/project.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,12 @@ void Project::load(QString filename) {
280280
if(!setDir(folder))
281281
throw QString("The folder " + obj["folder"].toString() + " does not exists.");
282282

283+
//ensure resources folder has been created (for old project)
284+
QDir resources = dir.filePath("resources");
285+
if (!resources.exists() && !dir.mkpath("resources")) {
286+
throw QString("Could not create the resources folder in %1").arg(dir.absolutePath());
287+
}
288+
283289
lens.fromJson(obj["lens"].toObject());
284290
lens.width = imgsize.width();
285291
lens.height = imgsize.height();

0 commit comments

Comments
 (0)