Blender  V2.93
SteerableViewMap.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
23 #include <sstream>
24 
25 #include "Silhouette.h"
26 #include "SteerableViewMap.h"
27 
28 #include "../geometry/Geom.h"
29 
30 #include "../image/Image.h"
31 #include "../image/ImagePyramid.h"
32 
33 #include "BKE_global.h"
34 #include "BLI_math.h"
35 
36 #include "IMB_imbuf.h"
37 #include "IMB_imbuf_types.h"
38 
39 namespace Freestyle {
40 
41 using namespace Geometry;
42 
43 SteerableViewMap::SteerableViewMap(unsigned int nbOrientations)
44 {
45  _nbOrientations = nbOrientations;
46  _bound = cos(M_PI / (float)_nbOrientations);
47  for (unsigned int i = 0; i < _nbOrientations; ++i) {
48  _directions.emplace_back(cos((float)i * M_PI / (float)_nbOrientations),
49  sin((float)i * M_PI / (float)_nbOrientations));
50  }
51  Build();
52 }
53 
55 {
56  _imagesPyramids =
57  new ImagePyramid *[_nbOrientations + 1]; // one more map to store the complete visible VM
58  memset((_imagesPyramids), 0, (_nbOrientations + 1) * sizeof(ImagePyramid *));
59 }
60 
62 {
63  _nbOrientations = iBrother._nbOrientations;
64  unsigned int i;
65  _bound = iBrother._bound;
66  _directions = iBrother._directions;
67  _mapping = iBrother._mapping;
68  _imagesPyramids =
69  new ImagePyramid *[_nbOrientations + 1]; // one more map to store the complete visible VM
70  for (i = 0; i <= _nbOrientations; ++i) {
71  _imagesPyramids[i] = new GaussianPyramid(
72  *(dynamic_cast<GaussianPyramid *>(iBrother._imagesPyramids[i])));
73  }
74 }
75 
77 {
78  Clear();
79 }
80 
82 {
83  unsigned int i;
84  if (_imagesPyramids) {
85  for (i = 0; i <= _nbOrientations; ++i) {
86  if (_imagesPyramids[i]) {
87  delete (_imagesPyramids)[i];
88  }
89  }
90  delete[] _imagesPyramids;
91  _imagesPyramids = nullptr;
92  }
93  if (!_mapping.empty()) {
94  for (map<unsigned int, double *>::iterator m = _mapping.begin(), mend = _mapping.end();
95  m != mend;
96  ++m) {
97  delete[](*m).second;
98  }
99  _mapping.clear();
100  }
101 }
102 
104 {
105  Clear();
106  Build();
107 }
108 
109 double SteerableViewMap::ComputeWeight(const Vec2d &dir, unsigned i)
110 {
111  double dotp = fabs(dir * _directions[i]);
112  if (dotp < _bound) {
113  return 0.0;
114  }
115  if (dotp > 1.0) {
116  dotp = 1.0;
117  }
118 
119  return cos((float)_nbOrientations / 2.0 * acos(dotp));
120 }
121 
123 {
124  unsigned i;
125  unsigned id = iFEdge->getId().getFirst();
126  map<unsigned int, double *>::iterator o = _mapping.find(id);
127  if (o != _mapping.end()) {
128  return (*o).second;
129  }
130  double *res = new double[_nbOrientations];
131  for (i = 0; i < _nbOrientations; ++i) {
132  res[i] = 0.0;
133  }
134  Vec3r o2d3 = iFEdge->orientation2d();
135  Vec2r o2d2(o2d3.x(), o2d3.y());
136  real norm = o2d2.norm();
137  if (norm < 1.0e-6) {
138  return res;
139  }
140  o2d2 /= norm;
141 
142  for (i = 0; i < _nbOrientations; ++i) {
143  res[i] = ComputeWeight(o2d2, i);
144  }
145  _mapping[id] = res;
146  return res;
147 }
148 
150 {
151  // soc unsigned res = 0;
152  real norm = dir.norm();
153  if (norm < 1.0e-6) {
154  return _nbOrientations + 1;
155  }
156  dir /= norm;
157  double maxw = 0.0f;
158  unsigned winner = _nbOrientations + 1;
159  for (unsigned int i = 0; i < _nbOrientations; ++i) {
160  double w = ComputeWeight(dir, i);
161  if (w > maxw) {
162  maxw = w;
163  winner = i;
164  }
165  }
166  return winner;
167 }
168 
169 unsigned SteerableViewMap::getSVMNumber(unsigned id)
170 {
171  map<unsigned int, double *>::iterator o = _mapping.find(id);
172  if (o != _mapping.end()) {
173  double *wvalues = (*o).second;
174  double maxw = 0.0;
175  unsigned winner = _nbOrientations + 1;
176  for (unsigned i = 0; i < _nbOrientations; ++i) {
177  double w = wvalues[i];
178  if (w > maxw) {
179  maxw = w;
180  winner = i;
181  }
182  }
183  return winner;
184  }
185  return _nbOrientations + 1;
186 }
187 
189  bool copy,
190  unsigned iNbLevels,
191  float iSigma)
192 {
193  for (unsigned int i = 0; i <= _nbOrientations; ++i) {
194  ImagePyramid *svm = (_imagesPyramids)[i];
195  delete svm;
196  if (copy) {
197  svm = new GaussianPyramid(*(steerableBases[i]), iNbLevels, iSigma);
198  }
199  else {
200  svm = new GaussianPyramid(steerableBases[i], iNbLevels, iSigma);
201  }
202  _imagesPyramids[i] = svm;
203  }
204 }
205 
206 float SteerableViewMap::readSteerableViewMapPixel(unsigned iOrientation, int iLevel, int x, int y)
207 {
208  ImagePyramid *pyramid = _imagesPyramids[iOrientation];
209  if (!pyramid) {
210  if (G.debug & G_DEBUG_FREESTYLE) {
211  cout << "Warning: this steerable ViewMap level doesn't exist" << endl;
212  }
213  return 0.0f;
214  }
215  if ((x < 0) || (x >= pyramid->width()) || (y < 0) || (y >= pyramid->height())) {
216  return 0;
217  }
218  // float v = pyramid->pixel(x, pyramid->height() - 1 - y, iLevel) * 255.0f;
219  // We encode both the directionality and the lines counting on 8 bits (because of frame buffer).
220  // Thus, we allow until 8 lines to pass through the same pixel, so that we can discretize the
221  // Pi/_nbOrientations angle into 32 slices. Therefore, for example, in the vertical direction, a
222  // vertical line will have the value 32 on each pixel it passes through.
223  float v = pyramid->pixel(x, pyramid->height() - 1 - y, iLevel) / 32.0f;
224  return v;
225 }
226 
227 float SteerableViewMap::readCompleteViewMapPixel(int iLevel, int x, int y)
228 {
229  return readSteerableViewMapPixel(_nbOrientations, iLevel, x, y);
230 }
231 
233 {
234  if (_imagesPyramids[0]) {
235  return _imagesPyramids[0]->getNumberOfLevels();
236  }
237  return 0;
238 }
239 
241 {
242  for (unsigned int i = 0; i <= _nbOrientations; ++i) {
243  if (_imagesPyramids[i] == nullptr) {
244  cerr << "SteerableViewMap warning: orientation " << i
245  << " of steerable View Map whas not been computed yet" << endl;
246  continue;
247  }
248  int ow = _imagesPyramids[i]->width(0);
249  int oh = _imagesPyramids[i]->height(0);
250 
251  // soc QString base("SteerableViewMap");
252  string base("SteerableViewMap");
253  stringstream filename;
254 
255  for (int j = 0; j < _imagesPyramids[i]->getNumberOfLevels(); ++j) { // soc
256  float coeff = 1.0f; // 1 / 255.0f; // 100 * 255; // * pow(2, j);
257  // soc QImage qtmp(ow, oh, QImage::Format_RGB32);
258  ImBuf *ibuf = IMB_allocImBuf(ow, oh, 32, IB_rect);
259  int rowbytes = ow * 4;
260  char *pix;
261 
262  for (int y = 0; y < oh; ++y) { // soc
263  for (int x = 0; x < ow; ++x) { // soc
264  int c = (int)(coeff * _imagesPyramids[i]->pixel(x, y, j));
265  if (c > 255) {
266  c = 255;
267  }
268  // int c = (int)(_imagesPyramids[i]->pixel(x, y, j));
269 
270  // soc qtmp.setPixel(x, y, qRgb(c, c, c));
271  pix = (char *)ibuf->rect + y * rowbytes + x * 4;
272  pix[0] = pix[1] = pix[2] = c;
273  }
274  }
275 
276  // soc qtmp.save(base+QString::number(i)+"-"+QString::number(j)+".png", "PNG");
277  filename << base;
278  filename << i << "-" << j << ".png";
279  ibuf->ftype = IMB_FTYPE_PNG;
280  IMB_saveiff(ibuf, const_cast<char *>(filename.str().c_str()), 0);
281  }
282 #if 0
283  QString base("SteerableViewMap");
284  for (unsigned j = 0; j < _imagesPyramids[i]->getNumberOfLevels(); ++j) {
285  GrayImage *img = _imagesPyramids[i]->getLevel(j);
286  int ow = img->width();
287  int oh = img->height();
288  float coeff = 1.0f; // 100 * 255; // * pow(2, j);
289  QImage qtmp(ow, oh, 32);
290  for (unsigned int y = 0; y < oh; ++y) {
291  for (unsigned int x = 0; x < ow; ++x) {
292  int c = (int)(coeff * img->pixel(x, y));
293  if (c > 255) {
294  c = 255;
295  }
296  //int c = (int)(_imagesPyramids[i]->pixel(x, y, j));
297  qtmp.setPixel(x, y, qRgb(c, c, c));
298  }
299  }
300  qtmp.save(base + QString::number(i) + "-" + QString::number(j) + ".png", "PNG");
301  }
302 #endif
303  }
304 }
305 
306 } /* namespace Freestyle */
@ G_DEBUG_FREESTYLE
Definition: BKE_global.h:140
#define M_PI
Definition: BLI_math_base.h:38
_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:478
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
Definition: writeimage.c:44
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:497
Vec3r orientation2d() const
Definition: Silhouette.h:926
float pixel(unsigned x, unsigned y) const
id_type getFirst() const
Definition: Id.h:76
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:532
value_type y() const
Definition: VecMat.h:542
value_type norm() const
Definition: VecMat.h:109
@ IMB_FTYPE_PNG
inherits from class Rep
Definition: AppCanvas.cpp:32
static unsigned c
Definition: RandGen.cpp:97
static unsigned x[3]
Definition: RandGen.cpp:87
double real
Definition: Precision.h:26
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
ccl_device_inline float2 fabs(const float2 &a)
#define G(x, y, z)