33 #ifndef __INCLUDE_POISSON_BLENDING__
34 #define __INCLUDE_POISSON_BLENDING__
37 #ifndef __INCLUDE_MIST_VECTOR__
41 #ifndef __INCLUDE_NUMERIC__
45 #ifndef __INCLUDE_CONVERTER__
49 #ifndef __INCLUDE_MIST_MORPHOLOGY__
64 namespace __poissonblender__
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;
73 typedef vector2< point_type > rectangle_type;
76 inline void _recTrim( array2< T > &out,
const array2< T > &in,
const rectangle_type &rec )
78 in.trim ( out, rec.x.x, rec.x.y, ( rec.y.x - rec.x.x ), ( rec.y.y - rec.x.y ) );
82 inline void _recTrim( array2< T > &in,
const rectangle_type &rec )
84 in.trim ( rec.x.x, rec.x.y, ( rec.y.x - rec.x.x ), ( rec.y.y - rec.x.y ) );
89 inline unsigned char _saturate_cast( T num )
91 if ( num > 255 )
return 255;
92 else if ( num < 0 )
return 0;
93 else return ( static_cast< unsigned char >(num) );
98 inline void _differencial( array2< T > &im1,
const array2< T > &im2,
const bool integral =
false )
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;
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 );
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 )
121 int w = _mask1.width();
122 int h = _mask1.height();
124 if ( w == 0 || h == 0 ) {
125 std::cerr <<
"mask size error w:" << w <<
",h:" << h << std::endl;
130 unsigned int max_row = 0;
132 for (
int y = 0; y < h - 1; ++y )
134 for (
int x = 0; x < w - 1; ++x )
136 if ( _mask1( x, y ) == 0 )
continue;
140 if ( _mp.count( (y - 1) * w + x ) != 0)
142 unsigned int diff = _mp[ id ] - _mp[ (y - 1) * w + x ];
143 if ( diff > max_row ) max_row = diff;
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;
152 if ( !b.resize( nz, 1 ) ) {
153 std::cerr <<
"mask size is too large." << std::endl;
156 if ( !u.resize( nz, 1 ) ){
157 std::cerr <<
"mask size is too large." << std::endl;
163 for (
int y = 1; y < h - 1; ++y )
165 for (
int x = 1; x < w - 1; ++x )
167 if ( _mask1( x, y ) == 0 )
continue;
168 differencial_type &drv = _drvxy( x, y );
171 int tidx =
id - w, lidx =
id - 1;
174 unsigned char tlrb = 15;
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 );
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 );
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 );
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 );
201 if ( tlrb & 8 ) A( _mp[ tidx ] - rowA + ( max_row ), rowA ) = -1.0;
202 if ( tlrb & 4 ) A( _mp[ lidx ] - rowA + ( max_row ), rowA ) = -1.0;
203 A( _mp[
id ] - rowA + ( max_row ), rowA ) = 4.0;
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;
214 if ( nz != static_cast< unsigned int >( rowA ) ){
215 std::cerr <<
"unexpected error!" << std::endl;
223 template <
typename T >
224 inline bool _solve(
const matrix< T > &A, matrix< T > &b, matrix< T > &u)
228 u = solve( A, b, matrix_style::pb );
230 catch( numerical_exception &e )
232 std::cerr <<
"solving failed" << std::endl;
233 std::cerr << e.message << std::endl;
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 )
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 )
249 if( _mask1( x, y ) == 0 )
continue;
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 ) );
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 )
280 __poissonblender__::mono_image_type _mask = mask;
281 if ( src.empty() || target.empty() || _mask.empty() )
return false;
284 __poissonblender__::point_type offset( offx, offy );
285 __poissonblender__::point_type tl( _mask.size1(), _mask.size2() ), br( -1, -1 );
288 for (
unsigned int y = 0; y < _mask.height(); ++y ) {
289 for (
unsigned int x = 0; x < _mask.width(); ++x )
291 if ( _mask( x, y ) < 50 ) _mask( x, y ) = 0;
292 else _mask( x, y ) = 255;
297 for (
unsigned int y = 0; y < _mask.height(); ++y ) {
298 for (
unsigned int x = 0; x < _mask.width(); ++x )
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;
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 ) );
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 );
322 __poissonblender__::color_image_type
dst = target;
325 __poissonblender__::mono_image_type _mask1;
326 __poissonblender__::color_image_type _dst1;
327 __poissonblender__::color_image_type _target1;
328 __poissonblender__::color_image_type _src1;
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 ) ) );
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 ) ) );
340 if ( _src.height() != _dst.height() || _src.width() != _dst.width() )
return false;
343 __poissonblender__::differencial_image_type src64, target64;
344 __poissonblender__::differencial_image_type _src64_00, _target64_00;
346 int pw = mask_roi2.y.x - mask_roi2.x.x - 1, ph = mask_roi2.y.y - mask_roi2.x.y -1;
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 );
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 );
362 __poissonblender__::differencial_image_type Dx, Dy;
365 unsigned int wx = src_dx.width();
366 unsigned int hx = src_dx.height();
368 unsigned int wy = src_dy.width();
369 unsigned int hy = src_dy.height();
372 for (
unsigned int j = 0; j < hx; j++ ) {
373 for (
unsigned int i = 0; i < wx; i++ )
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;
380 for (
unsigned int j = 0; j < hy; j++ ) {
381 for (
unsigned int i = 0; i < wy; i++ )
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;
398 unsigned int wx = target_dx.width();
399 unsigned int hx = target_dx.height();
401 unsigned int wy = target_dy.width();
402 unsigned int hy = target_dy.height();
405 double alpha = 0.2f, beta = 0.2f;
408 for (
unsigned int j = 0; j < hy; j++ ) {
409 for (
unsigned int i = 0; i < wx; i++ )
411 norm = sqrt( target_dx( i, j ).r * target_dx( i, j ).r + target_dy( i, j ).r * target_dy( i, j ).r );
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;
420 norm = sqrt( target_dx( i, j ).g * target_dx( i, j ).g + target_dy( i, j ).g * target_dy( i, j ).g );
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;
429 norm = sqrt( target_dx( i, j ).b * target_dx( i, j ).b + target_dy( i, j ).b * target_dy( i, j ).b );
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;
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;
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 );
460 matrix< double > A[ 3 ], b[ 3 ], u[ 3 ];
461 std::map<int,int> _mp;
463 for (
unsigned int i = 0; i < 3; i++ )
466 if ( !__poissonblender__::_buildMatrix( A[ i ], b[ i ], u[ i ], i, _mask1, _mp, _drvxy, _target1 ) ) {
467 std::cerr <<
"cant build matrix." << std::endl;
472 if ( !__poissonblender__::_solve(A[ i ], b[ i ], u[ i ]) ) {
473 std::cerr <<
"cant solve poissson matrix." << std::endl;
478 if ( !__poissonblender__::_copyResult( u[ i ], i, _mask1, _mp, _dst1, _src1 ) ) {
479 std::cerr <<
"cant reconstruct cloned image." << std::endl;
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 );
516 template<
class Array1,
class Array2,
class Array3 >
518 const Array1 &src,
const Array2 &target, Array3 &out,
520 const int offx = 0,
const int offy = 0,
const bool mix =
false )
522 return __seamlessCloning( src, target, out, mask, offx, offy, mix );
536 template<
class Array1,
class Array2 >
539 if ( in.empty() || mask.
empty() )
return false;
544 return __seamlessCloning( in, _target, out, mask );
559 template<
class Array1,
class Array2 >
563 if ( in.empty() || mask.
empty() )
return false;
566 for (
unsigned int j = 0; j < _src.
height(); j++ ) {
567 for (
unsigned int i = 0; i < _src.
width(); i++ )
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 );
575 return __seamlessCloning( _src, in, out, mask );
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 )
583 if ( in.empty() || mask.empty() )
return false;
585 __poissonblender__::color_image_type _target = in;
586 return __seamlessCloning( in, _target, out, mask, 0, 0,
false,
true, alpha, beta );