diff options
Diffstat (limited to 'src/libs/greycstoration/greycstorationiface.cpp')
-rw-r--r-- | src/libs/greycstoration/greycstorationiface.cpp | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/src/libs/greycstoration/greycstorationiface.cpp b/src/libs/greycstoration/greycstorationiface.cpp new file mode 100644 index 00000000..32f60514 --- /dev/null +++ b/src/libs/greycstoration/greycstorationiface.cpp @@ -0,0 +1,473 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-12-03 + * Description : Greycstoration interface. + * + * Copyright (C) 2007-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program 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 2, or (at your option) + * any later version. + * + * This program 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. + * + * ============================================================ */ + +/** Don't use CImg interface (keyboard/mouse interaction) */ +#define cimg_display 0 +/** Only print debug information on the console */ +#define cimg_debug 1 + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +// C++ includes. + +#include <cassert> + +// Local includes. + +#define cimg_plugin "greycstoration.h" +// Unix-like (Linux, Solaris, BSD, MacOSX, Irix,...). +#if defined(unix) || defined(__unix) || defined(__unix__) \ + || defined(linux) || defined(__linux) || defined(__linux__) \ + || defined(sun) || defined(__sun) \ + || defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined __DragonFly__ \ + || defined(__MACOSX__) || defined(__APPLE__) \ + || defined(sgi) || defined(__sgi) \ + || defined(__CYGWIN__) +#include <pthread.h> +#endif + +/** Number of children threads used to run Greystoration algorithm + For the moment we use only one thread. See B.K.O #186642 for details. + Multithreading management need to be fixed into CImg. + */ +#define COMPUTATION_THREAD 2 + +/** Uncomment this line if you use future GreycStoration implementation with GFact parameter + */ +#define GREYSTORATION_USING_GFACT 1 + +// Local includes. + +#include "ddebug.h" +#include "greycstorationsettings.h" +#include "greycstorationiface.h" + +// CImg includes. + +#include "CImg.h" + +using namespace cimg_library; + +namespace Digikam +{ + +class GreycstorationIfacePriv +{ + +public: + + GreycstorationIfacePriv() + { + mode = GreycstorationIface::Restore; + gfact = 1.0; + } + + float gfact; + + int mode; // The interface running mode. + + TQImage inPaintingMask; // Mask for inpainting. + + GreycstorationSettings settings; // Current Greycstoraion algorithm settings. + + CImg<> img; // Main image. + CImg<uchar> mask; // The mask used with inpaint or resize mode +}; + +GreycstorationIface::GreycstorationIface(DImg *orgImage, + GreycstorationSettings settings, + int mode, + int newWidth, int newHeight, + const TQImage& inPaintingMask, + TQObject *parent) + : DImgThreadedFilter(orgImage, parent) +{ + d = new GreycstorationIfacePriv; + d->settings = settings; + d->mode = mode; + d->inPaintingMask = inPaintingMask; + + if (m_orgImage.sixteenBit()) // 16 bits image. + d->gfact = 1.0/256.0; + + if (d->mode == Resize || d->mode == SimpleResize) + { + m_destImage = DImg(newWidth, newHeight, + m_orgImage.sixteenBit(), m_orgImage.hasAlpha()); + DDebug() << "GreycstorationIface::Resize: new size: (" + << newWidth << ", " << newHeight << ")" << endl; + } + else + { + m_destImage = DImg(m_orgImage.width(), m_orgImage.height(), + m_orgImage.sixteenBit(), m_orgImage.hasAlpha()); + } + + initFilter(); +} + +GreycstorationIface::~GreycstorationIface() +{ + delete d; +} + +// We need to re-implemente this method from DImgThreadedFilter class because +// target image size can be different from original if d->mode = Resize. + +void GreycstorationIface::initFilter() +{ + if (m_orgImage.width() && m_orgImage.height()) + { + if (m_parent) + start(); // m_parent is valide, start thread ==> run() + else + startComputation(); // no parent : no using thread. + } + else // No image data + { + if (m_parent) // If parent then send event about a problem. + { + postProgress(0, false, false); + DDebug() << m_name << "::No valid image data !!! ..." << endl; + } + } +} + +void GreycstorationIface::stopComputation() +{ + // Because Greycstoration algorithm run in a child thread, we need + // to stop it before to stop this thread. + if (d->img.greycstoration_is_running()) + { + // If the user abort, we stop the algorithm. + DDebug() << "Stop Greycstoration computation..." << endl; + d->img.greycstoration_stop(); + } + + // And now when stop main loop and clean up all + DImgThreadedFilter::stopComputation(); +} + +void GreycstorationIface::filterImage() +{ + int x, y; + + DDebug() << "GreycstorationIface::Initialization..." << endl; + + // Copy the src image data into a CImg type image with three channels and no alpha. + + uchar* imageData = m_orgImage.bits(); + int imageWidth = m_orgImage.width(); + int imageHeight = m_orgImage.height(); + d->img = CImg<>(imageWidth, imageHeight, 1, 4); + + if (!m_orgImage.sixteenBit()) // 8 bits image. + { + uchar *ptr = imageData; + + for (y = 0; y < imageHeight; y++) + { + for (x = 0; x < imageWidth; x++) + { + d->img(x, y, 0) = ptr[0]; // Blue. + d->img(x, y, 1) = ptr[1]; // Green. + d->img(x, y, 2) = ptr[2]; // Red. + d->img(x, y, 3) = ptr[3]; // Alpha. + ptr += 4; + } + } + } + else // 16 bits image. + { + unsigned short *ptr = (unsigned short *)imageData; + + for (y = 0; y < imageHeight; y++) + { + for (x = 0; x < imageWidth; x++) + { + d->img(x, y, 0) = ptr[0]; // Blue. + d->img(x, y, 1) = ptr[1]; // Green. + d->img(x, y, 2) = ptr[2]; // Red. + d->img(x, y, 3) = ptr[3]; // Alpha. + ptr += 4; + } + } + } + + DDebug() << "GreycstorationIface::Process Computation..." << endl; + + try + { + switch (d->mode) + { + case Restore: + restoration(); + break; + + case InPainting: + inpainting(); + break; + + case Resize: + resize(); + break; + + case SimpleResize: + simpleResize(); + break; + } + } + catch(...) // Everything went wrong. + { + DDebug() << "GreycstorationIface::Error during Greycstoration filter computation!" << endl; + + if (m_parent) + postProgress( 0, false, false ); + + return; + } + + if (m_cancel) + return; + + // Copy CImg onto destination. + + DDebug() << "GreycstorationIface::Finalization..." << endl; + + uchar* newData = m_destImage.bits(); + int newWidth = m_destImage.width(); + int newHeight = m_destImage.height(); + + if (!m_orgImage.sixteenBit()) // 8 bits image. + { + uchar *ptr = newData; + + for (y = 0; y < newHeight; y++) + { + for (x = 0; x < newWidth; x++) + { + // Overwrite RGB values to destination. + ptr[0] = static_cast<uchar>(d->img(x, y, 0)); // Blue + ptr[1] = static_cast<uchar>(d->img(x, y, 1)); // Green + ptr[2] = static_cast<uchar>(d->img(x, y, 2)); // Red + ptr[3] = static_cast<uchar>(d->img(x, y, 3)); // Alpha + ptr += 4; + } + } + } + else // 16 bits image. + { + unsigned short *ptr = (unsigned short *)newData; + + for (y = 0; y < newHeight; y++) + { + for (x = 0; x < newWidth; x++) + { + // Overwrite RGB values to destination. + ptr[0] = static_cast<unsigned short>(d->img(x, y, 0)); // Blue + ptr[1] = static_cast<unsigned short>(d->img(x, y, 1)); // Green + ptr[2] = static_cast<unsigned short>(d->img(x, y, 2)); // Red + ptr[3] = static_cast<unsigned short>(d->img(x, y, 3)); // Alpha + ptr += 4; + } + } + } +} + +void GreycstorationIface::restoration() +{ + for (uint iter = 0 ; !m_cancel && (iter < d->settings.nbIter) ; iter++) + { + // This function will start a thread running one iteration of the GREYCstoration filter. + // It returns immediately, so you can do what you want after (update a progress bar for + // instance). + d->img.greycstoration_run(d->settings.amplitude, + d->settings.sharpness, + d->settings.anisotropy, + d->settings.alpha, + d->settings.sigma, +#ifdef GREYSTORATION_USING_GFACT + d->gfact, +#endif + d->settings.dl, + d->settings.da, + d->settings.gaussPrec, + d->settings.interp, + d->settings.fastApprox, + d->settings.tile, + d->settings.btile, + COMPUTATION_THREAD); + + iterationLoop(iter); + } +} + +void GreycstorationIface::inpainting() +{ + if (!d->inPaintingMask.isNull()) + { + // Copy the inpainting image data into a CImg type image with three channels and no alpha. + + int x, y; + + d->mask = CImg<uchar>(d->inPaintingMask.width(), d->inPaintingMask.height(), 1, 3); + uchar *ptr = d->inPaintingMask.bits(); + + for (y = 0; y < d->inPaintingMask.height(); y++) + { + for (x = 0; x < d->inPaintingMask.width(); x++) + { + d->mask(x, y, 0) = ptr[2]; // blue. + d->mask(x, y, 1) = ptr[1]; // green. + d->mask(x, y, 2) = ptr[0]; // red. + ptr += 4; + } + } + } + else + { + DDebug() << "Inpainting image: mask is null!" << endl; + m_cancel = true; + return; + } + + for (uint iter=0 ; !m_cancel && (iter < d->settings.nbIter) ; iter++) + { + // This function will start a thread running one iteration of the GREYCstoration filter. + // It returns immediately, so you can do what you want after (update a progress bar for + // instance). + d->img.greycstoration_run(d->mask, + d->settings.amplitude, + d->settings.sharpness, + d->settings.anisotropy, + d->settings.alpha, + d->settings.sigma, +#ifdef GREYSTORATION_USING_GFACT + d->gfact, +#endif + d->settings.dl, + d->settings.da, + d->settings.gaussPrec, + d->settings.interp, + d->settings.fastApprox, + d->settings.tile, + d->settings.btile, + COMPUTATION_THREAD); + + iterationLoop(iter); + } +} + +void GreycstorationIface::resize() +{ + const bool anchor = true; // Anchor original pixels. + const unsigned int init = 5; // Initial estimate (1=block, 3=linear, 5=bicubic). + + int w = m_destImage.width(); + int h = m_destImage.height(); + + d->mask.assign(d->img.dimx(), d->img.dimy(), 1, 1, 255); + + if (!anchor) + d->mask.resize(w, h, 1, 1, 1); + else + d->mask = !d->mask.resize(w, h, 1, 1, 4); + + d->img.resize(w, h, 1, -100, init); + + for (uint iter = 0 ; !m_cancel && (iter < d->settings.nbIter) ; iter++) + { + // This function will start a thread running one iteration of the GREYCstoration filter. + // It returns immediately, so you can do what you want after (update a progress bar for + // instance). + d->img.greycstoration_run(d->mask, + d->settings.amplitude, + d->settings.sharpness, + d->settings.anisotropy, + d->settings.alpha, + d->settings.sigma, +#ifdef GREYSTORATION_USING_GFACT + d->gfact, +#endif + d->settings.dl, + d->settings.da, + d->settings.gaussPrec, + d->settings.interp, + d->settings.fastApprox, + d->settings.tile, + d->settings.btile, + COMPUTATION_THREAD); + + iterationLoop(iter); + } +} + +void GreycstorationIface::simpleResize() +{ + const unsigned int method = 3; // Initial estimate (0, none, 1=block, 3=linear, 4=grid, 5=bicubic). + + int w = m_destImage.width(); + int h = m_destImage.height(); + + while (d->img.dimx() > 2*w && + d->img.dimy() > 2*h) + { + d->img.resize_halfXY(); + } + + d->img.resize(w, h, -100, -100, method); +} + +void GreycstorationIface::iterationLoop(uint iter) +{ + uint mp = 0; + uint p = 0; + + do + { + usleep(100000); + + if (m_parent && !m_cancel) + { + // Update the progress bar in dialog. We simply computes the global + // progression index (including all iterations). + + p = (uint)((iter*100 + d->img.greycstoration_progress())/d->settings.nbIter); + + if (p > mp) + { + postProgress(p); + mp = p; + } + } + } + while (d->img.greycstoration_is_running() && !m_cancel); + + // A delay is require here. I suspect a sync problem between threads + // used by GreycStoration algorithm. + usleep(100000); +} + +} // NameSpace Digikam |