forked from Teragion/Sea-Thru-Impl
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompute_illuminant.cpp
More file actions
126 lines (103 loc) · 3.54 KB
/
Copy pathcompute_illuminant.cpp
File metadata and controls
126 lines (103 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//
// This file is part of Sea-Thru-Impl.
// Copyright (c) 2022 Zeyuan HE (Teragion).
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <queue>
#include <set>
#include <utility>
#include <vector>
#include <iostream>
#include <omp.h>
static int xlim;
static int ylim;
static bool precomputed = false;
static std::vector<std::vector<std::pair<int, int> > > maps;
inline int ind(int x, int y) {
return x * ylim + y;
}
std::vector<std::pair<int, int> > find_neighborhood(double* depths, int x, int y, double eps) {
std::vector<std::pair<int, int> > ret;
std::queue<std::pair<int, int> > q;
std::set<std::pair<int, int> > flags;
q.push(std::make_pair(x, y));
double z = depths[ind(x, y)];
while (!q.empty()) {
auto cur = q.front();
q.pop();
if (flags.find(cur) != flags.end()) {
continue;
} else {
flags.emplace(cur);
if (std::abs(depths[ind(cur.first, cur.second)] - z) < eps) {
ret.push_back(cur);
if (cur.first > 0) {
q.push({cur.first - 1, cur.second});
}
if (cur.second > 0) {
q.push({cur.first, cur.second - 1});
}
if (cur.first < xlim - 1) {
q.push({cur.first + 1, cur.second});
}
if (cur.second < ylim - 1) {
q.push({cur.first, cur.second + 1});
}
}
}
}
return ret;
}
extern "C" {
void compute_illuminant_map(double* Dc, double* depths, double* illu, double p, double f, double eps, int xlim, int ylim, int iterations) {
// Compute and store neighborhood map
std::vector<double> ac(xlim * ylim, 0.0);
std::vector<double> ac_p(xlim * ylim, 0.0);
std::vector<double> ac_new(xlim * ylim, 0.0);
if (!precomputed) {
std::cout << "Computing neighborhood map." << std::endl;
#pragma omp parallel for
for (int x = 0; x < xlim; x++) {
// std::cout << x << std::endl;
for (int y = 0; y < ylim; y++) {
#pragma omp critical
maps.push_back(find_neighborhood(depths, x, y, eps));
}
}
precomputed = true;
}
std::cout << "Computing illuminant." << std::endl;
for (int k = 0; k < iterations; k++) {
// std::cout << k << std::endl;
#pragma omp parallel for
for (int x = 0; x < xlim; x++) {
for (int y = 0; y < ylim; y++) {
auto nmap = maps[ind(x, y)];
double sum = 0.0;
for (const auto & p : nmap) {
sum += ac[ind(p.first, p.second)];
}
ac_p[ind(x, y)] = sum /= nmap.size();
ac_new[ind(x, y)] = Dc[ind(x, y)] * p + ac_p[ind(x, y)] * (1 - p);
}
}
ac.swap(ac_new);
}
for (int x = 0; x < xlim; x++) {
for (int y = 0; y < ylim; y++) {
illu[ind(x, y)] = ac[ind(x, y)] * f;
}
}
}
}