Skip to content

Commit

Permalink
Flat normals algorithm: radial fit and fourier high-pass filter.
Browse files Browse the repository at this point in the history
  • Loading branch information
ponchio committed Aug 22, 2023
1 parent 75e6918 commit cfc29aa
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 35 deletions.
37 changes: 30 additions & 7 deletions relight/normalstask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "../src/jpeg_encoder.h"
#include "../src/imageset.h"
#include "../src/relight_threadpool.h"
#include "../src/flatnormals.h"

#include <Eigen/Eigen>
#include <Eigen/Core>
Expand Down Expand Up @@ -52,7 +53,7 @@ void NormalsTask::run()
}
imageSet.crop(m_Crop.left(), m_Crop.top(), m_Crop.width(), m_Crop.height());

std::vector<uint8_t> normals(imageSet.width * imageSet.height * 3);
std::vector<double> normals(imageSet.width * imageSet.height * 3);

// Thread pool used to handle the processors
RelightThreadPool pool;
Expand All @@ -68,7 +69,7 @@ void NormalsTask::run()

// Create the normal task and get the run lambda
uint32_t idx = i * 3 * imageSet.width;
uint8_t* data = normals.data() + idx;
double* data = normals.data() + idx;

std::function<void(void)> run = [this, &line, &imageSet, data](void)->void {
NormalsWorker task(m_Method, line, data, imageSet.lights);
Expand All @@ -84,8 +85,31 @@ void NormalsTask::run()

// Wait for the end of all the threads
pool.finish();

if(m_FlatMethod != NONE) {
NormalsImage ni;
ni.load(normals, imageSet.width, imageSet.height);
switch(m_FlatMethod) {
case RADIAL:
ni.flattenRadial();
break;
case FOURIER:
//convert radius to frequencies
double sigma = 100/m_FlatRadius;
ni.flattenFourier(imageSet.width/10, sigma);
break;
}
normals = ni.normals;
}

// Convert double to uint8_t;
std::vector<uint8_t> colors(imageSet.width * imageSet.height * 3);
for(size_t i = 0; i < normals.size(); i++) {
colors[i] = floor(((normals[i] + 1.0f) / 2.0f) * 255);
}

// Save the final result
QImage img(normals.data(), imageSet.width, imageSet.height, imageSet.width*3, QImage::Format_RGB888);
QImage img(colors.data(), imageSet.width, imageSet.height, imageSet.width*3, QImage::Format_RGB888);
img.save(m_OutputFolder);
progressed("Cleaning up...", 99);

Expand Down Expand Up @@ -164,10 +188,9 @@ void NormalsWorker::solveL2()
mNormals.col(0).normalize();

// Save
m_Normals[normalIdx] = floor(((mNormals(0, 0) + 1.0f) / 2.0f) * 255);
m_Normals[normalIdx+1] = floor(((mNormals(1, 0) + 1.0f) / 2.0f) * 255);
m_Normals[normalIdx+2] = floor(((mNormals(2, 0) + 1.0f) / 2.0f) * 255);

m_Normals[normalIdx] = mNormals(0, 0);
m_Normals[normalIdx+1] = mNormals(1, 0);
m_Normals[normalIdx+2] = mNormals(2, 0);
normalIdx += 3;
}
}
Expand Down
14 changes: 10 additions & 4 deletions relight/normalstask.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,31 @@
class NormalsTask : public Task
{
public:
NormalsTask(QString& inputPath, QString& outputPath, QRect crop, uint32_t method) :
m_InputFolder(inputPath), m_OutputFolder(outputPath), m_Crop(crop), m_Method(method){}

enum FlatMethod { NONE, RADIAL, FOURIER };
NormalsTask(QString& inputPath, QString& outputPath, QRect crop, uint32_t method, FlatMethod flatMethod, double flatRadius = 50) :
m_InputFolder(inputPath), m_OutputFolder(outputPath), m_Crop(crop), m_Method(method), m_FlatMethod (flatMethod), m_FlatRadius(flatRadius) {}
virtual ~NormalsTask(){};

virtual void run() override;



public slots:
bool progressed(std::string str, int percent) override;
private:
QString m_InputFolder;
QString m_OutputFolder;
QRect m_Crop;
uint32_t m_Method;
FlatMethod m_FlatMethod;
double m_FlatRadius;
};

class NormalsWorker
{
public:
NormalsWorker(unsigned int method, PixelArray& toProcess, uint8_t* normals, std::vector<Vector3f> lights) :
NormalsWorker(unsigned int method, PixelArray& toProcess, double* normals, std::vector<Vector3f> lights) :
m_Method(method), m_Row(toProcess), m_Normals(normals), m_Lights(lights){}

void run();
Expand All @@ -44,7 +50,7 @@ class NormalsWorker
private:
uint32_t m_Method;
PixelArray m_Row;
uint8_t* m_Normals;
double* m_Normals;
std::vector<Vector3f> m_Lights;
QMutex m_Mutex;
};
25 changes: 14 additions & 11 deletions relight/relight.pro
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ win32:INCLUDEPATH += ../external/libjpeg-turbo-2.0.6/include \
win32:LIBS += ../external/libjpeg-turbo-2.0.6/lib/jpeg-static.lib

unix:INCLUDEPATH += /usr/include/eigen3
unix:LIBS += -ljpeg -liomp5
unix:LIBS += -ljpeg -liomp5 -lfftw3 #-lfftw3f -lfftw3l
unix:QMAKE_CXXFLAGS += -fopenmp


