1 /*
2  */
3 
4 /*
5 
6     Copyright (C) 2014 Ferrero Andrea
7 
8     This program is free software: you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21 
22  */
23 
24 /*
25 
26     These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
27 
28  */
29 
30 #ifndef BLUR_BILATERAL_H
31 #define BLUR_BILATERAL_H
32 
33 #include <assert.h>
34 #include <string>
35 
36 #include "../base/processor.hh"
37 extern "C" {
38 #include "../external/darktable/src/common/bilateral.h"
39 }
40 
41 
42 namespace PF
43 {
44 
45 #include "blur_bilateral_splat.hh"
46 #include "blur_bilateral_blur.hh"
47 #include "blur_bilateral_slice.hh"
48 
49 
50 class BlurBilateralAlgoPar: public OpParBase
51 {
52   Property<float> sigma_s;
53   Property<float> sigma_r;
54   float ss, sr;
55 
56   int cur_padding;
57 
58 public:
59   BlurBilateralAlgoPar();
60 
61   //void set_iterations( int i ) { iterations.set( i ); }
set_sigma_s(float s)62   void set_sigma_s( float s ) { sigma_s.set( s ); }
set_sigma_r(float s)63   void set_sigma_r( float s ) { sigma_r.set( s ); }
64 
get_ss()65   float get_ss() { return ss; }
get_sr()66   float get_sr() { return sr; }
67 
get_sigma_s()68   float get_sigma_s() { return sigma_s.get(); }
get_sigma_r()69   float get_sigma_r() { return sigma_r.get(); }
70 
has_intensity()71   bool has_intensity() { return false; }
has_opacity()72   bool has_opacity() { return true; }
needs_caching()73   bool needs_caching() { return true; }
74 
compute_padding(VipsImage * full_res,unsigned int id,unsigned int level)75   void compute_padding( VipsImage* full_res, unsigned int id, unsigned int level )
76   {
77     float ss = sigma_s.get();
78     for( int l = 1; l <= level; l++ ) {
79       ss /= 2;
80     }
81     int iss = static_cast<int>(ss*3);
82     //iss /= 16;
83     //iss = (iss+1)*16;
84     iss = 2;
85     set_padding( iss, id );
86     std::cout<<"BlurBilateralAlgoPar()::compute_padding(): sigma_s="<<sigma_s.get()
87         <<"  level="<<level<<"  ss="<<ss<<"  iss="<<iss<<"  padding="<<get_padding(id)<<std::endl;
88   }
89 
90   /* Function to derive the output area from the input area
91    */
transform(const VipsRect * rin,VipsRect * rout,int)92   virtual void transform(const VipsRect* rin, VipsRect* rout, int /*id*/)
93   {
94     int pad = get_padding(0);
95     rout->left = rin->left+pad;
96     rout->top = rin->top+pad;
97     rout->width = rin->width-pad*2;
98     rout->height = rin->height-pad*2;
99   }
100 
101   /* Function to derive the area to be read from input images,
102      based on the requested output area
103   */
transform_inv(const VipsRect * rout,VipsRect * rin,int)104   virtual void transform_inv(const VipsRect* rout, VipsRect* rin, int /*id*/)
105   {
106     int pad = get_padding(0);
107     rin->left = rout->left-pad;
108     rin->top = rout->top-pad;
109     rin->width = rout->width+pad*2;
110     rin->height = rout->height+pad*2;
111   }
112 
113   VipsImage* build(std::vector<VipsImage*>& in, int first,
114       VipsImage* imap, VipsImage* omap,
115       unsigned int& level);
116 };
117 
118 
119 
120 template < OP_TEMPLATE_DEF >
121 class BlurBilateralAlgoProc
122 {
123 public:
render(VipsRegion ** ireg,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * oreg,OpParBase * par)124   void render(VipsRegion** ireg, int n, int in_first,
125       VipsRegion* imap, VipsRegion* omap,
126       VipsRegion* oreg, OpParBase* par)
127   {
128     std::cout<<"BlurBilateralAlgoProc::render() called"<<std::endl;
129   }
130 };
131 
132 template < OP_TEMPLATE_DEF_CS_SPEC >
133 class BlurBilateralAlgoProc< OP_TEMPLATE_IMP_CS_SPEC(PF_COLORSPACE_GRAYSCALE) >
134 {
135 public:
render(VipsRegion ** ireg,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * oreg,OpParBase * par)136   void render(VipsRegion** ireg, int n, int in_first,
137       VipsRegion* imap, VipsRegion* omap,
138       VipsRegion* oreg, OpParBase* par)
139   {
140     if( ireg[0] == NULL ) return;
141 
142     BlurBilateralAlgoPar* opar = dynamic_cast<BlurBilateralAlgoPar*>(par);
143     if( !opar ) return;
144 
145     VipsRect *r = &oreg->valid;
146     int width = r->width;
147     int height = r->height;
148     int y;
149     VipsImage* srcimg = ireg[0]->im;
150 
151     if( false && r->left<10000 && r->top<10000 ) {
152       std::cout<<"BlurBilateralAlgoProc::render(): ireg="<<ireg[0]->valid.width<<"x"<<ireg[0]->valid.height
153           <<"+"<<ireg[0]->valid.left<<","<<ireg[0]->valid.top<<std::endl;
154       std::cout<<"                                 oreg="<<r->width<<"x"<<r->height<<"+"<<r->left<<","<<r->top<<std::endl;
155     }
156 
157     T* obuf = (T*)malloc( ireg[0]->valid.width * ireg[0]->valid.height * sizeof(T) );
158     if(!obuf) return;
159 
160     T* pin = (T*)VIPS_REGION_ADDR( ireg[0], ireg[0]->valid.left, ireg[0]->valid.top );
161     T* pout;
162     T* p;
163 
164     int verb = 0;
165     //if(ireg[0]->valid.left==0 && ireg[0]->valid.top==0) verb = 1;
166     dt_bilateral_t* dt_b = dt_bilateral_init(ireg[0]->valid.width, ireg[0]->valid.height,
167         opar->get_ss(), opar->get_sr(), verb);
168     dt_b->buf = (float*)malloc(dt_b->size_x * dt_b->size_y * dt_b->size_z * sizeof(float));
169     memset(dt_b->buf, 0, dt_b->size_x * dt_b->size_y * dt_b->size_z * sizeof(float));
170 
171     int ilskip = VIPS_REGION_LSKIP( ireg[0] ) / sizeof(T);
172     int lskip = dt_b->size_x * dt_b->size_z;
173     int olskip = VIPS_REGION_LSKIP( oreg ) / sizeof(T);
174 
175     dt_bilateral_splat(dt_b, pin, ilskip, lskip, verb);
176     dt_bilateral_blur(dt_b);
177     dt_bilateral_slice(dt_b, pin, obuf, ilskip, lskip, olskip, -1);
178     dt_bilateral_free(dt_b);
179     int dx = r->left - ireg[0]->valid.left;
180     int dy = r->top - ireg[0]->valid.top;
181 
182     for( y = 0; y < height; y++ ) {
183       p = obuf + (y+dy)*ireg[0]->valid.width + dx;
184       pout = (T*)VIPS_REGION_ADDR( oreg, r->left, r->top + y );
185       memcpy(pout, p, sizeof(T)*width );
186     }
187     free(dt_b->buf);
188     free(obuf);
189   }
190 };
191 
192 
193 
194 
195 
196 class BlurBilateralPar: public OpParBase
197 {
198   Property<float> sigma_s;
199   Property<float> sigma_r;
200   ProcessorBase* bsplat;
201   ProcessorBase* blur;
202   ProcessorBase* slice;
203   ProcessorBase* balgo;
204 
205 public:
206   BlurBilateralPar();
207 
has_intensity()208   bool has_intensity() { return false; }
has_opacity()209   bool has_opacity() { return true; }
needs_caching()210   bool needs_caching() { return false; }
211 
212   void set_sigma_s( float s );
213   void set_sigma_r( float s );
get_sigma_s()214   float get_sigma_s() { return sigma_s.get(); }
get_sigma_r()215   float get_sigma_r() { return sigma_r.get(); }
216 
compute_padding(VipsImage * full_res,unsigned int id,unsigned int level)217   void compute_padding( VipsImage* full_res, unsigned int id, unsigned int level )
218   {
219     //g_assert(balgo->get_par() != NULL);
220     //balgo->get_par()->compute_padding(full_res, id, level);
221     //set_padding( balgo->get_par()->get_padding(id), id );
222     float ss;
223     ss = sigma_s.get();
224     for( int l = 1; l <= level; l++ ) {
225       ss /= 2;
226     }
227     ss = roundf(ss); //ss = 100;
228     int iss = ss;
229     if(iss < 1) iss = 1;
230 
231     set_padding( 5*iss, id );
232     //std::cout<<"BlurBilateralPar()::compute_padding(): padding="<<get_padding(id)<<std::endl;
233   }
234 
235   VipsImage* build(std::vector<VipsImage*>& in, int first,
236       VipsImage* imap, VipsImage* omap,
237       unsigned int& level);
238 
239   VipsImage* build_(std::vector<VipsImage*>& in, int first,
240       VipsImage* imap, VipsImage* omap,
241       unsigned int& level);
242 };
243 
244 
245 
246 template < OP_TEMPLATE_DEF >
247 class BlurBilateralProc
248 {
249 public:
render(VipsRegion ** ireg,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * oreg,OpParBase * par)250   void render(VipsRegion** ireg, int n, int in_first,
251       VipsRegion* imap, VipsRegion* omap,
252       VipsRegion* oreg, OpParBase* par)
253   {
254   }
255 };
256 
257 
258 
259 template < OP_TEMPLATE_DEF_CS_SPEC >
260 class BlurBilateralProc< OP_TEMPLATE_IMP_CS_SPEC(PF_COLORSPACE_GRAYSCALE) >
261 {
262 public:
render(VipsRegion ** ireg,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * oreg,OpParBase * par)263   void render(VipsRegion** ireg, int n, int in_first,
264       VipsRegion* imap, VipsRegion* omap,
265       VipsRegion* oreg, OpParBase* par)
266   {
267     if( ireg[0] == NULL ) return;
268 
269     BlurBilateralPar* opar = dynamic_cast<BlurBilateralPar*>(par);
270     if( !opar ) return;
271 
272     VipsRect *r = &oreg->valid;
273     int width = r->width;
274     int height = r->height;
275     int y;
276     VipsImage* srcimg = ireg[0]->im;
277 
278     if( false && r->left<10000 && r->top<10000 ) {
279       std::cout<<"BlurBilateralProc::render(): ireg="<<ireg[0]->valid.width<<"x"<<ireg[0]->valid.height
280           <<"+"<<ireg[0]->valid.left<<","<<ireg[0]->valid.top<<std::endl;
281       std::cout<<"                                 oreg="<<r->width<<"x"<<r->height<<"+"<<r->left<<","<<r->top<<std::endl;
282     }
283 
284     T* pin;
285     T* pout;
286     for( y = 0; y < height; y++ ) {
287       pin = (T*)VIPS_REGION_ADDR( ireg[0], r->left, r->top + y );
288       pout = (T*)VIPS_REGION_ADDR( oreg, r->left, r->top + y );
289       memcpy(pout, pin, sizeof(T)*width );
290     }
291   }
292 };
293 
294 
295 ProcessorBase* new_blur_bilateral();
296 }
297 
298 #endif
299 
300 
301