static Point<bool> imagesMoves( const AContainer& container ){ if( container.count() == 0 ) return { false, false }; Point<bool> moves{ false, false }; auto base = container.pos( 0 ); for( unsigned i=1; i<container.count(); ++i ){ auto current = container.pos( i ); moves.x = moves.x || (base.x != current.x); moves.y = moves.y || (base.y != current.y); } return moves; }
ImageEx EstimatorRender::render(const AContainer &group, AProcessWatcher *watcher) const { auto planes_amount = group.image(0).size(); auto min_point = group.minPoint(); ProgressWrapper( watcher ).setTotal( planes_amount * iterations * group.count() ); auto est = AverageRender().render( group ); //Starting estimate est.scaleFactor( upscale_factor ); auto beta = color::WHITE * this->beta / group.count(); for( unsigned c=0; c<planes_amount; ++c ){ for( int i=0; i<iterations; i++ ){ if( ProgressWrapper(watcher).shouldCancel() ) return {}; auto output_copy = est[c]; //Improve estimate for( unsigned j=0; j<group.count(); j++, ProgressWrapper( watcher ).add() ) sign( output_copy, degrade( est[c], {group, j, c} ), group.image(j)[c], group.pos(j)-min_point , beta, channelScale(group, j, c)*upscale_factor ); //Regularization if( lambda > 0.0 ) regularize( est[c], output_copy, reg_size, alpha, beta, lambda ); else est[c] = output_copy; } //DEBUG: See how close our model gets to the input data for( unsigned j=0; j<group.count(); j++ ){ save( degrade( est[c], {group, j, c} ), "deg" + QString::number(c) + "-" + QString::number(j) ); save( group.image(j)[c], "low" + QString::number(c) + "-" + QString::number(j) ); } } return est; }
void LinearAligner::align( AContainer& container, AProcessWatcher* watcher ) const { LinearFunc hor, ver;//, both; for( unsigned i=0; i<container.count(); i++ ){ hor.add( i, container.pos(i).x ); ver.add( i, container.pos(i).y ); //both.add( pos(i).x, pos(i).y ); } for( unsigned i=0; i<container.count(); i++ ){ switch( method ){ case AlignMethod::BOTH: container.setPos( i, { hor(i), ver(i) } ); break; case AlignMethod::VER: container.setPos( i, { 0, ver(i) } ); break; case AlignMethod::HOR: container.setPos( i, { hor(i), 0 } ); break; }; } }
ImageEx AverageRender::render( const AContainer& aligner, AProcessWatcher* watcher ) const{ Timer t( "AverageRender::render()" ); //Abort if no images if( aligner.count() == 0 ){ qWarning( "No images to render!" ); return ImageEx(); } unsigned planes_amount = for_merging ? 1 : aligner.image(0).size(); ProgressWrapper( watcher ).setTotal( aligner.count() * planes_amount ); //Determine if we need to care about alpha per plane bool use_plane_alpha = false; for( unsigned i=0; i<aligner.count(); ++i ) if( aligner.alpha( i ) || aligner.imageMask( i ) >= 0 ){ use_plane_alpha = true; break; } //Check for movement in both direction auto movement = aligner.hasMovement(); if( movement.first && movement.second ) use_plane_alpha = true; auto color_space = aligner.image(0).getColorSpace(); ImageEx img( for_merging ? color_space.changed( Transform::GRAY ) : color_space ); AlphaScales masks; for( unsigned c=0; c<planes_amount; c++ ){ auto scale = upscale_chroma ? Point<double>(1,1) : aligner.image( 0 )[c].getSize().to<double>() / aligner.image( 0 )[0].getSize().to<double>(); masks.addScale( aligner, scale ); } auto min_point = aligner.minPoint(); auto full = aligner.size().size; for( unsigned c=0; c<planes_amount; c++ ){ //Determine local size auto scale = upscale_chroma ? Point<double>(1,1) : aligner.image( 0 )[c].getSize().to<double>() / aligner.image( 0 )[0].getSize().to<double>(); //TODO: something is wrong with the rounding, chroma-channels are slightly off SumPlane sum( (scale * full).ceil() ); sum.spacing = spacing; sum.offset = offset; for( unsigned j=0; j<aligner.count(); j++ ){ auto& image = aligner.image( j ); auto pos = (scale * (aligner.pos(j) - min_point)).round(); auto plane = getScaled( image[c], (scale * image[0].getSize()).round() ); const Plane& alpha_plane = masks.getAlpha( c, aligner.imageMask( j ), aligner.alpha( j ) ); if( use_plane_alpha && alpha_plane.valid() ) sum.addAlphaPlane( plane(), alpha_plane, pos ); else sum.addPlane( plane(), pos ); ProgressWrapper( watcher ).add(); } img.addPlane( sum.average() ); if( c == 0 && use_plane_alpha ) img.alpha_plane() = sum.alpha(); //TODO: what to do about the rest? We should try to fill in the gaps? } return img; }