Expand All @@ -40,6 +40,7 @@ SOURCES += main.cpp \
graphics_view_zoom.cpp \
normalstask.cpp \
rtiexport.cpp \
../relight-cli/convert_rti.cpp \
../relight-cli/rtibuilder.cpp \
../src/imageset.cpp \
../src/jpeg_decoder.cpp \
Expand All @@ -48,6 +49,8 @@ SOURCES += main.cpp \
../src/legacy_rti.cpp \
../src/deepzoom.cpp \
../src/exif.cpp \
../src/flatnormals.cpp \
../src/lp.cpp \
dome.cpp \
helpdialog.cpp \
project.cpp \
Expand All @@ -64,9 +67,7 @@ SOURCES += main.cpp \
task.cpp \
rtitask.cpp \
settingsdialog.cpp \
../relight-cli/convert_rti.cpp \
domecalibration.cpp \
../src/lp.cpp \
qmarkerlist.cpp \
qmarker.cpp \
qmeasuremarker.cpp \
Expand All @@ -84,7 +85,6 @@ SOURCES += main.cpp \


HEADERS += \
../src/deepzoom.h \
dstretch.h \
dstretchdialog.h \
dstretchtask.h \
Expand All @@ -97,17 +97,24 @@ HEADERS += \
helpdialog.h \
../src/imageset.h \
../src/jpeg_decoder.h \
../src/jpeg_encoder.h \
../src/material.h \
../src/eigenpca.h \
../relight-cli/rtibuilder.h \
../src/relight_threadpool.h \
../src/relight_vector.h \
../src/lp.h \
../src/deepzoom.h \
../src/flatnormals.h \
../src/exif.h \
../src/legacy_rti.h \
../src/relight_vector.h \
../src/lp.h \
../src/flatnormals.h \
project.h \
measure.h \
focaldialog.h \
lens.h \
image.h \
../src/exif.h \
httpserver.h \
scripts.h \
processqueue.h \
Expand All @@ -117,12 +124,9 @@ HEADERS += \
task.h \
rtitask.h \
settingsdialog.h \
../src/legacy_rti.h \
httplib.h \
domecalibration.h \
dome.h \
../src/relight_vector.h \
../src/lp.h \
qmarker.h \
qmarkerlist.h \
qmeasuremarker.h \
Expand All @@ -136,8 +140,7 @@ HEADERS += \
aligndialog.h \
zoom.h \
zoomdialog.h \
zoomtask.h \
../src/deepzoom.h
zoomtask.h

FORMS += \
dstretchdialog.ui \
Expand Down
13 changes: 11 additions & 2 deletions relight/rtiexport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,17 @@ void RtiExport::createNormals() {
if(ui->rpca_solver->isChecked())
method = 5;

ProcessQueue &queue = ProcessQueue::instance();
NormalsTask *task = new NormalsTask(path, output, crop, method);
NormalsTask::FlatMethod flat_method;
if(ui->flat_none->isChecked())
flat_method = NormalsTask::FlatMethod::NONE;
if(ui->flat_radial->isChecked())
flat_method = NormalsTask::FlatMethod::RADIAL;
if(ui->flat_fourier->isChecked())
flat_method = NormalsTask::FlatMethod::FOURIER;

double flat_radius = ui->flat_fourier_radius->value();
ProcessQueue &queue = ProcessQueue::instance();
NormalsTask *task = new NormalsTask(path, output, crop, method, flat_method, flat_radius);

QList<QVariant> slights;
for(auto light: lights)
Expand Down
59 changes: 53 additions & 6 deletions relight/rtiexport.ui
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<item>
<widget class="QTabWidget" name="export_frame">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="tabWidgetPage1">
<attribute name="title">
Expand Down Expand Up @@ -286,8 +286,8 @@
<attribute name="title">
<string>Normals</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>Solver</string>
Expand Down Expand Up @@ -326,7 +326,54 @@
</layout>
</widget>
</item>
<item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Flatten normals</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0" colspan="2">
<widget class="QRadioButton" name="flat_none">
<property name="text">
<string>None</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="flat_radial">
<property name="text">
<string>Radial</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QRadioButton" name="flat_fourier">
<property name="text">
<string>Fourier</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Radius (0 - 100%):</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="flat_fourier_radius">
<property name="value">
<double>20.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="crop1">
<property name="text">
<string>Crop...</string>
Expand All @@ -337,7 +384,7 @@
</property>
</widget>
</item>
<item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
Expand All @@ -350,7 +397,7 @@
</property>
</spacer>
</item>
<item>
<item row="4" column="0">
<widget class="QPushButton" name="build_normals">
<property name="text">
<string>Build</string>
Expand Down
10 changes: 5 additions & 5 deletions relight/sphere.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,11 @@ void Sphere::resetHighlight(size_t n) {

void Sphere::ellipseFit() {
size_t n = border.size();

Eigen::MatrixXd D1(n, 3);
Eigen::MatrixXd D2(n, 3);
for(size_t k = 0; k < border.size(); k++) {
double x = X(k)= border[k].x();
double y = Y(k)= border[k].y();
double x = border[k].x();
double y = border[k].y();
D1(k, 0) = x*x;
D1(k, 1) = x*y;
D1(k, 2) = y*y;
Expand Down Expand Up @@ -96,9 +95,10 @@ void Sphere::ellipseFit() {
Eigen::VectorXd cond = 4 * row0.array() * row2.array() - row1.array().pow(2);


Eigen::VectorXd ellipse = eigenvector.col(0)
Eigen::VectorXd ellipse = eigenvector.col(0);
Eigen::VectorXd min_pos_eig;

for(int i= 0; i<3 ; i++){
for(int i = 0; i<3 ; i++) {
if(cond(i) > 0){
min_pos_eig = eigenvector.col(i);
break;
Expand Down

0 comments on commit cfc29aa

Please sign in to comment.