1
/* ============================================================
4
* Description : a tool to fix automatically camera lens aberrations
6
* Copyright (C) 2008 by Adrian Schroeter <adrian at suse dot de>
7
* Copyright (C) 2008-2010 by Gilles Caulier <caulier dot gilles at gmail dot com>
9
* This program is free software; you can redistribute it
10
* and/or modify it under the terms of the GNU General
11
* Public License as published by the Free Software Foundation;
12
* either version 2, or (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* ============================================================ */
21
#include "lensfunfilter.h"
35
#include "lensfuniface.h"
36
#include "dmetadata.h"
41
class LensFunFilter::LensFunFilterPriv
56
LensFunFilter::LensFunFilter(QObject* parent)
57
: DImgThreadedFilter(parent),
58
d(new LensFunFilterPriv)
60
d->iface = new LensFunIface;
64
LensFunFilter::LensFunFilter(DImg* orgImage, QObject* parent, const LensFunContainer& settings)
65
: DImgThreadedFilter(orgImage, parent, "LensCorrection"),
66
d(new LensFunFilterPriv)
68
d->iface = new LensFunIface;
69
d->iface->setSettings(settings);
73
LensFunFilter::~LensFunFilter()
79
d->modifier->Destroy();
86
void LensFunFilter::filterImage()
88
m_destImage.bitBltImage(&m_orgImage, 0, 0);
92
kError() << "ERROR: LensFun Interface is null.";
96
if (!d->iface->usedLens())
98
kError() << "ERROR: LensFun Interface Lens device is null.";
102
// Lensfun Modifier flags to process
106
if ( d->iface->settings().filterDST )
108
modifyFlags |= LF_MODIFY_DISTORTION;
111
if ( d->iface->settings().filterGEO )
113
modifyFlags |= LF_MODIFY_GEOMETRY;
116
if ( d->iface->settings().filterCCA )
118
modifyFlags |= LF_MODIFY_TCA;
121
if ( d->iface->settings().filterVIG )
123
modifyFlags |= LF_MODIFY_VIGNETTING;
126
if ( d->iface->settings().filterCCI )
128
modifyFlags |= LF_MODIFY_CCI;
131
// Init lensfun lib, we are working on the full image.
133
lfPixelFormat colorDepth = m_orgImage.bytesDepth() == 4 ? LF_PF_U8 : LF_PF_U16;
135
d->modifier = lfModifier::Create(d->iface->usedLens(),
136
d->iface->settings().cropFactor,
138
m_orgImage.height());
140
int modflags = d->modifier->Initialize(d->iface->usedLens(),
142
d->iface->settings().focalLength,
143
d->iface->settings().aperture,
144
d->iface->settings().subjectDistance,
145
d->iface->settings().cropFactor,
152
kError() << "ERROR: cannot initialize LensFun Modifier.";
156
// Calc necessary steps for progress bar
158
int steps = ( d->iface->settings().filterCCA ) ? 1 : 0 +
159
( d->iface->settings().filterVIG || d->iface->settings().filterCCI ) ? 1 : 0 +
160
( d->iface->settings().filterDST || d->iface->settings().filterGEO ) ? 1 : 0;
162
kDebug() << "LensFun Modifier Flags: " << modflags << " Steps:" << steps;
166
kDebug() << "No LensFun Modifier steps. There is nothing to process...";
170
// The real correction to do
173
int lwidth = m_orgImage.width() * 2 * 3;
174
float* pos = new float[lwidth];
176
kDebug() << "Image size to process: (" << m_orgImage.width() << ", " << m_orgImage.height() << ")";
178
// Stage 1: Chromatic Aberation Corrections
180
if ( d->iface->settings().filterCCA )
182
m_orgImage.prepareSubPixelAccess(); // init lanczos kernel
184
for (unsigned int y=0; runningFlag() && (y < m_orgImage.height()); ++y)
186
if (d->modifier->ApplySubpixelDistortion(0.0, y, m_orgImage.width(), 1, pos))
190
for (unsigned x = 0; runningFlag() && (x < m_destImage.width()); ++x)
192
DColor destPixel(0, 0, 0, 0xFFFF, m_destImage.sixteenBit());
194
destPixel.setRed (m_orgImage.getSubPixelColorFast(src[0], src[1]).red() );
195
destPixel.setGreen(m_orgImage.getSubPixelColorFast(src[2], src[3]).green() );
196
destPixel.setBlue (m_orgImage.getSubPixelColorFast(src[4], src[5]).blue() );
198
m_destImage.setPixelColor(x, y, destPixel);
205
// Update progress bar in dialog.
206
int progress = (int)(((double)y * 100.0) / m_orgImage.height());
210
postProgress(progress/steps);
214
kDebug() << "Chromatic Aberation Corrections applied. (loop: " << loop << ")";
217
// Stage 2: Color Corrections: Vignetting and Color Contribution Index
219
if ( d->iface->settings().filterVIG || d->iface->settings().filterCCI )
221
uchar* data = m_destImage.bits();
229
else if (steps == 2 && d->iface->settings().filterCCA)
234
for (unsigned int y=0; runningFlag() && (y < m_destImage.height()); ++y)
236
if (d->modifier->ApplyColorModification(data, 0.0, y, m_destImage.width(),
237
1, m_destImage.bytesDepth(), 0))
239
data += m_destImage.height() * m_destImage.bytesDepth();
243
// Update progress bar in dialog.
244
int progress = (int)(((double)y * 100.0) / m_destImage.height());
248
postProgress(progress/steps + offset);
252
kDebug() << "Vignetting and Color Corrections applied. (loop: " << loop << ")";
255
// Stage 3: Distortion and Geometry Corrections
257
if ( d->iface->settings().filterDST || d->iface->settings().filterGEO )
261
// we need a deep copy first
262
DImg tempImage(m_destImage.width(), m_destImage.height(), m_destImage.sixteenBit(), m_destImage.hasAlpha());
263
m_destImage.prepareSubPixelAccess(); // init lanczos kernel
265
for (unsigned long y=0; runningFlag() && (y < tempImage.height()); ++y)
267
if (d->modifier->ApplyGeometryDistortion(0.0, y, tempImage.width(), 1, pos))
271
for (unsigned long x = 0; runningFlag() && (x < tempImage.width()); ++x, ++loop)
273
//kDebug() << " ZZ " << src[0] << " " << src[1] << " " << (int)src[0] << " " << (int)src[1];
275
tempImage.setPixelColor(x, y, m_destImage.getSubPixelColor(src[0], src[1]));
280
// Update progress bar in dialog.
281
int progress = (int)(((double)y * 100.0) / tempImage.height());
285
postProgress(progress/steps + 33.3*(steps-1));
289
kDebug() << "Distortion and Geometry Corrections applied. (loop: " << loop << ")";
293
m_destImage = tempImage;
302
bool LensFunFilter::registerSettingsToXmp(KExiv2Data& data) const
304
// Register in digiKam Xmp namespace all information about Lens corrections.
307
LensFunContainer prm = d->iface->settings();
309
str.append(i18n("Camera: %1-%2", prm.cameraMake, prm.cameraModel));
311
str.append(i18n("Lens: %1", prm.lensModel));
313
str.append(i18n("Subject Distance: %1", QString::number(prm.subjectDistance)));
315
str.append(i18n("Aperture: %1", QString::number(prm.aperture)));
317
str.append(i18n("Focal Length: %1", QString::number(prm.focalLength)));
319
str.append(i18n("Crop Factor: %1", QString::number(prm.cropFactor)));
321
str.append(i18n("CCA Correction: %1", prm.filterCCA && d->iface->supportsCCA() ? i18n("enabled") : i18n("disabled")));
323
str.append(i18n("VIG Correction: %1", prm.filterVIG && d->iface->supportsVig() ? i18n("enabled") : i18n("disabled")));
325
str.append(i18n("CCI Correction: %1", prm.filterCCI && d->iface->supportsCCI() ? i18n("enabled") : i18n("disabled")));
327
str.append(i18n("DST Correction: %1", prm.filterDST && d->iface->supportsDistortion() ? i18n("enabled") : i18n("disabled")));
329
str.append(i18n("GEO Correction: %1", prm.filterGEO && d->iface->supportsGeometry() ? i18n("enabled") : i18n("disabled")));
331
DMetadata meta(data);
332
bool ret = meta.setXmpTagString("Xmp.digiKam.LensCorrectionSettings",
333
str.replace("\n", " ; "), false);
339
FilterAction LensFunFilter::filterAction()
341
FilterAction action(FilterIdentifier(), CurrentVersion());
342
action.setDisplayableName(DisplayableName());
344
LensFunContainer prm = d->iface->settings();
345
action.addParameter("ccaCorrection", prm.filterCCA);
346
action.addParameter("vigCorrection", prm.filterVIG);
347
action.addParameter("cciCorrection", prm.filterCCI);
348
action.addParameter("dstCorrection", prm.filterDST);
349
action.addParameter("geoCorrection", prm.filterGEO);
350
action.addParameter("cropFactor", prm.cropFactor);
351
action.addParameter("focalLength", prm.focalLength);
352
action.addParameter("aperture", prm.aperture);
353
action.addParameter("subjectDistance", prm.subjectDistance);
354
action.addParameter("cameraMake", prm.cameraMake);
355
action.addParameter("cameraModel", prm.cameraModel);
356
action.addParameter("lensModel", prm.lensModel);
361
void LensFunFilter::readParameters(const Digikam::FilterAction& action)
363
LensFunContainer prm = d->iface->settings();
364
prm.filterCCA = action.parameter("ccaCorrection").toBool();
365
prm.filterVIG = action.parameter("vigCorrection").toBool();
366
prm.filterCCI = action.parameter("cciCorrection").toBool();
367
prm.filterDST = action.parameter("dstCorrection").toBool();
368
prm.filterGEO = action.parameter("geoCorrection").toBool();
369
prm.cropFactor = action.parameter("cropFactor").toDouble();
370
prm.focalLength = action.parameter("focalLength").toDouble();
371
prm.aperture = action.parameter("aperture").toDouble();
372
prm.subjectDistance = action.parameter("subjectDistance").toDouble();
373
prm.cameraMake = action.parameter("cameraMake").toString();
374
prm.cameraModel = action.parameter("cameraModel").toString();
375
prm.lensModel = action.parameter("lensModel").toString();
376
d->iface->setSettings(prm);
379
} // namespace Digikam