Merged changes in the trunk up to revision 28600.
[blender.git] / source / blender / freestyle / intern / view_map / SteerableViewMap.cpp
1 //
2 //  Copyright (C) : Please refer to the COPYRIGHT file distributed 
3 //   with this source distribution. 
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License
7 //  as published by the Free Software Foundation; either version 2
8 //  of the License, or (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 //
19 ///////////////////////////////////////////////////////////////////////////////
20
21 #include "Silhouette.h"
22 #include "SteerableViewMap.h"
23 #include "../image/ImagePyramid.h"
24 #include "../image/Image.h"
25 #include <math.h>
26 #include "../geometry/Geom.h"
27 using namespace Geometry;
28
29 //soc #include <qstring.h>
30 //soc #include <qimage.h>
31 #include <sstream>
32
33 extern "C" {
34 #include "IMB_imbuf.h"
35 #include "IMB_imbuf_types.h"
36 #include "intern/IMB_png.h"
37 }
38
39 SteerableViewMap::SteerableViewMap(unsigned int nbOrientations){
40   _nbOrientations = nbOrientations;
41   _bound = cos(M_PI/(float)_nbOrientations);
42   for(unsigned i=0; i<_nbOrientations; ++i){
43     _directions.push_back(Vec2d(cos((float)i*M_PI/(float)_nbOrientations), sin((float)i*M_PI/(float)_nbOrientations)));
44   }
45   Build();
46 }
47
48 void SteerableViewMap::Build(){
49   _imagesPyramids = new ImagePyramid*[_nbOrientations+1]; // one more map to store the complete visible VM
50   memset((_imagesPyramids),0,(_nbOrientations+1)*sizeof(ImagePyramid*));
51 }
52
53 SteerableViewMap::SteerableViewMap(const SteerableViewMap& iBrother){
54   _nbOrientations = iBrother._nbOrientations;
55   unsigned i;
56   _bound = iBrother._bound;
57   _directions = iBrother._directions;
58   _mapping = iBrother._mapping;
59   _imagesPyramids = new ImagePyramid*[_nbOrientations+1]; // one more map to store the complete visible VM
60   for(i=0;i<_nbOrientations+1;++i)
61     _imagesPyramids[i] = new GaussianPyramid(*(dynamic_cast<GaussianPyramid*>(iBrother._imagesPyramids[i])));
62 }
63
64 SteerableViewMap::~SteerableViewMap(){
65   Clear(); 
66 }
67
68 void SteerableViewMap::Clear(){
69   unsigned i;
70   if(_imagesPyramids){
71     for(i=0; i<=_nbOrientations; ++i){
72       if(_imagesPyramids[i])
73         delete (_imagesPyramids)[i];
74     } 
75     delete [] _imagesPyramids;
76     _imagesPyramids = 0;
77   } 
78   if(!_mapping.empty()){
79     for(map<unsigned int, double*>::iterator m=_mapping.begin(), mend=_mapping.end(); 
80     m!=mend;
81     ++m){
82       delete [] (*m).second;
83     }
84     _mapping.clear();
85   }
86 }
87
88 void SteerableViewMap::Reset(){
89   Clear();
90   Build();
91 }
92
93 double SteerableViewMap::ComputeWeight(const Vec2d& dir, unsigned i){ 
94   double dotp = fabs(dir*_directions[i]);
95   if(dotp < _bound)
96     return 0;
97   if(dotp>1)
98     dotp = 1;
99
100   return cos((float)_nbOrientations/2.0*acos(dotp));
101 }
102
103 double * SteerableViewMap::AddFEdge(FEdge *iFEdge){
104   unsigned i;
105   unsigned id = iFEdge->getId().getFirst();
106   map<unsigned int, double* >::iterator o = _mapping.find(id);
107   if(o!=_mapping.end()){
108     return (*o).second;
109   }
110   double * res = new double[_nbOrientations];
111   for(i=0; i<_nbOrientations; ++i){
112     res[i] = 0;
113   }
114   Vec3r o2d3 = iFEdge->orientation2d();
115   Vec2r o2d2(o2d3.x(), o2d3.y());
116   real norm = o2d2.norm();
117   if(norm < 1e-6){
118     return res;
119   }
120   o2d2/=norm;
121
122   for(i=0; i<_nbOrientations; ++i){
123     res[i] = ComputeWeight(o2d2, i);
124   }
125   _mapping[id] = res;
126   return res;
127 }
128
129 unsigned SteerableViewMap::getSVMNumber(const Vec2f& orient){
130   Vec2f dir(orient);
131   //soc unsigned res = 0;
132   real norm = dir.norm();
133   if(norm < 1e-6){
134     return _nbOrientations+1;
135   }
136   dir/=norm;
137   double maxw = 0.f; 
138   unsigned winner = _nbOrientations+1;
139   for(unsigned i=0; i<_nbOrientations; ++i){
140     double w = ComputeWeight(dir, i);
141     if(w>maxw){
142       maxw = w;
143       winner = i;
144     }
145   }
146   return winner;
147 }
148
149
150 unsigned SteerableViewMap::getSVMNumber(unsigned id){
151   map<unsigned int, double* >::iterator o = _mapping.find(id);
152   if(o!=_mapping.end()){
153     double* wvalues=  (*o).second;
154     double maxw = 0.f; 
155     unsigned winner = _nbOrientations+1;
156     for(unsigned i=0; i<_nbOrientations; ++i){
157       double w = wvalues[i];
158       if(w>maxw){
159         maxw = w;
160         winner = i;
161       } 
162     }  
163     return winner;
164   }
165   return _nbOrientations+1;
166 }
167
168 void SteerableViewMap::buildImagesPyramids(GrayImage **steerableBases, bool copy, unsigned iNbLevels, float iSigma){
169   for(unsigned i=0; i<=_nbOrientations; ++i){
170     ImagePyramid * svm = (_imagesPyramids)[i];
171     if(svm)
172       delete svm;
173     if(copy)
174       svm = new GaussianPyramid(*(steerableBases[i]), iNbLevels, iSigma);
175     else
176       svm = new GaussianPyramid(steerableBases[i], iNbLevels, iSigma);
177     _imagesPyramids[i] = svm;
178   }
179 }
180
181 float SteerableViewMap::readSteerableViewMapPixel(unsigned iOrientation, int iLevel, int x, int y){
182   ImagePyramid *pyramid = _imagesPyramids[iOrientation];
183   if(pyramid==0){
184     cout << "Warning: this steerable ViewMap level doesn't exist" << endl;
185     return 0;
186   }
187   if((x<0) || (x>=pyramid->width()) || (y<0) || (y>=pyramid->height()))
188     return 0;
189   //float v = pyramid->pixel(x,pyramid->height()-1-y,iLevel)*255.f;
190   float v = pyramid->pixel(x,pyramid->height()-1-y,iLevel)/32.f; // we encode both the directionality and the lines counting on 8 bits 
191                                                                  // (because of frame buffer). Thus, we allow until 8 lines to pass through
192                                                                  // the same pixel, so that we can discretize the Pi/_nbOrientations angle into 
193                                                                  // 32 slices. Therefore, for example, in the vertical direction, a vertical line
194                                                                  // will have the value 32 on each pixel it passes through.
195   return v;
196 }
197
198 float SteerableViewMap::readCompleteViewMapPixel(int iLevel, int x, int y){
199   return readSteerableViewMapPixel(_nbOrientations,iLevel,x,y);
200 }
201
202 unsigned int SteerableViewMap::getNumberOfPyramidLevels() const{
203   if(_imagesPyramids[0])
204     return _imagesPyramids[0]->getNumberOfLevels();
205   return 0;
206 }
207
208 void SteerableViewMap::saveSteerableViewMap() const {
209   for(unsigned i=0; i<=_nbOrientations; ++i){
210     if(_imagesPyramids[i] == 0){
211       cerr << "SteerableViewMap warning: orientation " << i <<" of steerable View Map whas not been computed yet" << endl;
212       continue;
213     }
214     int ow = _imagesPyramids[i]->width(0);
215     int oh = _imagesPyramids[i]->height(0);
216
217     //soc QString base("SteerableViewMap");
218         string base("SteerableViewMap");
219         stringstream filename;
220         
221     for(int j=0; j<_imagesPyramids[i]->getNumberOfLevels(); ++j){ //soc
222       float coeff = 1;//1/255.f; //100*255;//*pow(2,j);
223           //soc QImage qtmp(ow, oh, QImage::Format_RGB32);
224           ImBuf *ibuf = IMB_allocImBuf(ow, oh, 32, IB_rect, 0);
225           int rowbytes = ow*4;
226           char *pix;
227       
228         for(int y=0;y<oh;++y){ //soc
229                 for(int x=0;x<ow;++x){ //soc
230           int c = (int)(coeff*_imagesPyramids[i]->pixel(x,y,j));
231           if(c>255)
232             c=255;
233           //int c = (int)(_imagesPyramids[i]->pixel(x,y,j));
234           
235                 //soc qtmp.setPixel(x,y,qRgb(c,c,c));
236                   pix = (char*)ibuf->rect + y*rowbytes + x*4;
237                 pix[0] = pix [1] = pix[2] = c;
238         }
239       }
240
241       //soc qtmp.save(base+QString::number(i)+"-"+QString::number(j)+".png", "PNG");
242         filename << base;
243         filename << i << "-" << j << ".png";
244         
245         imb_savepng(ibuf, const_cast<char *>(filename.str().c_str()), 0);
246         
247     }
248     //    QString base("SteerableViewMap");
249     //    for(unsigned j=0; j<_imagesPyramids[i]->getNumberOfLevels(); ++j){
250     //      GrayImage * img = _imagesPyramids[i]->getLevel(j);
251     //      int ow = img->width();
252     //      int oh = img->height();
253     //      float coeff = 1; //100*255;//*pow(2,j);
254     //      QImage qtmp(ow, oh, 32);
255     //      for(unsigned y=0;y<oh;++y){
256     //        for(unsigned x=0;x<ow;++x){
257     //          int c = (int)(coeff*img->pixel(x,y));
258     //          if(c>255)
259     //            c=255;
260     //          //int c = (int)(_imagesPyramids[i]->pixel(x,y,j));
261     //          qtmp.setPixel(x,y,qRgb(c,c,c));
262     //        }
263     //      }
264     //      qtmp.save(base+QString::number(i)+"-"+QString::number(j)+".png", "PNG");
265     //    }
266     //    
267   }
268 }