Blender V4.3
SteerableViewMap.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <sstream>
12
13#include "Silhouette.h"
14#include "SteerableViewMap.h"
15
16#include "../geometry/Geom.h"
17
18#include "../image/Image.h"
20
21#include "BLI_math_base.h"
22#include "BLI_sys_types.h"
23
24#include "BKE_global.hh"
25
26#include "IMB_imbuf.hh"
27#include "IMB_imbuf_types.hh"
28
29namespace Freestyle {
30
31using namespace Geometry;
32
34{
35 _nbOrientations = nbOrientations;
36 _bound = cos(M_PI / float(_nbOrientations));
37 for (uint i = 0; i < _nbOrientations; ++i) {
38 _directions.emplace_back(cos(float(i) * M_PI / float(_nbOrientations)),
39 sin(float(i) * M_PI / float(_nbOrientations)));
40 }
41 Build();
42}
43
45{
47 new ImagePyramid *[_nbOrientations + 1]; // one more map to store the complete visible VM
48 memset((_imagesPyramids), 0, (_nbOrientations + 1) * sizeof(ImagePyramid *));
49}
50
52{
54 uint i;
55 _bound = iBrother._bound;
56 _directions = iBrother._directions;
57 _mapping = iBrother._mapping;
59 new ImagePyramid *[_nbOrientations + 1]; // one more map to store the complete visible VM
60 for (i = 0; i <= _nbOrientations; ++i) {
62 *(dynamic_cast<GaussianPyramid *>(iBrother._imagesPyramids[i])));
63 }
64}
65
70
72{
73 uint i;
74 if (_imagesPyramids) {
75 for (i = 0; i <= _nbOrientations; ++i) {
76 if (_imagesPyramids[i]) {
77 delete (_imagesPyramids)[i];
78 }
79 }
80 delete[] _imagesPyramids;
81 _imagesPyramids = nullptr;
82 }
83 if (!_mapping.empty()) {
84 for (map<uint, double *>::iterator m = _mapping.begin(), mend = _mapping.end(); m != mend; ++m)
85 {
86 delete[] (*m).second;
87 }
88 _mapping.clear();
89 }
90}
91
93{
94 Clear();
95 Build();
96}
97
99{
100 double dotp = fabs(dir * _directions[i]);
101 if (dotp < _bound) {
102 return 0.0;
103 }
104 if (dotp > 1.0) {
105 dotp = 1.0;
106 }
107
108 return cos(float(_nbOrientations) / 2.0 * acos(dotp));
109}
110
112{
113 uint i;
114 uint id = iFEdge->getId().getFirst();
115 map<uint, double *>::iterator o = _mapping.find(id);
116 if (o != _mapping.end()) {
117 return (*o).second;
118 }
119 double *res = new double[_nbOrientations];
120 for (i = 0; i < _nbOrientations; ++i) {
121 res[i] = 0.0;
122 }
123 Vec3r o2d3 = iFEdge->orientation2d();
124 Vec2r o2d2(o2d3.x(), o2d3.y());
125 real norm = o2d2.norm();
126 if (norm < 1.0e-6) {
127 return res;
128 }
129 o2d2 /= norm;
130
131 for (i = 0; i < _nbOrientations; ++i) {
132 res[i] = ComputeWeight(o2d2, i);
133 }
134 _mapping[id] = res;
135 return res;
136}
137
139{
140 // soc uint res = 0;
141 real norm = dir.norm();
142 if (norm < 1.0e-6) {
143 return _nbOrientations + 1;
144 }
145 dir /= norm;
146 double maxw = 0.0f;
147 uint winner = _nbOrientations + 1;
148 for (uint i = 0; i < _nbOrientations; ++i) {
149 double w = ComputeWeight(dir, i);
150 if (w > maxw) {
151 maxw = w;
152 winner = i;
153 }
154 }
155 return winner;
156}
157
159{
160 map<uint, double *>::iterator o = _mapping.find(id);
161 if (o != _mapping.end()) {
162 double *wvalues = (*o).second;
163 double maxw = 0.0;
164 uint winner = _nbOrientations + 1;
165 for (uint i = 0; i < _nbOrientations; ++i) {
166 double w = wvalues[i];
167 if (w > maxw) {
168 maxw = w;
169 winner = i;
170 }
171 }
172 return winner;
173 }
174 return _nbOrientations + 1;
175}
176
178 bool copy,
179 uint iNbLevels,
180 float iSigma)
181{
182 for (uint i = 0; i <= _nbOrientations; ++i) {
183 ImagePyramid *svm = (_imagesPyramids)[i];
184 delete svm;
185 if (copy) {
186 svm = new GaussianPyramid(*(steerableBases[i]), iNbLevels, iSigma);
187 }
188 else {
189 svm = new GaussianPyramid(steerableBases[i], iNbLevels, iSigma);
190 }
191 _imagesPyramids[i] = svm;
192 }
193}
194
195float SteerableViewMap::readSteerableViewMapPixel(uint iOrientation, int iLevel, int x, int y)
196{
197 ImagePyramid *pyramid = _imagesPyramids[iOrientation];
198 if (!pyramid) {
199 if (G.debug & G_DEBUG_FREESTYLE) {
200 cout << "Warning: this steerable ViewMap level doesn't exist" << endl;
201 }
202 return 0.0f;
203 }
204 if ((x < 0) || (x >= pyramid->width()) || (y < 0) || (y >= pyramid->height())) {
205 return 0;
206 }
207 // float v = pyramid->pixel(x, pyramid->height() - 1 - y, iLevel) * 255.0f;
208 // We encode both the directionality and the lines counting on 8 bits (because of frame buffer).
209 // Thus, we allow until 8 lines to pass through the same pixel, so that we can discretize the
210 // Pi/_nbOrientations angle into 32 slices. Therefore, for example, in the vertical direction, a
211 // vertical line will have the value 32 on each pixel it passes through.
212 float v = pyramid->pixel(x, pyramid->height() - 1 - y, iLevel) / 32.0f;
213 return v;
214}
215
216float SteerableViewMap::readCompleteViewMapPixel(int iLevel, int x, int y)
217{
218 return readSteerableViewMapPixel(_nbOrientations, iLevel, x, y);
219}
220
222{
223 if (_imagesPyramids[0]) {
225 }
226 return 0;
227}
228
230{
231 for (uint i = 0; i <= _nbOrientations; ++i) {
232 if (_imagesPyramids[i] == nullptr) {
233 cerr << "SteerableViewMap warning: orientation " << i
234 << " of steerable View Map whas not been computed yet" << endl;
235 continue;
236 }
237 int ow = _imagesPyramids[i]->width(0);
238 int oh = _imagesPyramids[i]->height(0);
239
240 // soc QString base("SteerableViewMap");
241 string base("SteerableViewMap");
242 stringstream filepath;
243
244 for (int j = 0; j < _imagesPyramids[i]->getNumberOfLevels(); ++j) { // soc
245 float coeff = 1.0f; // 1 / 255.0f; // 100 * 255; // * pow(2, j);
246 // soc QImage qtmp(ow, oh, QImage::Format_RGB32);
247 ImBuf *ibuf = IMB_allocImBuf(ow, oh, 32, IB_rect);
248 int rowbytes = ow * 4;
249 uchar *pix;
250
251 for (int y = 0; y < oh; ++y) { // soc
252 for (int x = 0; x < ow; ++x) { // soc
253 int c = int(coeff * _imagesPyramids[i]->pixel(x, y, j));
254 if (c > 255) {
255 c = 255;
256 }
257 // int c = int(_imagesPyramids[i]->pixel(x, y, j));
258
259 // soc qtmp.setPixel(x, y, qRgb(c, c, c));
260 pix = ibuf->byte_buffer.data + y * rowbytes + x * 4;
261 pix[0] = pix[1] = pix[2] = c;
262 }
263 }
264
265 // soc qtmp.save(base+QString::number(i)+"-"+QString::number(j)+".png", "PNG");
266 filepath << base;
267 filepath << i << "-" << j << ".png";
268 ibuf->ftype = IMB_FTYPE_PNG;
269 IMB_saveiff(ibuf, const_cast<char *>(filepath.str().c_str()), 0);
270 }
271#if 0
272 QString base("SteerableViewMap");
273 for (uint j = 0; j < _imagesPyramids[i]->getNumberOfLevels(); ++j) {
274 GrayImage *img = _imagesPyramids[i]->getLevel(j);
275 int ow = img->width();
276 int oh = img->height();
277 float coeff = 1.0f; // 100 * 255; // * pow(2, j);
278 QImage qtmp(ow, oh, 32);
279 for (uint y = 0; y < oh; ++y) {
280 for (uint x = 0; x < ow; ++x) {
281 int c = int(coeff * img->pixel(x, y));
282 if (c > 255) {
283 c = 255;
284 }
285 // int c = int(_imagesPyramids[i]->pixel(x, y, j));
286 qtmp.setPixel(x, y, qRgb(c, c, c));
287 }
288 }
289 qtmp.save(base + QString::number(i) + "-" + QString::number(j) + ".png", "PNG");
290 }
291#endif
292 }
293}
294
295} /* namespace Freestyle */
@ G_DEBUG_FREESTYLE
#define M_PI
unsigned char uchar
unsigned int uint
Vectors and Matrices (useful type definitions)
@ IMB_FTYPE_PNG
Contains defines and structs used throughout the imbuf module.
@ IB_rect
Class to represent a pyramid of images.
Class to encapsulate an array of RGB or Gray level values.
Classes to define a silhouette structure.
Convenient access to the steerable ViewMap to which any element of the ViewMap belongs to.
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition btVector3.h:263
virtual Id getId() const
Definition Silhouette.h:485
Vec3r orientation2d() const
Definition Silhouette.h:910
uint height() const
Definition Image.h:113
uint width() const
Definition Image.h:107
float pixel(uint x, uint y) const
Definition Image.h:369
id_type getFirst() const
Definition Id.h:64
virtual float pixel(int x, int y, int level=0)
virtual GrayImage * getLevel(int l)
int getNumberOfLevels() const
virtual int height(int level=0)
virtual int width(int level=0)
double * AddFEdge(FEdge *iFEdge)
float readCompleteViewMapPixel(int iLevel, int x, int y)
SteerableViewMap(uint nbOrientations=4)
map< uint, double * > _mapping
double ComputeWeight(const Vec2d &dir, uint iNOrientation)
float readSteerableViewMapPixel(uint iOrientation, int iLevel, int x, int y)
void buildImagesPyramids(GrayImage **steerableBases, bool copy=false, uint iNbLevels=4, float iSigma=1.0f)
value_type x() const
Definition VecMat.h:493
value_type y() const
Definition VecMat.h:503
value_type norm() const
Definition VecMat.h:94
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
bool IMB_saveiff(struct ImBuf *, const char *, int)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float3 cos(float3 v)
#define G(x, y, z)
inherits from class Rep
Definition AppCanvas.cpp:20
static uint c
Definition RandGen.cpp:87
static uint x[3]
Definition RandGen.cpp:77
double real
Definition Precision.h:14
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
ImBufByteBuffer byte_buffer
enum eImbFileType ftype