Skip to content

Commit

Permalink
ADD: Simple focus stacking
Browse files Browse the repository at this point in the history
  • Loading branch information
spillerrec committed Dec 27, 2020
1 parent 24cf2f3 commit 126837c
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 0 deletions.
22 changes: 22 additions & 0 deletions interface/gui/configs/RenderConfigs.cpp
Expand Up @@ -23,6 +23,7 @@
#include "renders/AverageRender.hpp"
#include "renders/DiffRender.hpp"
#include "renders/FastRender.hpp"
#include "renders/FocusStackingRender.hpp"
#include "renders/FloatRender.hpp"
#include "renders/StatisticsRender.hpp"
#include "renders/RobustSrRender.hpp"
Expand Down Expand Up @@ -63,6 +64,7 @@ void RenderConfigChooser::p_initialize(){
set( &addConfig<JpegConstrainerRenderConfig>() );
set( &addConfig<DistanceMatrixRenderConfig>() );
set( &addConfig<FastRenderConfig>() );
set( &addConfig<FocusStackingRenderConfig>() );
}

std::unique_ptr<ARender> RenderConfigChooser::getRender() const
Expand Down Expand Up @@ -234,4 +236,24 @@ std::unique_ptr<ARender> JpegConstrainerRenderConfig::getRender() const

std::unique_ptr<ARender> DistanceMatrixRenderConfig::getRender() const
{ return std::make_unique<DistanceMatrixRender>(); }


FocusStackingRenderConfig::FocusStackingRenderConfig( QWidget* parent )
: ARenderConfig( parent ) {
setLayout( new QVBoxLayout( this ) );
blur_amount = addWidget<QDoubleSpinBox>("Blurring");
kernel_size = addWidget<QSpinBox>("Size");

blur_amount->setRange(0, 999);
blur_amount->setDecimals(3);
blur_amount->setValue( 0.0 );

kernel_size->setRange(0, 999);
kernel_size->setValue( 15 );
}
std::unique_ptr<ARender> FocusStackingRenderConfig::getRender() const {
auto amount = blur_amount->value();
auto size = kernel_size->value();
return std::make_unique<FocusStackingRender>( amount, size );
}

12 changes: 12 additions & 0 deletions interface/gui/configs/RenderConfigsInternal.hpp
Expand Up @@ -79,6 +79,18 @@ class DiffRenderConfig : public ARenderConfig{
QString discription() const override{ return "Detects static content (logo, credits, etc.)"; }
};

class FocusStackingRenderConfig : public ARenderConfig{
private:
QDoubleSpinBox* blur_amount;
QSpinBox* kernel_size;
public:
explicit FocusStackingRenderConfig( QWidget* parent );
std::unique_ptr<ARender> getRender() const override;

QString name() const override { return "Focus Stacking"; }
QString discription() const override{ return "Combine focus stacked images"; }
};

