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 PF_GUIDED_FILTER_H
31 #define PF_GUIDED_FILTER_H
32 
33 #include "../base/operation.hh"
34 
35 #include "padded_op.hh"
36 
37 namespace PF
38 {
39 
40 class GuidedFilterPar: public PaddedOpPar
41 {
42   Property<float> radius;
43   float radius_real;
44   Property<float> threshold;
45   Property<int> subsampling;
46   int subsampling_real;
47 
48   ICCProfile* icc_data;
49   Property<bool> convert_to_perceptual;
50 public:
51   GuidedFilterPar();
52 
get_icc_data()53   ICCProfile* get_icc_data() { return icc_data; }
54 
has_intensity()55   bool has_intensity() { return false; }
56   bool needs_caching();
set_convert_to_perceptual(bool val)57   void set_convert_to_perceptual(bool val) { convert_to_perceptual.set(val); }
get_convert_to_perceptual()58   bool get_convert_to_perceptual() { return convert_to_perceptual.get(); }
59 
set_radius(float r)60   void set_radius(float r) { radius.set(r); }
get_radius()61   float get_radius() { return radius_real; }
set_threshold(float t)62   void set_threshold(float t) { threshold.set(t); }
get_threshold()63   float get_threshold() { return threshold.get(); }
64 
set_subsampling(int s)65   void set_subsampling(int s) { subsampling.set(s); }
get_subsampling()66   int get_subsampling() { return subsampling_real; }
67 
68   void compute_padding( VipsImage* full_res, unsigned int id, unsigned int level );
69 
70   VipsImage* build(std::vector<VipsImage*>& in, int first,
71       VipsImage* imap, VipsImage* omap,
72       unsigned int& level);
73 };
74 
75 
76 
77 template < OP_TEMPLATE_DEF >
78 class GuidedFilterProc
79 {
80 public:
render(VipsRegion ** in,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * out,OpParBase * par)81   void render(VipsRegion** in, int n, int in_first,
82       VipsRegion* imap, VipsRegion* omap,
83       VipsRegion* out, OpParBase* par)
84   {
85   }
86 };
87 
88 
89 void guidedFilter(const PixelMatrix<float> &guide, const PixelMatrix<float> &src,
90     PixelMatrix<float> &dst, int r, float epsilon, int subsampling);
91 
92 
93 void guidedFilter(const PixelMatrix<float> &src, PixelMatrix<float> &dst,
94     int r, float epsilon, int subsampling);
95 
96 
97 template < OP_TEMPLATE_DEF_TYPE_SPEC >
98 class GuidedFilterProc< OP_TEMPLATE_IMP_TYPE_SPEC(float) >
99 {
100   ICCProfile* profile;
101   GuidedFilterPar* opar;
102 
fill_L_matrices(int rw,int rh,PixelMatrix<float> & rgbin,PixelMatrix<float> & guidein,PixelMatrix<float> & Lin,PixelMatrix<float> & Lguide)103   void fill_L_matrices(int rw, int rh, PixelMatrix<float>& rgbin, PixelMatrix<float>& guidein,
104       PixelMatrix<float>& Lin, PixelMatrix<float>& Lguide)
105   {
106     int x, y, z;
107 
108     for(y = 0; y < rh; y++) {
109       float* row = rgbin[y];
110       float* rowg = guidein[y];
111       float* L = Lin[y];
112       float* Lg = Lguide[y];
113       for( x = 0; x < rw; x++ ) {
114         //std::cout<<"  y="<<y<<"  x="<<x<<"  row="<<row<<"  rr="<<rr<<"  gr="<<gr<<"  br="<<br<<std::endl;
115         //if(x==0 && y==0) std::cout<<"  row="<<row[0]<<" "<<row[1]<<" "<<row[2]<<std::endl;
116         if( opar->get_convert_to_perceptual() &&
117             profile && profile->is_linear() ) {
118           //*L = (row[0]>0) ? powf( row[0], 1./2.4 ) : row[0];
119           *L = (row[0]>1.0e-16) ? log10( row[0] ) : -16;
120           *Lg = (rowg[0]>1.0e-16) ? log10( rowg[0] ) : -16;
121         } else {
122           *L = row[0];
123           *Lg = rowg[0];
124         }
125         //*Lg = *L;
126 
127         row += 1;
128         rowg += 1;
129         L += 1;
130         Lg += 1;
131       }
132     }
133   }
134 
fill_L_matrices(int rw,int rh,PixelMatrix<float> & rgbin,PixelMatrix<float> & Lin)135   void fill_L_matrices(int rw, int rh, PixelMatrix<float>& rgbin, PixelMatrix<float>& Lin)
136   {
137     int x, y, z;
138 
139     for(y = 0; y < rh; y++) {
140       float* row = rgbin[y];
141       float* L = Lin[y];
142       for( x = 0; x < rw; x++ ) {
143         //std::cout<<"  y="<<y<<"  x="<<x<<"  row="<<row<<"  rr="<<rr<<"  gr="<<gr<<"  br="<<br<<std::endl;
144         //if(x==0 && y==0) std::cout<<"  row="<<row[0]<<" "<<row[1]<<" "<<row[2]<<std::endl;
145         if( opar->get_convert_to_perceptual() &&
146             profile && profile->is_linear() ) {
147           //*L = (row[0]>0) ? powf( row[0], 1./2.4 ) : row[0];
148           *L = (row[0]>1.0e-16) ? log10( row[0] ) : -16;
149         } else {
150           *L = row[0];
151         }
152         //*Lg = *L;
153 
154         row += 1;
155         L += 1;
156       }
157     }
158   }
159 
fill_RGB_matrices(int rw,int rh,PixelMatrix<float> & rgbin,PixelMatrix<float> & rin,PixelMatrix<float> & gin,PixelMatrix<float> & bin,PixelMatrix<float> & rguide,PixelMatrix<float> & gguide,PixelMatrix<float> & bguide)160   void fill_RGB_matrices(int rw, int rh, PixelMatrix<float>& rgbin,
161       PixelMatrix<float>& rin, PixelMatrix<float>& gin, PixelMatrix<float>& bin,
162       PixelMatrix<float>& rguide, PixelMatrix<float>& gguide, PixelMatrix<float>& bguide)
163   {
164     int x, y, z;
165 
166     for(y = 0; y < rh; y++) {
167       float* row = rgbin[y];
168       float* rr = rin[y];
169       float* gr = gin[y];
170       float* br = bin[y];
171       float* rrg = rguide[y];
172       float* grg = gguide[y];
173       float* brg = bguide[y];
174       for( x = 0; x < rw; x++ ) {
175         //std::cout<<"  y="<<y<<"  x="<<x<<"  row="<<row<<"  rr="<<rr<<"  gr="<<gr<<"  br="<<br<<std::endl;
176         //if(x==0 && y==0) std::cout<<"  row="<<row[0]<<" "<<row[1]<<" "<<row[2]<<std::endl;
177         if( opar->get_convert_to_perceptual() &&
178             profile && profile->is_linear() ) {
179           //*rr = (row[0]>0) ? powf( row[0], 1./2.4 ) : row[0];
180           //*gr = (row[1]>0) ? powf( row[1], 1./2.4 ) : row[1];
181           //*br = (row[2]>0) ? powf( row[2], 1./2.4 ) : row[2];
182           *rr = (row[0]>1.0e-16) ? log10( row[0] ) : -16;
183           *gr = (row[1]>1.0e-16) ? log10( row[1] ) : -16;
184           *br = (row[2]>1.0e-16) ? log10( row[2] ) : -16;
185         } else {
186           *rr = row[0];
187           *gr = row[1];
188           *br = row[2];
189         }
190         *rrg = *rr;
191         *grg = *gr;
192         *brg = *br;
193 
194         row += 3;
195         rr += 1;
196         gr += 1;
197         br += 1;
198         rrg += 1;
199         grg += 1;
200         brg += 1;
201       }
202     }
203   }
204 
fill_RGBL_matrices(int rw,int rh,PixelMatrix<float> & rgbin,PixelMatrix<float> & rin,PixelMatrix<float> & gin,PixelMatrix<float> & bin,PixelMatrix<float> & Lin,PixelMatrix<float> & rguide,PixelMatrix<float> & gguide,PixelMatrix<float> & bguide,PixelMatrix<float> & Lguide)205   void fill_RGBL_matrices(int rw, int rh, PixelMatrix<float>& rgbin,
206       PixelMatrix<float>& rin, PixelMatrix<float>& gin, PixelMatrix<float>& bin, PixelMatrix<float>& Lin,
207       PixelMatrix<float>& rguide, PixelMatrix<float>& gguide, PixelMatrix<float>& bguide, PixelMatrix<float>& Lguide)
208   {
209     int x, y, z;
210 
211     for(y = 0; y < rh; y++) {
212       float* row = rgbin[y];
213       float* rr = rin[y];
214       float* gr = gin[y];
215       float* br = bin[y];
216       float* Lr = Lin[y];
217       float* rrg = rguide[y];
218       float* grg = gguide[y];
219       float* brg = bguide[y];
220       float* Lrg = Lguide[y];
221       for( x = 0; x < rw; x++ ) {
222         //std::cout<<"  y="<<y<<"  x="<<x<<"  row="<<row<<"  rr="<<rr<<"  gr="<<gr<<"  br="<<br<<std::endl;
223         //if(x==0 && y==0) std::cout<<"  row="<<row[0]<<" "<<row[1]<<" "<<row[2]<<std::endl;
224         if( opar->get_convert_to_perceptual() && profile && profile->is_linear() ) {
225           //*rr = (row[0]>0) ? powf( row[0], 1./2.4 ) : row[0];
226           //*gr = (row[1]>0) ? powf( row[1], 1./2.4 ) : row[1];
227           //*br = (row[2]>0) ? powf( row[2], 1./2.4 ) : row[2];
228           //*Lr = (row[3]>0) ? powf( row[3], 1./2.4 ) : row[3];
229           *rr = (row[0]>1.0e-16) ? log10( row[0] ) : -16;
230           *gr = (row[1]>1.0e-16) ? log10( row[1] ) : -16;
231           *br = (row[2]>1.0e-16) ? log10( row[2] ) : -16;
232           *Lr = (row[3]>1.0e-16) ? log10( row[3] ) : -16;
233         } else {
234           *rr = row[0];
235           *gr = row[1];
236           *br = row[2];
237           *Lr = row[3];
238         }
239         *rrg = *rr;
240         *grg = *gr;
241         *brg = *br;
242         *Lrg = *Lr;
243 
244         row += 4;
245         rr += 1; gr += 1; br += 1; Lr += 1;
246         rrg += 1; grg += 1; brg += 1; Lrg += 1;
247       }
248     }
249   }
250 
fill_RGB_out(int rw,int rh,int dx,int dy,PixelMatrix<float> & rgbout,PixelMatrix<float> & rout,PixelMatrix<float> & gout,PixelMatrix<float> & bout)251   void fill_RGB_out(int rw, int rh, int dx, int dy, PixelMatrix<float>& rgbout,
252       PixelMatrix<float>& rout, PixelMatrix<float>& gout, PixelMatrix<float>& bout)
253   {
254     int x, y, z;
255 
256    for(y = 0; y < rh; y++) {
257       float* rr = rout[y+dy];
258       float* gr = gout[y+dy];
259       float* br = bout[y+dy];
260       float* row = rgbout[y];
261       rr += dx; gr += dx; br += dx;
262       for( x = 0; x < rw; x++ ) {
263         if( opar->get_convert_to_perceptual() &&
264             profile && profile->is_linear() ) {
265           //row[0] = (*rr>0) ? powf( *rr, 2.4 ) : *rr;
266           //row[1] = (*gr>0) ? powf( *gr, 2.4 ) : *gr;
267           //row[2] = (*br>0) ? powf( *br, 2.4 ) : *br;
268           row[0] = pow( 10, *rr );
269           row[1] = pow( 10, *gr );
270           row[2] = pow( 10, *br );
271         } else {
272           row[0] = *rr;
273           row[1] = *gr;
274           row[2] = *br;
275         }
276         row += 3;
277         rr += 1;
278         gr += 1;
279         br += 1;
280       }
281     }
282   }
283 
fill_RGBL_out(int rw,int rh,int dx,int dy,PixelMatrix<float> & rgbout,PixelMatrix<float> & rout,PixelMatrix<float> & gout,PixelMatrix<float> & bout,PixelMatrix<float> & Lout)284   void fill_RGBL_out(int rw, int rh, int dx, int dy, PixelMatrix<float>& rgbout,
285       PixelMatrix<float>& rout, PixelMatrix<float>& gout, PixelMatrix<float>& bout, PixelMatrix<float>& Lout)
286   {
287     int x, y, z;
288 
289    for(y = 0; y < rh; y++) {
290       float* rr = rout[y+dy];
291       float* gr = gout[y+dy];
292       float* br = bout[y+dy];
293       float* Lr = Lout[y+dy];
294       float* row = rgbout[y];
295       rr += dx; gr += dx; br += dx; Lr += dx;
296       for( x = 0; x < rw; x++ ) {
297         if( opar->get_convert_to_perceptual() &&
298             profile && profile->is_linear() ) {
299           //row[0] = (*rr>0) ? powf( *rr, 2.4 ) : *rr;
300           //row[1] = (*gr>0) ? powf( *gr, 2.4 ) : *gr;
301           //row[2] = (*br>0) ? powf( *br, 2.4 ) : *br;
302           //row[3] = (*Lr>0) ? powf( *Lr, 2.4 ) : *Lr;
303           row[0] = pow( 10, *rr );
304           row[1] = pow( 10, *gr );
305           row[2] = pow( 10, *br );
306           row[3] = pow( 10, *Lr );
307         } else {
308           row[0] = *rr;
309           row[1] = *gr;
310           row[2] = *br;
311           row[3] = *Lr;
312         }
313         row += 4;
314         rr += 1;
315         gr += 1;
316         br += 1;
317         Lr += 1;
318       }
319     }
320   }
321 
fill_L_out(int rw,int rh,int dx,int dy,PixelMatrix<float> & rgbout,PixelMatrix<float> & Lout)322   void fill_L_out(int rw, int rh, int dx, int dy,
323       PixelMatrix<float>& rgbout, PixelMatrix<float>& Lout)
324   {
325     int x, y, z;
326 
327    for(y = 0; y < rh; y++) {
328       float* L = Lout[y+dy];
329       float* row = rgbout[y];
330       L += dx;
331       for( x = 0; x < rw; x++ ) {
332         if( opar->get_convert_to_perceptual() &&
333             profile && profile->is_linear() ) {
334           //row[0] = (*L>0) ? powf( *L, 2.4 ) : *L;
335           row[0] = pow( 10, *L );
336         } else {
337           row[0] = *L;
338         }
339         row += 1;
340         L += 1;
341       }
342     }
343   }
344 
345 public:
render(VipsRegion ** ireg,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * oreg,OpParBase * par)346   void render(VipsRegion** ireg, int n, int in_first,
347       VipsRegion* imap, VipsRegion* omap,
348       VipsRegion* oreg, OpParBase* par)
349   {
350     if( n < 1 ) return;
351     if( ireg[0] == NULL ) return;
352 
353     opar = dynamic_cast<GuidedFilterPar*>(par);
354     if( !opar ) return;
355 
356     int es = VIPS_IMAGE_SIZEOF_ELEMENT( ireg[0]->im );
357     int ips = VIPS_IMAGE_SIZEOF_PEL( ireg[0]->im );
358     const int ops = VIPS_IMAGE_SIZEOF_PEL( oreg->im );
359 
360     //const int order = 1; // 0,1,2
361     //const float radius = opar->get_radius();
362     //const float thresfold = opar->get_threshold();
363 
364     int r = opar->get_radius();
365     float epsilon = opar->get_threshold();
366     int subsampling = opar->get_subsampling();
367 
368 #ifdef GF_DEBUG
369     std::cout<<"[GuidedFilter]: padding = "<<opar->get_padding(0)<<"  subsampling = "<<subsampling<<"  epsilon = "<<epsilon<<std::endl;;
370     std::cout<<"  ireg[0] = "<<ireg[0]<<" -> ("<<ireg[0]->valid.left<<","<<ireg[0]->valid.top<<") x ("<<ireg[0]->valid.width<<","<<ireg[0]->valid.height<<")\n";
371     std::cout<<"  oreg =    "<<oreg<<" -> ("<<oreg->valid.left<<","<<oreg->valid.top<<") x ("<<oreg->valid.width<<","<<oreg->valid.height<<")\n";
372     std::cout<<"  pin[0] =  "<<(void*)VIPS_REGION_ADDR(ireg[0], ireg[0]->valid.left, ireg[0]->valid.top)
373         <<" -> "<<*((float*)VIPS_REGION_ADDR(ireg[0], ireg[0]->valid.left, ireg[0]->valid.top))<<std::endl;
374 #endif
375 
376     profile = opar->get_icc_data();
377     if( opar->get_convert_to_perceptual() && profile && profile->is_linear() ) epsilon *= 10;
378 
379     //std::cout<<"GuidedFilterProc::render: n="<<n<<"  radius="<<r<<"  epsilon="<<epsilon<<std::endl;
380 
381     int offsx = 0;
382     int offsy = 0;
383     int shiftx = (ireg[0]->valid.left/subsampling+1) * subsampling - ireg[0]->valid.left;
384     int shifty = (ireg[0]->valid.top/subsampling+1) * subsampling - ireg[0]->valid.top;
385     int rw = ireg[0]->valid.width - shiftx - subsampling;
386     rw = (rw/subsampling+1) * subsampling;
387     int rh = ireg[0]->valid.height - shifty - subsampling;
388     rh = (rh/subsampling+1) * subsampling;
389     int ileft = ireg[0]->valid.left + shiftx;
390     int itop = ireg[0]->valid.top + shifty;
391     float* p = (float*)VIPS_REGION_ADDR( ireg[0], ileft, itop );
392     float* pguide = (n==2 && ireg[1]) ? (float*)VIPS_REGION_ADDR( ireg[1], ileft, itop ) : p;
393     float* pout;
394     int rowstride = VIPS_REGION_LSKIP(ireg[0]) / sizeof(float);
395     PixelMatrix<float> rgbin(p, rw, rh, rowstride, offsy, offsx);
396     PixelMatrix<float> guidein(pguide, rw, rh, rowstride, offsy, offsx);
397 
398     /*
399     std::cout<<"GuidedFilterProc::render: Bands="<<ireg[0]->im->Bands<<std::endl;
400     std::cout<<"GuidedFilterProc::render: radius="<<r<<"  subsampling="<<subsampling<<std::endl;
401     std::cout<<"GuidedFilterProc::render: ireg.left="<<ireg[0]->valid.left
402         <<"  shiftx="<<shiftx<<std::endl;
403     std::cout<<"GuidedFilterProc::render: ireg.top="<<ireg[0]->valid.top
404         <<"  shifty="<<shifty<<std::endl;
405     std::cout<<"GuidedFilterProc::render: ireg.width="<<ireg[0]->valid.width
406         <<"  rw="<<rw<<std::endl;
407     std::cout<<"GuidedFilterProc::render: ireg.height="<<ireg[0]->valid.height
408         <<"  rh="<<rh<<std::endl;
409     */
410     if( ireg[0]->im->Bands == 1 ) {
411       //if(true && r->top<150 && r->left<700 && x==0 && y==0)
412       //std::cout<<"[x,y]="<<x0+r->left<<","<<y+r->top<<"  l1: "<<l2<<"  l2: "<<l2<<std::endl;
413 
414       PixelMatrix<float> Lin(rw, rh, offsy, offsx);
415       PixelMatrix<float> Lguide(rw, rh, offsy, offsx);
416       PixelMatrix<float> Lout(rw, rh, offsy, offsx);
417 
418       //std::cout<<"GuidedFilterProc::render: splitting RGB channels"<<std::endl;
419 
420       //fill_L_matrices( rw, rh, rgbin, guidein, Lin, Lguide );
421       fill_L_matrices( rw, rh, rgbin, Lin );
422 
423       //std::cout<<"GuidedFilterProc::render: processing L channel"<<std::endl;
424       //guidedFilter(Lguide, Lin, Lout, r, epsilon, subsampling);
425       guidedFilter(Lin, Lout, r, epsilon, subsampling);
426 
427       int dx = oreg->valid.left - ireg[0]->valid.left - shiftx;
428       int dy = oreg->valid.top - ireg[0]->valid.top - shifty;
429       offsx = oreg->valid.left;
430       offsy = oreg->valid.top;
431       rw = oreg->valid.width;
432       rh = oreg->valid.height;
433       pout = (float*)VIPS_REGION_ADDR( oreg, offsx, offsy );
434       rowstride = VIPS_REGION_LSKIP(oreg) / sizeof(float);
435       PF::PixelMatrix<float> rgbout(pout, rw, rh, rowstride, 0, 0);
436 
437       //std::cout<<"GuidedFilterProc::render: r="<<r<<"  epsilon="<<epsilon<<"  subsampling="<<subsampling
438       //    <<"  left="<<oreg->valid.left<<"  top="<<oreg->valid.top
439       //    <<"  dx="<<dx<<"  dy="<<dy<<"  rw="<<rw<<"  rh="<<rh<<std::endl;
440 
441       fill_L_out(rw, rh, dx, dy, rgbout, Lout);
442 #ifdef GF_DEBUG
443       std::cout<<"  pout[0] = "<<(void*)VIPS_REGION_ADDR(oreg, oreg->valid.left, oreg->valid.top)
444           <<" -> "<<*((float*)VIPS_REGION_ADDR(oreg, oreg->valid.left, oreg->valid.top))<<std::endl;
445 #endif
446     }
447 
448     if( ireg[0]->im->Bands == 3 ) {
449       PixelMatrix<float> rin(rw, rh, offsy, offsx);
450       PixelMatrix<float> gin(rw, rh, offsy, offsx);
451       PixelMatrix<float> bin(rw, rh, offsy, offsx);
452       PixelMatrix<float> rguide(rw, rh, offsy, offsx);
453       PixelMatrix<float> gguide(rw, rh, offsy, offsx);
454       PixelMatrix<float> bguide(rw, rh, offsy, offsx);
455       PixelMatrix<float> rout(rw, rh, offsy, offsx);
456       PixelMatrix<float> gout(rw, rh, offsy, offsx);
457       PixelMatrix<float> bout(rw, rh, offsy, offsx);
458 
459       //std::cout<<"GuidedFilterProc::render: splitting RGB channels"<<std::endl;
460 
461       fill_RGB_matrices( rw, rh, rgbin, rin, gin, bin, rguide, gguide, bguide );
462 
463       //std::cout<<"GuidedFilterProc::render: processing RGB channels"<<std::endl;
464       //std::cout<<"                          processing R:"<<std::endl;
465       guidedFilter(rguide, rin, rout, r, epsilon, subsampling);
466       //std::cout<<"                          processing G:"<<std::endl;
467       guidedFilter(gguide, gin, gout, r, epsilon, subsampling);
468       //std::cout<<"                          processing B:"<<std::endl;
469       guidedFilter(bguide, bin, bout, r, epsilon, subsampling);
470 
471       int dx = oreg->valid.left - ireg[0]->valid.left - shiftx;
472       int dy = oreg->valid.top - ireg[0]->valid.top - shifty;
473       offsx = oreg->valid.left;
474       offsy = oreg->valid.top;
475       rw = oreg->valid.width;
476       rh = oreg->valid.height;
477       p = (float*)VIPS_REGION_ADDR( oreg, offsx, offsy );
478       rowstride = VIPS_REGION_LSKIP(oreg) / sizeof(float);
479       PF::PixelMatrix<float> rgbout(p, rw, rh, rowstride, 0, 0);
480 
481       //std::cout<<"GuidedFilterProc::render: r="<<r<<"  epsilon="<<epsilon<<"  subsampling="<<subsampling
482       //    <<"  dx="<<dx<<"  dy="<<dy<<"  rw="<<rw<<"  rh="<<rh<<std::endl;
483 
484       fill_RGB_out(rw, rh, dx, dy, rgbout, rout, gout, bout);
485     }
486 
487 
488     if( ireg[0]->im->Bands == 4 ) {
489       PixelMatrix<float> rin(rw, rh, offsy, offsx);
490       PixelMatrix<float> gin(rw, rh, offsy, offsx);
491       PixelMatrix<float> bin(rw, rh, offsy, offsx);
492       PixelMatrix<float> Lin(rw, rh, offsy, offsx);
493       PixelMatrix<float> rguide(rw, rh, offsy, offsx);
494       PixelMatrix<float> gguide(rw, rh, offsy, offsx);
495       PixelMatrix<float> bguide(rw, rh, offsy, offsx);
496       PixelMatrix<float> Lguide(rw, rh, offsy, offsx);
497       PixelMatrix<float> rout(rw, rh, offsy, offsx);
498       PixelMatrix<float> gout(rw, rh, offsy, offsx);
499       PixelMatrix<float> bout(rw, rh, offsy, offsx);
500       PixelMatrix<float> Lout(rw, rh, offsy, offsx);
501 
502       //std::cout<<"GuidedFilterProc::render: splitting RGB channels"<<std::endl;
503 
504       fill_RGBL_matrices( rw, rh, rgbin, rin, gin, bin, Lin, rguide, gguide, bguide, Lguide );
505 
506       //std::cout<<"GuidedFilterProc::render: processing RGB channels"<<std::endl;
507       //std::cout<<"                          processing R:"<<std::endl;
508       guidedFilter(rguide, rin, rout, r, epsilon, subsampling);
509       //std::cout<<"                          processing G:"<<std::endl;
510       guidedFilter(gguide, gin, gout, r, epsilon, subsampling);
511       //std::cout<<"                          processing B:"<<std::endl;
512       guidedFilter(bguide, bin, bout, r, epsilon, subsampling);
513       //std::cout<<"                          processing L:"<<std::endl;
514       guidedFilter(Lguide, Lin, Lout, r, epsilon, subsampling);
515 
516       int dx = oreg->valid.left - ireg[0]->valid.left;
517       int dy = oreg->valid.top - ireg[0]->valid.top;
518       offsx = oreg->valid.left;
519       offsy = oreg->valid.top;
520       rw = oreg->valid.width;
521       rh = oreg->valid.height;
522       p = (float*)VIPS_REGION_ADDR( oreg, offsx, offsy );
523       rowstride = VIPS_REGION_LSKIP(oreg) / sizeof(float);
524       PF::PixelMatrix<float> rgbout(p, rw, rh, rowstride, 0, 0);
525 
526       //std::cout<<"GuidedFilterProc::render: r="<<r<<"  epsilon="<<epsilon<<"  subsampling="<<subsampling
527       //    <<"  dx="<<dx<<"  dy="<<dy<<"  rw="<<rw<<"  rh="<<rh<<std::endl;
528 
529       fill_RGBL_out(rw, rh, dx, dy, rgbout, rout, gout, bout, Lout);
530     }
531 
532     /*
533     int x, y, z;
534 
535     for(y = 0; y < rh; y++) {
536       float* row = rgbin[y];
537       float* rr = rin[y];
538       float* gr = gin[y];
539       float* br = bin[y];
540       float* rrg = rguide[y];
541       float* grg = gguide[y];
542       float* brg = bguide[y];
543       for( x = 0; x < rw; x++ ) {
544         //std::cout<<"  y="<<y<<"  x="<<x<<"  row="<<row<<"  rr="<<rr<<"  gr="<<gr<<"  br="<<br<<std::endl;
545         //if(x==0 && y==0) std::cout<<"  row="<<row[0]<<" "<<row[1]<<" "<<row[2]<<std::endl;
546         if( opar->get_convert_to_perceptual() &&
547             profile && profile->is_linear() ) {
548           *rr = (row[0]>0) ? powf( row[0], 1./2.4 ) : row[0];
549           *gr = (row[1]>0) ? powf( row[1], 1./2.4 ) : row[1];
550           *br = (row[2]>0) ? powf( row[2], 1./2.4 ) : row[2];
551         } else {
552           *rr = row[0];
553           *gr = row[1];
554           *br = row[2];
555         }
556         if(false && profile && profile->is_linear()) {
557           *rrg = (*rr>0) ? powf( *rr, 1./2.4 ) : *rr;
558           *grg = (*gr>0) ? powf( *gr, 1./2.4 ) : *gr;
559           *brg = (*br>0) ? powf( *br, 1./2.4 ) : *br;
560         } else {
561           *rrg = *rr;
562           *grg = *gr;
563           *brg = *br;
564         }
565         row += 3;
566         rr += 1;
567         gr += 1;
568         br += 1;
569         rrg += 1;
570         grg += 1;
571         brg += 1;
572       }
573     }
574 
575     //return;
576 
577     int dx = oreg->valid.left - ireg[0]->valid.left;
578     int dy = oreg->valid.top - ireg[0]->valid.top;
579     offsx = oreg->valid.left;
580     offsy = oreg->valid.top;
581     rw = oreg->valid.width;
582     rh = oreg->valid.height;
583     p = (float*)VIPS_REGION_ADDR( oreg, offsx, offsy );
584     rowstride = VIPS_REGION_LSKIP(oreg) / sizeof(float);
585     PF::PixelMatrix<float> rgbout(p, rw, rh, rowstride, 0, 0);
586 
587     if( ireg[0]->im.Bands == 3 ) {
588     fill_RGB_out(rw, rh, dx, dy, rout, gout, bout, rgbout);
589     }
590 
591     for(y = 0; y < rh; y++) {
592       float* irow = rgbin[y+dy];
593       float* rr = rout[y+dy];
594       float* gr = gout[y+dy];
595       float* br = bout[y+dy];
596       float* row = rgbout[y];
597       //float* rr = rin[y+dy];
598       //float* gr = gin[y+dy];
599       //float* br = bin[y+dy];
600       rr += dx; gr += dx; br += dx; irow += dx*3;
601       for( x = 0; x < rw; x++ ) {
602         if( opar->get_convert_to_perceptual() &&
603             profile && profile->is_linear() ) {
604           row[0] = (*rr>0) ? powf( *rr, 2.4 ) : *rr;
605           row[1] = (*gr>0) ? powf( *gr, 2.4 ) : *gr;
606           row[2] = (*br>0) ? powf( *br, 2.4 ) : *br;
607         } else {
608           row[0] = *rr;
609           row[1] = *gr;
610           row[2] = *br;
611         }
612         //row[0] = irow[0];
613         //row[1] = irow[1];
614         //row[2] = irow[2];
615         row += 3;
616         irow += 3;
617         rr += 1;
618         gr += 1;
619         br += 1;
620       }
621     }
622     */
623   }
624 };
625 
626 
627 ProcessorBase* new_guided_filter();
628 
629 }
630 
631 #endif
632 
633 
634