2
* * Copyright (C) 2006-2011 Anders Brander <anders@brander.dk>,
3
* * Anders Kvist <akv@lnxbx.dk> and Klaus Post <klauspost@gmail.com>
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* as published by the Free Software Foundation; either version 2
8
* of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
#include "fftdenoiser.h"
21
#include "complexblock.h"
22
#include "fftdenoiseryuv.h"
25
int rs_get_number_of_processor_cores(){return 4;}
32
FFTDenoiser::FFTDenoiser(void)
34
nThreads = rs_get_number_of_processor_cores();
35
threads = new DenoiseThread[nThreads];
37
FloatPlanarImage::initConvTable();
40
FFTDenoiser::~FFTDenoiser(void)
43
fftwf_destroy_plan(plan_forward);
44
fftwf_destroy_plan(plan_reverse);
47
void FFTDenoiser::denoiseImage( RS_IMAGE16* image )
50
img.bw = FFT_BLOCK_SIZE;
51
img.bh = FFT_BLOCK_SIZE;
52
img.ox = FFT_BLOCK_OVERLAP;
53
img.oy = FFT_BLOCK_OVERLAP;
55
if ((image->w < FFT_BLOCK_SIZE) || (image->h < FFT_BLOCK_SIZE))
56
return; // Image too small to denoise
58
if (image->channels > 1 && image->filters==0) {
59
img.unpackInterleaved(image);
68
FFTWindow window(img.bw,img.bh);
69
window.createHalfCosineWindow(img.ox, img.oy);
71
ComplexFilter *filter = new ComplexWienerFilterDeGrid(img.bw, img.bh, beta, sigma, 1.0, plan_forward, &window);
72
filter->setSharpen(sharpen, sharpenMinSigma, sharpenMaxSigma, sharpenCutoff);
73
img.setFilter(0,filter,&window);
75
filter = new ComplexWienerFilterDeGrid(img.bw, img.bh, beta, sigma, 1.0, plan_forward, &window);
76
filter->setSharpen(sharpen, sharpenMinSigma, sharpenMaxSigma, sharpenCutoff);
77
img.setFilter(1,filter,&window);
79
filter = new ComplexWienerFilterDeGrid(img.bw, img.bh, beta, sigma, 1.0, plan_forward, &window);
80
filter->setSharpen(sharpen, sharpenMinSigma, sharpenMaxSigma, sharpenCutoff);
81
img.setFilter(2,filter,&window);
83
FloatPlanarImage outImg(img);
85
processJobs(img, outImg);
89
if (image->channels > 1 && image->filters==0) {
90
outImg.packInterleaved(image);
94
void FFTDenoiser::processJobs(FloatPlanarImage &img, FloatPlanarImage &outImg)
96
// Prepare for reassembling the image
97
outImg.allocate_planes();
99
JobQueue* waiting_jobs = img.getJobs(outImg);
100
JobQueue* finished_jobs = new JobQueue();
102
// Count waiting jobs
103
gint njobs = waiting_jobs->jobsLeft();
105
for (guint i = 0; i < nThreads; i++) {
106
threads[i].addJobs(waiting_jobs,finished_jobs);
111
while (jobs_added < njobs) {
112
Job *_j = finished_jobs->waitForJob();
114
if (_j->type == JOB_FFT) {
118
jobs_added += waiting_jobs->removeRemaining();
119
jobs_added += finished_jobs->removeRemaining();
124
for (guint i = 0; i < nThreads; i++)
125
threads[i].jobsEnded();
127
delete finished_jobs;
131
void FFTDenoiser::waitForJobs(JobQueue *waiting_jobs)
133
JobQueue* finished_jobs = new JobQueue();
135
gint njobs = waiting_jobs->jobsLeft();
137
for (guint i = 0; i < nThreads; i++) {
138
threads[i].addJobs(waiting_jobs,finished_jobs);
142
while (jobs_added < njobs) {
143
Job *j = finished_jobs->waitForJob();
148
for (guint i = 0; i < nThreads; i++)
149
threads[i].jobsEnded();
152
delete finished_jobs;
155
gboolean FFTDenoiser::initializeFFT()
157
// Create dummy block
158
FloatImagePlane plane(FFT_BLOCK_SIZE,FFT_BLOCK_SIZE);
159
plane.allocateImage();
160
ComplexBlock complex(FFT_BLOCK_SIZE,FFT_BLOCK_SIZE);
162
dim[0] = FFT_BLOCK_SIZE;
163
dim[1] = FFT_BLOCK_SIZE;
164
plan_forward = fftwf_plan_dft_r2c(2, dim, plane.data, complex.complex,FFTW_MEASURE|FFTW_DESTROY_INPUT);
165
plan_reverse = fftwf_plan_dft_c2r(2, dim, complex.complex, plane.data,FFTW_MEASURE|FFTW_DESTROY_INPUT);
166
for (guint i = 0; i < nThreads; i++) {
167
threads[i].forward = plan_forward;
168
threads[i].reverse = plan_reverse;
170
return (plan_forward && plan_reverse);
174
void FFTDenoiser::setParameters( FFTDenoiseInfo *info )
176
sigma = info->sigmaLuma *SIGMA_FACTOR;
177
beta = max(1.0f, info->betaLuma);
178
sharpen = info->sharpenLuma;
179
sharpenCutoff = info->sharpenCutoffLuma;
180
sharpenMinSigma = info->sharpenMinSigmaLuma*SIGMA_FACTOR;
181
sharpenMaxSigma = info->sharpenMaxSigmaLuma*SIGMA_FACTOR;
184
}}// namespace RawStudio::FFTFilter
190
void initDenoiser(FFTDenoiseInfo* info) {
191
RawStudio::FFTFilter::FFTDenoiser *t;
192
switch (info->processMode) {
194
t = new RawStudio::FFTFilter::FFTDenoiser();
197
t = new RawStudio::FFTFilter::FFTDenoiserYUV();
203
// Initialize parameters to default
204
info->betaLuma = 1.0f;
205
info->betaChroma = 1.0f;
206
info->sigmaLuma = 1.0f;
207
info->sigmaChroma = 1.0f;
208
info->sharpenLuma = 0.0f;
209
info->sharpenChroma = 0.0f;
210
info->sharpenCutoffLuma = 0.10f;
211
info->sharpenCutoffChroma = 0.3f;
212
info->sharpenMinSigmaLuma = 4.0f;
213
info->sharpenMinSigmaChroma = 4.0f;
214
info->sharpenMaxSigmaLuma = 20.0f;
215
info->sharpenMaxSigmaChroma = 20.0f;
216
info->redCorrection = 1.0f;
217
info->blueCorrection = 1.0f;
220
void denoiseImage(FFTDenoiseInfo* info) {
221
RawStudio::FFTFilter::FFTDenoiser *t = (RawStudio::FFTFilter::FFTDenoiser*)info->_this;
223
t->setParameters(info);
224
t->denoiseImage(info->image);
227
void destroyDenoiser(FFTDenoiseInfo* info) {
228
RawStudio::FFTFilter::FFTDenoiser *t = (RawStudio::FFTFilter::FFTDenoiser*)info->_this;
232
void abortDenoiser(FFTDenoiseInfo* info) {
233
RawStudio::FFTFilter::FFTDenoiser *t = (RawStudio::FFTFilter::FFTDenoiser*)info->_this;