class FloatRenderConfig : public ARenderConfig{
public:
explicit FloatRenderConfig( QWidget* parent ) : ARenderConfig( parent ) { }
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -60,6 +60,7 @@ set(SOURCES_RENDERS
renders/AnimRender.cpp
renders/AverageRender.cpp
renders/FastRender.cpp
renders/FocusStackingRender.cpp
renders/FloatRender.cpp
renders/DiffRender.cpp
renders/DistanceMatrixRender.cpp
Expand Down
135 changes: 135 additions & 0 deletions src/renders/FocusStackingRender.cpp
@@ -0,0 +1,135 @@
/*
This file is part of Overmix.
Overmix is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Overmix is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Overmix. If not, see <http://www.gnu.org/licenses/>.
*/


#include "FocusStackingRender.hpp"
#include "../debug.hpp"

#include "../containers/AContainer.hpp"
#include "../planes/ImageEx.hpp"
#include "../utils/AProcessWatcher.hpp"
#include "../utils/PlaneUtils.hpp"

#include <QTime>
#include <QImage>
#include <vector>
using namespace std;
using namespace Overmix;

ImageEx diff( const ImageEx& img1, const ImageEx& img2 )
{
ImageEx out(img1);
for (int i=0; i<(int)out.size(); i++)
out[i].substract( img2[i] );
return out;
}


ImageEx FocusStackingRender::render( const AContainer& aligner, AProcessWatcher* watcher ) const{
Timer t( "FocusStackingRender::render()" );

auto makeError = [](const char* msg){
qWarning( "%s", msg );
return ImageEx();
};

//Abort if no images
if( aligner.count() == 0 )
return makeError( "No images to render!" );

Progress progress( "FocusStackingRender", aligner.count() * 1, watcher );

//Determine if we need to care about alpha per plane
// for( unsigned i=0; i<aligner.count(); ++i )
// if( aligner.alpha( i ) || aligner.imageMask( i ) >= 0 )
// return makeError( "Alpha not supported in FocusStacking" );

//Check for movement in both direction
auto movement = aligner.hasMovement();
if( movement.first && movement.second )
return makeError( "No movement support in FocusStacking yet" );


std::vector<Plane> planes;
for( unsigned i=0; i<aligner.count(); i++){
if( progress.shouldCancel() )
return {};

auto inputImg = aligner.image(i);
inputImg.to_grayscale();

planes.push_back( inputImg[0].edge_sobel() );

progress.add();
}


auto out = ImageEx(aligner.image(0));
auto size = planes[0].getSize();
Plane selected( size );
Plane weight( size );

for( int y=0; y<(int)size.height(); y++ )
for( int x=0; x<(int)size.width(); x++ ){
int best = 0;
int id = 0;
for( int i=0; i<(int)aligner.count(); i++ ){
auto val = planes[i][y][x];
if( val > best ){
best = val;
id = i;
}
}

selected[y][x] = id;// * 256;
weight[y][x] = best;
}

Plane selected_filter( selected );
int k = kernel_size;
for(int y=k; y<(int)size.height()-k; y++)
for (int x=k; x<(int)size.width()-k; x++)
{
int best = 0;
int id = 0;
for( int i=-k; i<=k; i++ )
for( int j=-k; j<=k; j++ ){
auto val = weight[y+i][x+j];
if( val > best ){
best = val;
id = selected[y+i][x+j];
}
}
selected_filter[y][x] = id;
}

for( int y=0; y<(int)size.height(); y++ )
for ( int x=0; x<(int)size.width(); x++ ){
auto id = selected_filter[y][x];// / 256;
auto& img = aligner.image(id);
for( int c=0; c<(int)img.size(); c++ )
out[c][y][x] = img[c][y][x];
}

// ImageEx(Plane(selected)).to_qimage().save("selected.png");
// ImageEx(Plane(selected_filter)).to_qimage().save("selected_filter.png");
// ImageEx(Plane(weight)).to_qimage().save("weight.png");
return out;
}



44 changes: 44 additions & 0 deletions src/renders/FocusStackingRender.hpp
@@ -0,0 +1,44 @@
/*
This file is part of Overmix.
Overmix is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Overmix is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Overmix. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef FOCUS_STACKING_RENDER_HPP
#define FOCUS_STACKING_RENDER_HPP

#include "ARender.hpp"

#include "../color.hpp"
#include "../planes/PlaneBase.hpp"

namespace Overmix{

class FocusStackingRender : public ARender{
protected:
double blur_amount;
int kernel_size;

public:
FocusStackingRender( double blur_amount, int kernel_size )
: blur_amount(blur_amount), kernel_size(kernel_size) { }

virtual ImageEx render( const AContainer& group, AProcessWatcher* watcher=nullptr ) const override;

void setBlurAmount( double val ){ blur_amount = val; }
};

}

#endif

0 comments on commit 126837c

Please sign in to comment.