]> git.sesse.net Git - movit/blob - deconvolution_sharpen_effect.h
Hard-assert on something that has bitten me too many times now.
[movit] / deconvolution_sharpen_effect.h
1 #ifndef _MOVIT_DECONVOLUTION_SHARPEN_EFFECT_H
2 #define _MOVIT_DECONVOLUTION_SHARPEN_EFFECT_H 1
3
4 // DeconvolutionSharpenEffect is an effect that sharpens by way of deconvolution
5 // (i.e., trying to reverse the blur kernel, as opposed to just boosting high
6 // frequencies), more specifically by FIR Wiener filters. It is the same
7 // algorithm as used by the (now largely abandoned) Refocus plug-in for GIMP,
8 // and I suspect the same as in Photoshop's “Smart Sharpen” filter.
9 // The implementation is, however, distinct from either.
10 //
11 // The effect gives generally better results than unsharp masking, but can be very
12 // GPU intensive, and requires a fair bit of tweaking to get good results without
13 // ringing and/or excessive noise. It should be mentioned that for the larger
14 // convolutions (e.g. R approaching 10), we should probably move to FFT-based
15 // convolution algorithms, especially as Mesa's shader compiler starts having
16 // problems compiling our shader.
17 //
18 // We follow the same book as Refocus was implemented from, namely
19 //
20 //   Jain, Anil K.: “Fundamentals of Digital Image Processing”, Prentice Hall, 1988.
21
22 #include <epoxy/gl.h>
23 #include <Eigen/Dense>
24 #include <string>
25
26 #include "effect.h"
27
28 namespace movit {
29
30 class DeconvolutionSharpenEffect : public Effect {
31 public:
32         DeconvolutionSharpenEffect();
33         virtual ~DeconvolutionSharpenEffect();
34         virtual std::string effect_type_id() const { return "DeconvolutionSharpenEffect"; }
35         std::string output_fragment_shader();
36
37         // Samples a lot of times from its input.
38         virtual bool needs_texture_bounce() const { return true; }
39
40         virtual void inform_input_size(unsigned input_num, unsigned width, unsigned height)
41         {
42                 this->width = width;
43                 this->height = height;
44         }
45
46         void set_gl_state(GLuint glsl_program_num, const std::string &prefix, unsigned *sampler_num);
47         virtual AlphaHandling alpha_handling() const { return INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK; }
48
49 private:
50         // Input size.
51         unsigned width, height;
52
53         // The maximum radius of the (de)convolution kernel.
54         // Note that since this extends both ways, and we also have a center element,
55         // the actual convolution matrix will be (2R + 1) x (2R + 1).
56         //
57         // Must match the definition in the shader, and as such, cannot be set once
58         // the chain has been finalized.
59         int R;
60
61         // The parameters. Typical OK values are circle_radius = 2, gaussian_radius = 0
62         // (ie., blur is assumed to be a 2px circle), correlation = 0.95, and noise = 0.01.
63         // Note that once the radius starts going too far past R, you will get nonsensical results.
64         float circle_radius, gaussian_radius, correlation, noise;
65
66         // The deconvolution kernel, and the parameters last time we did an update.
67         Eigen::MatrixXf g;
68         int last_R;
69         float last_circle_radius, last_gaussian_radius, last_correlation, last_noise;
70
71         float *uniform_samples;
72         
73         void update_deconvolution_kernel();
74 };
75
76 }  // namespace movit
77
78 #endif // !defined(_MOVIT_DECONVOLUTION_SHARPEN_EFFECT_H)