poisson_blending.h
説明を見る。
1 //
2 // Copyright (c) 2003-2011, MIST Project, Nagoya University
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // 3. Neither the name of the Nagoya University nor the names of its contributors
16 // may be used to endorse or promote products derived from this software
17 // without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
20 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28 
33 #ifndef __INCLUDE_POISSON_BLENDING__
34 #define __INCLUDE_POISSON_BLENDING__
35 
36 
37 #ifndef __INCLUDE_MIST_VECTOR__
38 #include "vector.h"
39 #endif
40 
41 #ifndef __INCLUDE_NUMERIC__
42 #include "numeric.h"
43 #endif
44 
45 #ifndef __INCLUDE_CONVERTER__
46 #include <mist/converter.h>
47 #endif
48 
49 #ifndef __INCLUDE_MIST_MORPHOLOGY__
50 #include <mist/filter/morphology.h>
51 #endif
52 
53 
54 
55 #include <map>
56 #include <stdio.h>
57 
58 
59 
60 // mist名前空間の始まり
62 
63 
64 namespace __poissonblender__
65 {
66  typedef unsigned char mono_type;
67  typedef rgb< unsigned char > color_type;
68  typedef rgb< double > differencial_type;
69  typedef array2< mono_type > mono_image_type;
70  typedef array2< color_type > color_image_type;
71  typedef array2< differencial_type > differencial_image_type;
72  typedef vector2< int > point_type; // ( x, y )
73  typedef vector2< point_type > rectangle_type; // ( ( tl_x, tl_y ), ( br_x, br_y ) )
74 
75  template <typename T>
76  inline void _recTrim( array2< T > &out, const array2< T > &in, const rectangle_type &rec )
77  {
78  in.trim ( out, rec.x.x, rec.x.y, ( rec.y.x - rec.x.x ), ( rec.y.y - rec.x.y ) );
79  }
80 
81  template <typename T>
82  inline void _recTrim( array2< T > &in, const rectangle_type &rec )
83  {
84  in.trim ( rec.x.x, rec.x.y, ( rec.y.x - rec.x.x ), ( rec.y.y - rec.x.y ) );
85  }
86 
87  // clipping
88  template <typename T>
89  inline unsigned char _saturate_cast( T num )
90  {
91  if ( num > 255 ) return 255;
92  else if ( num < 0 ) return 0;
93  else return ( static_cast< unsigned char >(num) );
94  }
95 
96  // calc differencial
97  template <typename T> // return im1 -= im2
98  inline void _differencial( array2< T > &im1, const array2< T > &im2, const bool integral = false )
99  {
100  unsigned int w = im1.width() < im2.width() ? im1.width() : im2.width();
101  unsigned int h = im1.height() < im2.height() ? im1.height() : im2.height();
102  array2< T > tmp = im1;
103  im1.resize( w, h );
104  for ( unsigned int j = 0; j < h; j++ ) {
105  for ( unsigned int i = 0; i < w; i++ ) {
106  if ( integral ) im1( i, j ) = tmp( i, j ) + im2( i, j );
107  else im1( i, j ) = tmp( i, j ) - im2( i, j );
108  }
109  }
110  }
111 
112  // build matrix as linear system
113  template <typename T>
114  inline bool _buildMatrix( matrix< T > &A, matrix< T > &b, matrix< T > &u,
115  const unsigned int &color,
116  const mono_image_type &_mask1,
117  std::map<int, int> &_mp,
118  differencial_image_type &_drvxy,
119  const color_image_type &_target1 )
120  {
121  int w = _mask1.width();
122  int h = _mask1.height();
123 
124  if ( w == 0 || h == 0 ) {
125  std::cerr << "mask size error w:" << w << ",h:" << h << std::endl;
126  return false;
127  }
128 
129  unsigned int nz=0;
130  unsigned int max_row = 0;
131  _mp.clear();
132  for ( int y = 0; y < h - 1; ++y )
133  {
134  for ( int x = 0; x < w - 1; ++x )
135  {
136  if ( _mask1( x, y ) == 0 ) continue;
137 
138  int id = y * w + x;
139  _mp[ id ] = nz++;
140  if ( _mp.count( (y - 1) * w + x ) != 0)
141  {
142  unsigned int diff = _mp[ id ] - _mp[ (y - 1) * w + x ];
143  if ( diff > max_row ) max_row = diff;
144  }
145  }
146  }
147  if ( !A.resize( max_row + 1, nz ) ) {
148  std::cerr << "cant allocate matrix( "<< max_row + 1 <<", "<< nz <<" )" << std::endl;
149  std::cerr << "mask size is too large." << std::endl;
150  return false;
151  }
152  if ( !b.resize( nz, 1 ) ) {
153  std::cerr << "mask size is too large." << std::endl;
154  return false;
155  }
156  if ( !u.resize( nz, 1 ) ){
157  std::cerr << "mask size is too large." << std::endl;
158  return false;
159  }
160 
161  int rowA = 0;
162 
163  for ( int y = 1; y < h - 1; ++y )
164  {
165  for ( int x = 1; x < w - 1; ++x )
166  {
167  if ( _mask1( x, y ) == 0 ) continue;
168  differencial_type &drv = _drvxy( x, y );
169 
170  int id = y * w + x;
171  int tidx = id - w, lidx = id - 1;
172 
173  // to omtimize insertion
174  unsigned char tlrb = 15; // 0b1111
175  if ( _mask1( x, y - 1 ) == 0 ) {
176  if ( color == 0 ) drv.r -= static_cast< double >( _target1( x, y - 1 ).r );
177  if ( color == 1 ) drv.g -= static_cast< double >( _target1( x, y - 1 ).g );
178  if ( color == 2 ) drv.b -= static_cast< double >( _target1( x, y - 1 ).b );
179  tlrb &= 7; //0b0111
180  }
181  if ( _mask1( x - 1, y ) == 0 ) {
182  if ( color == 0 ) drv.r -= static_cast< double >( _target1( x - 1, y ).r );
183  if ( color == 1 ) drv.g -= static_cast< double >( _target1( x - 1, y ).g );
184  if ( color == 2 ) drv.b -= static_cast< double >( _target1( x - 1, y ).b );
185  tlrb &= 11; //0b1011
186  }
187  if ( _mask1( x + 1, y ) == 0 ) {
188  if ( color == 0 ) drv.r -= static_cast< double >( _target1( x + 1, y ).r );
189  if ( color == 1 ) drv.g -= static_cast< double >( _target1( x + 1, y ).g );
190  if ( color == 2 ) drv.b -= static_cast< double >( _target1( x + 1, y ).b );
191  tlrb &= 13; //0b1101
192  }
193  if ( _mask1( x, y + 1 ) == 0 ) {
194  if ( color == 0 ) drv.r -= static_cast< double >( _target1( x, y + 1 ).r );
195  if ( color == 1 ) drv.g -= static_cast< double >( _target1( x, y + 1 ).g );
196  if ( color == 2 ) drv.b -= static_cast< double >( _target1( x, y + 1 ).b );
197  tlrb &= 14; //0b1110
198  }
199 
200  // transform upper triangle matrix
201  if ( tlrb & 8 ) A( _mp[ tidx ] - rowA + ( max_row ), rowA ) = -1.0; // top
202  if ( tlrb & 4 ) A( _mp[ lidx ] - rowA + ( max_row ), rowA ) = -1.0; // left
203  A( _mp[ id ] - rowA + ( max_row ), rowA ) = 4.0; // center
204 
205  if ( color == 0 ) b( rowA, 0 ) = drv.r;
206  if ( color == 1 ) b( rowA, 0 ) = drv.g;
207  if ( color == 2 ) b( rowA, 0 ) = drv.b;
208 
209  rowA++;
210 
211  }
212  }
213 
214  if ( nz != static_cast< unsigned int >( rowA ) ){
215  std::cerr << "unexpected error!" << std::endl;
216  return false;
217  }
218 
219  return true;
220  }
221 
222  // solver sparse linear system
223  template < typename T >
224  inline bool _solve(const matrix< T > &A, matrix< T > &b, matrix< T > &u)
225  {
226  try
227  {
228  u = solve( A, b, matrix_style::pb );
229  }
230  catch( numerical_exception &e )
231  {
232  std::cerr << "solving failed" << std::endl;
233  std::cerr << e.message << std::endl;
234  return false;
235  }
236 
237  return true;
238  }
239 
240  template <typename T>
241  inline bool _copyResult(matrix< T > &u, const unsigned int &color, const mono_image_type &_mask1,
242  std::map< int, int > &_mp, color_image_type &_dst1, const color_image_type &_src1 )
243  {
244  int w = _mask1.width();
245  int h = _mask1.height();
246  for ( int y = 1; y < h - 1; ++y ) {
247  for ( int x = 1; x < w - 1; ++x )
248  {
249  if( _mask1( x, y ) == 0 ) continue;
250  else
251  {
252  int idx = _mp[ y * w + x ];
253  color_type &pd = _dst1( x, y );
254  if ( color == 0 ) pd.r = _saturate_cast( -u( idx, 0 ) );
255  if ( color == 1 ) pd.g = _saturate_cast( -u( idx, 0 ) );
256  if ( color == 2 ) pd.b = _saturate_cast( -u( idx, 0 ) );
257  }
258  }
259  }
260 
261  return true;
262  }
263 }
264 
265 
273 
274 template< class Array1, class Array2, class Array3 >
275  inline bool __seamlessCloning(
276  const Array1 &src, const Array2 &target, Array3 &out,
277  const array2< unsigned char > &mask,
278  const int offx = 0, const int offy = 0, const bool mix = false, const bool ill_change = false, const double alpha = 0.2, const double beta = 0.2 )
279 {
280  __poissonblender__::mono_image_type _mask = mask;
281  if ( src.empty() || target.empty() || _mask.empty() ) return false;
282 
283  //
284  __poissonblender__::point_type offset( offx, offy );
285  __poissonblender__::point_type tl( _mask.size1(), _mask.size2() ), br( -1, -1 );
286 
287  // binary transform
288  for ( unsigned int y = 0; y < _mask.height(); ++y ) {
289  for ( unsigned int x = 0; x < _mask.width(); ++x )
290  {
291  if ( _mask( x, y ) < 50 ) _mask( x, y ) = 0;
292  else _mask( x, y ) = 255;
293  }
294  }
295 
296  // calc bounding box
297  for ( unsigned int y = 0; y < _mask.height(); ++y ) {
298  for ( unsigned int x = 0; x < _mask.width(); ++x )
299  {
300  if ( _mask( x, y ) == 0 ) continue;
301  if ( tl.x > (int)x ) tl.x = (int)x;
302  if ( tl.y > (int)y ) tl.y = (int)y;
303  if ( br.x < (int)x ) br.x = (int)x;
304  if ( br.y < (int)y ) br.y = (int)y;
305  }
306  }
307  br.x += 1;
308  br.y += 1;
309 
310  // add borders
311  __poissonblender__::rectangle_type mask_roi ( tl, br );
312  __poissonblender__::rectangle_type mask_roi1( tl - __poissonblender__::point_type( 1, 1 ), br + __poissonblender__::point_type( 1, 1 ) );
313  __poissonblender__::rectangle_type mask_roi2( tl - __poissonblender__::point_type( 2, 2 ), br + __poissonblender__::point_type( 2, 2 ) );
314 
315  marray< __poissonblender__::color_image_type > _srcUP( src.width(), src.height(), 2 ), _targetUP( target.width(), target.height(), 2 ), _dstUP;
316  marray< __poissonblender__::mono_image_type > _maskUP( _mask.width(), _mask.height(), 1 );
317  _srcUP = src;
318  _targetUP = target;
319  _maskUP = _mask;
320 
321  // allocate destination image
322  __poissonblender__::color_image_type dst = target;
323  _dstUP = _targetUP;
324 
325  __poissonblender__::mono_image_type _mask1;
326  __poissonblender__::color_image_type _dst1;
327  __poissonblender__::color_image_type _target1;
328  __poissonblender__::color_image_type _src1;
329 
330  __poissonblender__::_recTrim( _mask1, _maskUP, __poissonblender__::rectangle_type( mask_roi1.x + __poissonblender__::point_type( 1, 1 ), mask_roi1.y + __poissonblender__::point_type( 1, 1 ) ) );
331  __poissonblender__::_recTrim( _target1, _targetUP, __poissonblender__::rectangle_type( mask_roi1.x + offset + __poissonblender__::point_type( 2, 2 ), mask_roi1.y + offset + __poissonblender__::point_type( 2, 2 ) ) );
332  __poissonblender__::_recTrim( _src1, _srcUP, __poissonblender__::rectangle_type( mask_roi1.x + offset + __poissonblender__::point_type( 2, 2 ), mask_roi1.y + offset + __poissonblender__::point_type( 2, 2 ) ) );
333  __poissonblender__::_recTrim( _dst1, _dstUP, __poissonblender__::rectangle_type( mask_roi1.x + offset + __poissonblender__::point_type( 2, 2 ), mask_roi1.y + offset + __poissonblender__::point_type( 2, 2 ) ) );
334 
335  __poissonblender__::color_image_type _src, _target, _dst;
336  __poissonblender__::_recTrim( _src, _srcUP, __poissonblender__::rectangle_type( mask_roi2.x + offset + __poissonblender__::point_type( 2, 2 ), mask_roi2.y + offset + __poissonblender__::point_type( 2, 2 ) ) );
337  __poissonblender__::_recTrim( _target, _targetUP, __poissonblender__::rectangle_type( mask_roi2.x + offset + __poissonblender__::point_type( 2, 2 ), mask_roi2.y + offset + __poissonblender__::point_type( 2, 2 ) ) );
338  __poissonblender__::_recTrim( _dst, _dstUP, __poissonblender__::rectangle_type( mask_roi2.x + offset + __poissonblender__::point_type( 2, 2 ), mask_roi2.y + offset + __poissonblender__::point_type( 2, 2 ) ) );
339 
340  if ( _src.height() != _dst.height() || _src.width() != _dst.width() ) return false;
341 
342  // calc differential image
343  __poissonblender__::differencial_image_type src64, target64;
344  __poissonblender__::differencial_image_type _src64_00, _target64_00;
345 
346  int pw = mask_roi2.y.x - mask_roi2.x.x - 1, ph = mask_roi2.y.y - mask_roi2.x.y -1;
347  src64 = _src;
348  target64 = _target;
349  __poissonblender__::rectangle_type roi00( __poissonblender__::point_type( 0, 0 ), __poissonblender__::point_type( pw, ph ) );
350  __poissonblender__::rectangle_type roi10( __poissonblender__::point_type( 1, 0 ), __poissonblender__::point_type( pw, ph ) );
351  __poissonblender__::rectangle_type roi01( __poissonblender__::point_type( 0, 1 ), __poissonblender__::point_type( pw, ph ) );
352  __poissonblender__::_recTrim( _src64_00, src64, roi00 );
353  __poissonblender__::_recTrim( _target64_00, target64, roi00 );
354 
355  __poissonblender__::differencial_image_type src_dx, src_dy, target_dx, target_dy;
356  __poissonblender__::_recTrim( src_dx, src64, roi10 ); __poissonblender__::_differencial( src_dx, _src64_00 );
357  __poissonblender__::_recTrim( src_dy, src64, roi01 ); __poissonblender__::_differencial( src_dy, _src64_00 );
358  __poissonblender__::_recTrim( target_dx, target64, roi10 ); __poissonblender__::_differencial( target_dx, _target64_00 );
359  __poissonblender__::_recTrim( target_dy, target64, roi01 ); __poissonblender__::_differencial( target_dy, _target64_00 );
360 
361  // gradient mixture
362  __poissonblender__::differencial_image_type Dx, Dy;
363  if ( mix )
364  { // with gradient mixture
365  unsigned int wx = src_dx.width();
366  unsigned int hx = src_dx.height();
367  Dx.resize( wx, hx );
368  unsigned int wy = src_dy.width();
369  unsigned int hy = src_dy.height();
370  Dy.resize( wy, hy );
371 
372  for ( unsigned int j = 0; j < hx; j++ ) {
373  for ( unsigned int i = 0; i < wx; i++ )
374  { //
375  Dx( i, j ).r = abs( src_dx( i, j ).r ) > abs( target_dx( i, j ).r ) ? src_dx( i, j ).r : target_dx( i, j ).r;
376  Dx( i, j ).g = abs( src_dx( i, j ).g ) > abs( target_dx( i, j ).g ) ? src_dx( i, j ).g : target_dx( i, j ).g;
377  Dx( i, j ).b = abs( src_dx( i, j ).b ) > abs( target_dx( i, j ).b ) ? src_dx( i, j ).b : target_dx( i, j ).b;
378  }
379  }
380  for ( unsigned int j = 0; j < hy; j++ ) {
381  for ( unsigned int i = 0; i < wy; i++ )
382  { //
383  Dy( i, j ).r = abs( src_dy( i, j ).r ) > abs( target_dy( i, j ).r ) ? src_dy( i, j ).r : target_dy( i, j ).r;
384  Dy( i, j ).g = abs( src_dy( i, j ).g ) > abs( target_dy( i, j ).g ) ? src_dy( i, j ).g : target_dy( i, j ).g;
385  Dy( i, j ).b = abs( src_dy( i, j ).b ) > abs( target_dy( i, j ).b ) ? src_dy( i, j ).b : target_dy( i, j ).b;
386  }
387  }
388  }
389  else
390  { // without gradient mixture
391  Dx = src_dx;
392  Dy = src_dy;
393  }
394 
395  if ( ill_change )
396  { //Local illumination change
397  //wx+1 = wy, hx = hy+1の関係
398  unsigned int wx = target_dx.width();
399  unsigned int hx = target_dx.height();
400  Dx.resize( wx, hx );
401  unsigned int wy = target_dy.width();
402  unsigned int hy = target_dy.height();
403  Dy.resize( wy, hy );
404 
405  double alpha = 0.2f, beta = 0.2f;
406  double norm;
407 
408  for ( unsigned int j = 0; j < hy; j++ ) {
409  for ( unsigned int i = 0; i < wx; i++ )
410  { //
411  norm = sqrt( target_dx( i, j ).r * target_dx( i, j ).r + target_dy( i, j ).r * target_dy( i, j ).r );
412  if( norm == 0 ) {
413  Dx( i, j ).r = 0;
414  Dy( i, j ).r = 0;
415  } else {
416  Dx( i, j ).r = pow( alpha / norm, beta ) * target_dx( i, j ).r;
417  Dy( i, j ).r = pow( alpha / norm, beta ) * target_dy( i, j ).r;
418  }
419  //
420  norm = sqrt( target_dx( i, j ).g * target_dx( i, j ).g + target_dy( i, j ).g * target_dy( i, j ).g );
421  if( norm == 0 ) {
422  Dx( i, j ).g = 0;
423  Dy( i, j ).g = 0;
424  } else {
425  Dx( i, j ).g = pow( alpha / norm, beta ) * target_dx( i, j ).g;
426  Dy( i, j ).g = pow( alpha / norm, beta ) * target_dy( i, j ).g;
427  }
428  //
429  norm = sqrt( target_dx( i, j ).b * target_dx( i, j ).b + target_dy( i, j ).b * target_dy( i, j ).b );
430  if( norm == 0 ){
431  Dx( i, j ).b = 0;
432  Dy( i, j ).b = 0;
433  } else {
434  Dx( i, j ).b = pow( alpha / norm, beta ) * target_dx( i, j ).b;
435  Dy( i, j ).b = pow( alpha / norm, beta ) * target_dy( i, j ).b;
436  }
437  }
438  }
439 
440 
441  }
442 
443  // lapilacian
444  int w = pw-1, h = ph-1;
445  __poissonblender__::differencial_image_type Dx_00 = Dx, Dy_00 = Dy;
446  __poissonblender__::differencial_image_type _drvxy;
447 
448  __poissonblender__::_recTrim( Dx, __poissonblender__::rectangle_type( __poissonblender__::point_type( 1, 0 ), __poissonblender__::point_type( w, h ) ) );
449  __poissonblender__::_recTrim( Dx_00, __poissonblender__::rectangle_type( __poissonblender__::point_type( 0, 0 ), __poissonblender__::point_type( w, h ) ) );
450  __poissonblender__::_differencial( Dx, Dx_00 );
451  __poissonblender__::_recTrim( Dy, __poissonblender__::rectangle_type( __poissonblender__::point_type( 0, 1 ), __poissonblender__::point_type( w, h ) ) );
452  __poissonblender__::_recTrim( Dy_00, __poissonblender__::rectangle_type( __poissonblender__::point_type( 0, 0 ), __poissonblender__::point_type( w, h ) ) );
453  __poissonblender__::_differencial( Dy, Dy_00 );
454  __poissonblender__::_differencial( Dx, Dy, true );
455  _drvxy = Dx;
456 
457  //
458  // solve an poisson's equation
459  //
460  matrix< double > A[ 3 ], b[ 3 ], u[ 3 ];
461  std::map<int,int> _mp;
462 
463  for ( unsigned int i = 0; i < 3; i++ )
464  {
465  // build right-hand and left-hand matrix
466  if ( !__poissonblender__::_buildMatrix( A[ i ], b[ i ], u[ i ], i, _mask1, _mp, _drvxy, _target1 ) ) {
467  std::cerr << "cant build matrix." << std::endl;
468  return false;
469  }
470 
471  // solve sparse linear system
472  if ( !__poissonblender__::_solve(A[ i ], b[ i ], u[ i ]) ) {
473  std::cerr << "cant solve poissson matrix." << std::endl;
474  return false;
475  }
476 
477  // copy computed result to destination image
478  if ( !__poissonblender__::_copyResult( u[ i ], i, _mask1, _mp, _dst1, _src1 ) ) {
479  std::cerr << "cant reconstruct cloned image." << std::endl;
480  return false;
481  }
482  }
483 
484  // reconstruct whole image
485  for ( unsigned int j = 0; j < _dst1.height(); j++ ) {
486  for ( unsigned int i = 0; i < _dst1.width(); i++ ) {
487  int _x = i + mask_roi1.x.x + offset.x;
488  int _y = j + mask_roi1.x.y + offset.y;
489  if ( _x > -1 && _y > -1 && _x < static_cast< int >( dst.width() ) && _y < static_cast< int >( dst.height() ))
490  dst( _x, _y ) = _dst1( i, j );
491  }
492  }
493 
494  // convert to "out" color type
495  convert( dst, out );
496 
497  return true;
498 }
499 
516 template< class Array1, class Array2, class Array3 >
517  inline bool seamlessCloning(
518  const Array1 &src, const Array2 &target, Array3 &out,
519  const array2< unsigned char > &mask,
520  const int offx = 0, const int offy = 0, const bool mix = false )
521 {
522  return __seamlessCloning( src, target, out, mask, offx, offy, mix );
523 }
524 
536 template< class Array1, class Array2 >
537 inline bool localColorChange( const Array1 &in, Array2 &out, const array2< unsigned char > &mask )
538 {
539  if ( in.empty() || mask.empty() ) return false;
540 
542  convert( in, _target );
543 
544  return __seamlessCloning( in, _target, out, mask );
545 }
546 
559 template< class Array1, class Array2 >
560 inline bool localColorChange( const Array1 &in, Array2 &out, const array2< unsigned char > &mask,
561  const rgb< double > multiplier )
562 {
563  if ( in.empty() || mask.empty() ) return false;
564 
566  for ( unsigned int j = 0; j < _src.height(); j++ ) {
567  for ( unsigned int i = 0; i < _src.width(); i++ )
568  {
569  _src( i, j ).r = __poissonblender__::_saturate_cast( in( i, j ).r * multiplier.r );
570  _src( i, j ).g = __poissonblender__::_saturate_cast( in( i, j ).g * multiplier.g );
571  _src( i, j ).b = __poissonblender__::_saturate_cast( in( i, j ).b * multiplier.b );
572  }
573  }
574 
575  return __seamlessCloning( _src, in, out, mask );
576 }
577 
578 //local illumination changes
579 template< class Array1, class Array2 >
580 inline bool localIlluminationChange( const Array1 &in, Array2 &out, const array2< unsigned char > &mask,
581  const double alpha = 0.2, const double beta = 0.2 )
582 {
583  if ( in.empty() || mask.empty() ) return false;
584 
585  __poissonblender__::color_image_type _target = in;
586  return __seamlessCloning( in, _target, out, mask, 0, 0, false, true, alpha, beta );
587 }
588 
590 // PoissonImageEditingグループの終わり
591 
592 _MIST_END
593 
594 #endif /*__INCLUDE_POISSON_BLENDING__*/

Generated on Wed Nov 12 2014 19:44:22 for MIST by doxygen 1.8.1.2