Blender  V3.3
SteerableViewMap.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
9 #include <sstream>
10 
11 #include "Silhouette.h"
12 #include "SteerableViewMap.h"
13 
14 #include "../geometry/Geom.h"
15 
16 #include "../image/Image.h"
17 #include "../image/ImagePyramid.h"
18 
19 #include "BKE_global.h"
20 #include "BLI_math.h"
21 
22 #include "IMB_imbuf.h"
23 #include "IMB_imbuf_types.h"
24 
25 namespace Freestyle {
26 
27 using namespace Geometry;
28 
29 SteerableViewMap::SteerableViewMap(unsigned int nbOrientations)
30 {
31  _nbOrientations = nbOrientations;
32  _bound = cos(M_PI / (float)_nbOrientations);
33  for (unsigned int i = 0; i < _nbOrientations; ++i) {
34  _directions.emplace_back(cos((float)i * M_PI / (float)_nbOrientations),
35  sin((float)i * M_PI / (float)_nbOrientations));
36  }
37  Build();
38 }
39 
41 {
42  _imagesPyramids =
43  new ImagePyramid *[_nbOrientations + 1]; // one more map to store the complete visible VM
44  memset((_imagesPyramids), 0, (_nbOrientations + 1) * sizeof(ImagePyramid *));
45 }
46 
48 {
49  _nbOrientations = iBrother._nbOrientations;
50  unsigned int i;
51  _bound = iBrother._bound;
52  _directions = iBrother._directions;
53  _mapping = iBrother._mapping;
54  _imagesPyramids =
55  new ImagePyramid *[_nbOrientations + 1]; // one more map to store the complete visible VM
56  for (i = 0; i <= _nbOrientations; ++i) {
57  _imagesPyramids[i] = new GaussianPyramid(
58  *(dynamic_cast<GaussianPyramid *>(iBrother._imagesPyramids[i])));
59  }
60 }
61 
63 {
64  Clear();
65 }
66 
68 {
69  unsigned int i;
70  if (_imagesPyramids) {
71  for (i = 0; i <= _nbOrientations; ++i) {
72  if (_imagesPyramids[i]) {
73  delete (_imagesPyramids)[i];
74  }
75  }
76  delete[] _imagesPyramids;
77  _imagesPyramids = nullptr;
78  }
79  if (!_mapping.empty()) {
80  for (map<unsigned int, double *>::iterator m = _mapping.begin(), mend = _mapping.end();
81  m != mend;
82  ++m) {
83  delete[](*m).second;
84  }
85  _mapping.clear();
86  }
87 }
88 
90 {
91  Clear();
92  Build();
93 }
94 
95 double SteerableViewMap::ComputeWeight(const Vec2d &dir, unsigned i)
96 {
97  double dotp = fabs(dir * _directions[i]);
98  if (dotp < _bound) {
99  return 0.0;
100  }
101  if (dotp > 1.0) {
102  dotp = 1.0;
103  }
104 
105  return cos((float)_nbOrientations / 2.0 * acos(dotp));
106 }
107 
109 {
110  unsigned i;
111  unsigned id = iFEdge->getId().getFirst();
112  map<unsigned int, double *>::iterator o = _mapping.find(id);
113  if (o != _mapping.end()) {
114  return (*o).second;
115  }
116  double *res = new double[_nbOrientations];
117  for (i = 0; i < _nbOrientations; ++i) {
118  res[i] = 0.0;
119  }
120  Vec3r o2d3 = iFEdge->orientation2d();
121  Vec2r o2d2(o2d3.x(), o2d3.y());
122  real norm = o2d2.norm();
123  if (norm < 1.0e-6) {
124  return res;
125  }
126  o2d2 /= norm;
127 
128  for (i = 0; i < _nbOrientations; ++i) {
129  res[i] = ComputeWeight(o2d2, i);
130  }
131  _mapping[id] = res;
132  return res;
133 }
134 
136 {
137  // soc unsigned res = 0;
138  real norm = dir.norm();
139  if (norm < 1.0e-6) {
140  return _nbOrientations + 1;
141  }
142  dir /= norm;
143  double maxw = 0.0f;
144  unsigned winner = _nbOrientations + 1;
145  for (unsigned int i = 0; i < _nbOrientations; ++i) {
146  double w = ComputeWeight(dir, i);
147  if (w > maxw) {
148  maxw = w;
149  winner = i;
150  }
151  }
152  return winner;
153 }
154 
155 unsigned SteerableViewMap::getSVMNumber(unsigned id)
156 {
157  map<unsigned int, double *>::iterator o = _mapping.find(id);
158  if (o != _mapping.end()) {
159  double *wvalues = (*o).second;
160  double maxw = 0.0;
161  unsigned winner = _nbOrientations + 1;
162  for (unsigned i = 0; i < _nbOrientations; ++i) {
163  double w = wvalues[i];
164  if (w > maxw) {
165  maxw = w;
166  winner = i;
167  }
168  }
169  return winner;
170  }
171  return _nbOrientations + 1;
172 }
173 
175  bool copy,
176  unsigned iNbLevels,
177  float iSigma)
178 {
179  for (unsigned int i = 0; i <= _nbOrientations; ++i) {
180  ImagePyramid *svm = (_imagesPyramids)[i];
181  delete svm;
182  if (copy) {
183  svm = new GaussianPyramid(*(steerableBases[i]), iNbLevels, iSigma);
184  }
185  else {
186  svm = new GaussianPyramid(steerableBases[i], iNbLevels, iSigma);
187  }
188  _imagesPyramids[i] = svm;
189  }
190 }
191 
192 float SteerableViewMap::readSteerableViewMapPixel(unsigned iOrientation, int iLevel, int x, int y)
193 {
194  ImagePyramid *pyramid = _imagesPyramids[iOrientation];
195  if (!pyramid) {
196  if (G.debug & G_DEBUG_FREESTYLE) {
197  cout << "Warning: this steerable ViewMap level doesn't exist" << endl;
198  }
199  return 0.0f;
200  }
201  if ((x < 0) || (x >= pyramid->width()) || (y < 0) || (y >= pyramid->height())) {
202  return 0;
203  }
204  // float v = pyramid->pixel(x, pyramid->height() - 1 - y, iLevel) * 255.0f;
205  // We encode both the directionality and the lines counting on 8 bits (because of frame buffer).
206  // Thus, we allow until 8 lines to pass through the same pixel, so that we can discretize the
207  // Pi/_nbOrientations angle into 32 slices. Therefore, for example, in the vertical direction, a
208  // vertical line will have the value 32 on each pixel it passes through.
209  float v = pyramid->pixel(x, pyramid->height() - 1 - y, iLevel) / 32.0f;
210  return v;
211 }
212 
213 float SteerableViewMap::readCompleteViewMapPixel(int iLevel, int x, int y)
214 {
215  return readSteerableViewMapPixel(_nbOrientations, iLevel, x, y);
216 }
217 
219 {
220  if (_imagesPyramids[0]) {
221  return _imagesPyramids[0]->getNumberOfLevels();
222  }
223  return 0;
224 }
225 
227 {
228  for (unsigned int i = 0; i <= _nbOrientations; ++i) {
229  if (_imagesPyramids[i] == nullptr) {
230  cerr << "SteerableViewMap warning: orientation " << i
231  << " of steerable View Map whas not been computed yet" << endl;
232  continue;
233  }
234  int ow = _imagesPyramids[i]->width(0);
235  int oh = _imagesPyramids[i]->height(0);
236 
237  // soc QString base("SteerableViewMap");
238  string base("SteerableViewMap");
239  stringstream filename;
240 
241  for (int j = 0; j < _imagesPyramids[i]->getNumberOfLevels(); ++j) { // soc
242  float coeff = 1.0f; // 1 / 255.0f; // 100 * 255; // * pow(2, j);
243  // soc QImage qtmp(ow, oh, QImage::Format_RGB32);
244  ImBuf *ibuf = IMB_allocImBuf(ow, oh, 32, IB_rect);
245  int rowbytes = ow * 4;
246  char *pix;
247 
248  for (int y = 0; y < oh; ++y) { // soc
249  for (int x = 0; x < ow; ++x) { // soc
250  int c = (int)(coeff * _imagesPyramids[i]->pixel(x, y, j));
251  if (c > 255) {
252  c = 255;
253  }
254  // int c = (int)(_imagesPyramids[i]->pixel(x, y, j));
255 
256  // soc qtmp.setPixel(x, y, qRgb(c, c, c));
257  pix = (char *)ibuf->rect + y * rowbytes + x * 4;
258  pix[0] = pix[1] = pix[2] = c;
259  }
260  }
261 
262  // soc qtmp.save(base+QString::number(i)+"-"+QString::number(j)+".png", "PNG");
263  filename << base;
264  filename << i << "-" << j << ".png";
265  ibuf->ftype = IMB_FTYPE_PNG;
266  IMB_saveiff(ibuf, const_cast<char *>(filename.str().c_str()), 0);
267  }
268 #if 0
269  QString base("SteerableViewMap");
270  for (unsigned j = 0; j < _imagesPyramids[i]->getNumberOfLevels(); ++j) {
271  GrayImage *img = _imagesPyramids[i]->getLevel(j);
272  int ow = img->width();
273  int oh = img->height();
274  float coeff = 1.0f; // 100 * 255; // * pow(2, j);
275  QImage qtmp(ow, oh, 32);
276  for (unsigned int y = 0; y < oh; ++y) {
277  for (unsigned int x = 0; x < ow; ++x) {
278  int c = (int)(coeff * img->pixel(x, y));
279  if (c > 255) {
280  c = 255;
281  }
282  //int c = (int)(_imagesPyramids[i]->pixel(x, y, j));
283  qtmp.setPixel(x, y, qRgb(c, c, c));
284  }
285  }
286  qtmp.save(base + QString::number(i) + "-" + QString::number(j) + ".png", "PNG");
287  }
288 #endif
289  }
290 }
291 
292 } /* namespace Freestyle */
@ G_DEBUG_FREESTYLE
Definition: BKE_global.h:181
#define M_PI
Definition: BLI_math_base.h:20
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
Definition: writeimage.c:22
Contains defines and structs used throughout the imbuf module.
@ IB_rect
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:483
Vec3r orientation2d() const
Definition: Silhouette.h:912
float pixel(unsigned x, unsigned y) const
id_type getFirst() const
Definition: Id.h:62
virtual float pixel(int x, int y, int level=0)
virtual int height(int level=0)
virtual int width(int level=0)
float readSteerableViewMapPixel(unsigned iOrientation, int iLevel, int x, int y)
unsigned getSVMNumber(Vec2f dir)
double * AddFEdge(FEdge *iFEdge)
float readCompleteViewMapPixel(int iLevel, int x, int y)
void buildImagesPyramids(GrayImage **steerableBases, bool copy=false, unsigned iNbLevels=4, float iSigma=1.0f)
SteerableViewMap(unsigned int nbOrientations=4)
double ComputeWeight(const Vec2d &dir, unsigned iNOrientation)
unsigned int getNumberOfPyramidLevels() const
map< unsigned int, double * > _mapping
value_type x() const
Definition: VecMat.h:518
value_type y() const
Definition: VecMat.h:528
value_type norm() const
Definition: VecMat.h:95
@ IMB_FTYPE_PNG
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
#define G(x, y, z)
inherits from class Rep
Definition: AppCanvas.cpp:18
static unsigned c
Definition: RandGen.cpp:83
static unsigned x[3]
Definition: RandGen.cpp:73
double real
Definition: Precision.h:12
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
INLINE Rall1d< T, V, S > acos(const Rall1d< T, V, S > &x)
Definition: rall1d.h:399
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:311
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
enum eImbFileType ftype
unsigned int * rect