Skip to content

Commit

Permalink
Refactored BSpline to hold coordinates in form of unscaled indices
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-pr committed Dec 28, 2020
1 parent 9193bd7 commit 10a0430
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 44 deletions.
7 changes: 3 additions & 4 deletions src/plugins/opencv/bspline.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ namespace opencv {
template <unsigned DEGREE>
class BSpline {
public:
explicit BSpline(const std::array<std::size_t, DEGREE>& subdiv = initArray(std::size_t(0)),
const std::array<float, DEGREE>& min = initArray(0.0f),
const std::array<float, DEGREE>& max = initArray(1.0f));
explicit BSpline(const std::array<std::size_t, DEGREE>& subdiv = initArray(std::size_t(0)));

void addSample(const std::array<float, DEGREE>& coords, float value);
float sample(const std::array<float, DEGREE>& coords) const;

std::size_t size(unsigned dim) const;

bool operator==(const BSpline& b) const;
bool operator!=(const BSpline& b) const;

Expand All @@ -31,7 +31,6 @@ class BSpline {

std::array<std::size_t, DEGREE> m_subdiv;
std::vector<std::pair<float, float>> m_controls;
std::array<float, DEGREE> m_min, m_max;
};

template <unsigned DEGREE>
Expand Down
62 changes: 40 additions & 22 deletions src/plugins/opencv/bspline.inl
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,17 @@ std::array<T, DEGREE> BSpline<DEGREE>::initArray(T val) {
}

template <unsigned DEGREE>
BSpline<DEGREE>::BSpline(const std::array<std::size_t, DEGREE>& subdiv,
const std::array<float, DEGREE>& min,
const std::array<float, DEGREE>& max)
: m_subdiv(subdiv), m_min(min), m_max(max) {
std::size_t controlCount = 1;
for(unsigned d = 0; d < DEGREE; ++d)
controlCount *= subdiv[d] + 2;
m_controls.reserve(controlCount);
m_controls.resize(controlCount, std::make_pair(0.0f, 0.0f));
BSpline<DEGREE>::BSpline(const std::array<std::size_t, DEGREE>& subdiv) : m_subdiv(subdiv) {
std::size_t controlCount = 1, baseCount = 1;
for(unsigned d = 0; d < DEGREE; ++d) {
controlCount *= subdiv[d] + 3;
baseCount *= subdiv[d];
}

if(baseCount > 0) {
m_controls.reserve(controlCount);
m_controls.resize(controlCount, std::make_pair(0.0f, 0.0f));
}
}

namespace {
Expand All @@ -60,7 +62,7 @@ struct Visitor {
template <typename VISITOR, unsigned DIM>
struct Visit {
static void visit(const VISITOR& visitor, std::size_t index = 0, float weight = 1.0f) {
index = index * (visitor.subdiv[DIM] + 2) + visitor.offsets[DIM];
index = index * (visitor.subdiv[DIM] + 3) + visitor.offsets[DIM];
for(std::size_t a = 0; a < 4; ++a)
Visit<VISITOR, DIM - 1>::visit(visitor, index + a, visitor.b_coeffs[DIM * 4 + a] * weight);
}
Expand All @@ -69,7 +71,7 @@ struct Visit {
template <typename VISITOR>
struct Visit<VISITOR, 0> {
static void visit(const VISITOR& visitor, std::size_t index, float weight) {
index = index * (visitor.subdiv[0] + 2) + visitor.offsets[0];
index = index * (visitor.subdiv[0] + 3) + visitor.offsets[0];
for(std::size_t a = 0; a < 4; ++a)
visitor.fn(index + a, weight * visitor.b_coeffs[a]);
}
Expand All @@ -87,24 +89,26 @@ void BSpline<DEGREE>::visit(const std::array<float, DEGREE>& _coords, const FN&
data.fn = fn;

for(unsigned d = 0; d < DEGREE; ++d) {
coords[d] = (coords[d] - m_min[d]) / (m_max[d] - m_min[d] + 1e-6f);
coords[d] += 0.5f;

assert(coords[d] >= 0.0f);
assert(floor(coords[d]) >= 0.0f);

data.offsets[d] = floor(coords[d]);

if(coords[d] < 0.0 || coords[d] >= 1.0) {
if(data.offsets[d] >= m_subdiv[d]) {
std::stringstream ss;
ss << "Coordinate #" << d << " out of range - " << _coords[d] << " (expected between " << m_min[d]
<< " and " << m_max[d] << ")";
ss << "Coordinate #" << d << " out of range - " << (_coords[d] - 0.5f) << " (expected between 0.0 and "
<< (m_subdiv[d] - 3) << ")";
throw std::runtime_error(ss.str());
}

coords[d] *= (float)(m_subdiv[d]);

data.offsets[d] = floor(coords[d]);
coords[d] = coords[d] - data.offsets[d];

assert(coords[d] >= 0.0f);
assert(coords[d] < 1.0f);

assert(data.offsets[d] >= std::size_t(0) && data.offsets[d] < m_subdiv[d]);
assert(data.offsets[d] < m_subdiv[d]);
}

// precompute per-dim b-spline coeficients
Expand All @@ -123,6 +127,7 @@ struct AddSample {
float m_value;

void operator()(std::size_t index, float weight) const {
assert(index < m_controls->size());
(*m_controls)[index].first += weight * m_value;
(*m_controls)[index].second += weight;
}
Expand All @@ -133,6 +138,8 @@ struct Sample {
float* m_result;

void operator()(std::size_t index, float weight) const {
assert(index < m_controls->size());

if((*m_controls)[index].second > 0.0f)
(*m_result) += (*m_controls)[index].first / (*m_controls)[index].second * weight;
}
Expand All @@ -142,29 +149,40 @@ struct Sample {

template <unsigned DEGREE>
void BSpline<DEGREE>::addSample(const std::array<float, DEGREE>& coords, float value) {
assert(!m_controls.empty());

AddSample add{&m_controls, value};
visit(coords, add);
}

template <unsigned DEGREE>
float BSpline<DEGREE>::sample(const std::array<float, DEGREE>& coords) const {
if(m_controls.empty())
return 0.0f;

float result = 0;
Sample smp{&m_controls, &result};
this->visit(coords, smp);
visit(coords, smp);

assert(std::isfinite(result));

return result;
}

template <unsigned DEGREE>
std::size_t BSpline<DEGREE>::size(unsigned dim) const {
assert(dim < DEGREE);
return m_subdiv[dim];
}

template <unsigned DEGREE>
bool BSpline<DEGREE>::operator==(const BSpline& b) const {
return m_subdiv == b.m_subdiv && m_controls == b.m_controls && m_min == b.m_min && m_max == b.m_max;
return m_subdiv == b.m_subdiv && m_controls == b.m_controls;
}

template <unsigned DEGREE>
bool BSpline<DEGREE>::operator!=(const BSpline& b) const {
return m_subdiv != b.m_subdiv || m_controls != b.m_controls || m_min != b.m_min || m_max != b.m_max;
return m_subdiv != b.m_subdiv || m_controls != b.m_controls;
}

template <unsigned DEGREE>
Expand Down
12 changes: 7 additions & 5 deletions src/plugins/opencv/nodes/lightfields/bspline_to_frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ dependency_graph::OutAttr<possumwood::opencv::Frame> a_frame;
dependency_graph::State compute(dependency_graph::Values& data) {
const Imath::V2i& res = data.get(a_resolution);

const std::array<possumwood::opencv::BSpline<4>, 3>& bspline = data.get(a_bspline);

Imath::V2f uv = data.get(a_uv);
uv = (uv + Imath::V2f(1.0f, 1.0f)) / 2.0f;
uv = (uv + Imath::V2f(1.0f, 1.0f)) / 2.0f * Imath::V2f(bspline[0].size(2) - 1, bspline[0].size(3) - 1);

const std::array<possumwood::opencv::BSpline<4>, 3>& bspline = data.get(a_bspline);
Imath::V2f xy_scale =
Imath::V2f(bspline[0].size(0) - 1, bspline[0].size(1) - 1) / Imath::V2f(data.get(a_resolution));

cv::Mat result = cv::Mat::zeros(res.y, res.x, CV_32FC3);

Expand All @@ -33,9 +36,8 @@ dependency_graph::State compute(dependency_graph::Values& data) {
float* pixel = result.ptr<float>(y, x);

for(int c = 0; c < 3; ++c)
pixel[c] = bspline[c].sample(std::array<float, 4>{
{(float)x / (float)(res.x - 1), (float)y / (float)(res.y - 1), uv.x, uv.y}});
;
pixel[c] = bspline[c].sample(
std::array<float, 4>{{(float)x * xy_scale.x, (float)y * xy_scale.y, uv.x, uv.y}});
}
});

Expand Down
25 changes: 20 additions & 5 deletions src/plugins/opencv/nodes/lightfields/samples_to_bspline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,38 @@ dependency_graph::State compute(dependency_graph::Values& data) {
std::array<std::size_t, 4>{{data.get(a_xyRes), data.get(a_xyRes), data.get(a_uvRes), data.get(a_uvRes)}});

const lightfields::Samples& samples = data.get(a_samples);
const Imath::V2f xy_scale = Imath::V2f(data.get(a_xyRes) - 1, data.get(a_xyRes) - 1) /
Imath::V2f(samples.sensorSize().x - 1, samples.sensorSize().y - 1);
const Imath::V2f uv_scale = Imath::V2f(data.get(a_uvRes) - 1, data.get(a_uvRes) - 1);

const float xy_lim = data.get(a_xyRes);
const float uv_lim = data.get(a_uvRes);

std::size_t missed = 0;

for(auto& s : samples) {
const Imath::V2f xy = s.xy / Imath::V2f(samples.sensorSize());
const Imath::V2f uv = s.uv / 2.0 + Imath::V2f(0.5f, 0.5f);
const Imath::V2f xy = s.xy * xy_scale;
const Imath::V2f uv = (s.uv / 2.0 + Imath::V2f(0.5f, 0.5f)) * uv_scale;

if(xy.x >= 0.0f && xy.x <= 1.0f && xy.y >= 0.0f && xy.y <= 1.0f && uv.x >= 0.0f && uv.x <= 1.0f &&
uv.y >= 0.0f && uv.y <= 1.0f) {
if(xy.x >= 0.0f && xy.x <= xy_lim && xy.y >= 0.0f && xy.y <= xy_lim && uv.x >= 0.0f && uv.x <= uv_lim &&
uv.y >= 0.0f && uv.y <= uv_lim) {
if(s.color == lightfields::Samples::kRGB)
for(int a = 0; a < 3; ++a)
bspline[a].addSample(std::array<float, 4>{xy.x, xy.y, uv.x, uv.y}, s.value[a]);
else
bspline[s.color].addSample(std::array<float, 4>{xy.x, xy.y, uv.x, uv.y}, s.value[s.color]);
}
else
++missed;
}

data.set(a_bspline, bspline);

return dependency_graph::State();
dependency_graph::State state;
if(missed > 0)
state.addWarning(std::to_string(missed) + " samples were missed when constructing the b spline.");

return state;
}

void init(possumwood::Metadata& meta) {
Expand Down
16 changes: 8 additions & 8 deletions toolbars/07_lightfields_import/18_mosaic_normalization.psw
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
{
"connections": [
{
"in_node": "convert_0",
"in_port": "in_frame",
"out_node": "bspline_to_frame_0",
"out_port": "frame"
},
{
"in_node": "network_0",
"in_port": "frame",
Expand Down Expand Up @@ -36,12 +42,6 @@
"out_node": "integrate_mosaic_0",
"out_port": "sequence"
},
{
"in_node": "convert_0",
"in_port": "in_frame",
"out_node": "integrate_nearest_0",
"out_port": "out_frame"
},
{
"in_node": "demosaic_0",
"in_port": "in_frame",
Expand Down Expand Up @@ -131,7 +131,7 @@
},
"name": "convert",
"ports": {
"a": 512.0,
"a": 500.0,
"b": 0.0,
"mode": "CV_8U"
},
Expand Down Expand Up @@ -632,5 +632,5 @@
},
"type": "network",
"ui_geometry": "AdnQywADAAAAAAAAAAAAAAAABqoAAAOfAAAAAAAAABQAAAQ6AAACkwAAAAACAAAABqsAAAAAAAAAFwAABqoAAAOf",
"ui_state": "AAAA/wAAAAD9AAAAAgAAAAAAAAKRAAAC+fwCAAAAAfsAAAAKAGcAcgBhAHAAaAEAAAB1AAAC+QAAAJsBAAADAAAAAQAAAagAAAL5/AIAAAAC+wAAABQAcAByAG8AcABlAHIAdABpAGUAcwEAAAB1AAABJwAAAHkBAAAD+wAAAAwAZQBkAGkAdABvAHIBAAABnQAAAdEAAACtAQAAAwAAAnAAAAL5AAAABAAAAAQAAAAIAAAACPwAAAAA"
"ui_state": "AAAA/wAAAAD9AAAAAgAAAAAAAAJjAAAC+fwCAAAAAfsAAAAKAGcAcgBhAHAAaAEAAAB1AAAC+QAAAJsBAAADAAAAAQAAAagAAAL5/AIAAAAC+wAAABQAcAByAG8AcABlAHIAdABpAGUAcwEAAAB1AAABJwAAAHkBAAAD+wAAAAwAZQBkAGkAdABvAHIBAAABnQAAAdEAAACtAQAAAwAAAp4AAAL5AAAABAAAAAQAAAAIAAAACPwAAAAA"
}

0 comments on commit 10a0430

Please sign in to comment.