diff options
Diffstat (limited to 'src/imageplugins/hotpixels')
19 files changed, 2473 insertions, 0 deletions
diff --git a/src/imageplugins/hotpixels/Makefile.am b/src/imageplugins/hotpixels/Makefile.am new file mode 100644 index 00000000..711fe84e --- /dev/null +++ b/src/imageplugins/hotpixels/Makefile.am @@ -0,0 +1,36 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/threadimageio \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_hotpixels_la_SOURCES = blackframeparser.cpp weights.cpp \ + hotpixelfixer.cpp imageplugin_hotpixels.cpp \ + blackframelistview.cpp hotpixelstool.cpp + +digikamimageplugin_hotpixels_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_hotpixels_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_hotpixels.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_hotpixels.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_hotpixels_ui.rc + diff --git a/src/imageplugins/hotpixels/TODO b/src/imageplugins/hotpixels/TODO new file mode 100644 index 00000000..880e1a36 --- /dev/null +++ b/src/imageplugins/hotpixels/TODO @@ -0,0 +1,4 @@ +- Store black frames. Include the fullsize image to be able to reedit it if necessary. +- Add a hand hot-pixel editor for the hot pixels on the black frame +- Use the same hot-pixel editor from the image view, to edit a new black frame with the added data + diff --git a/src/imageplugins/hotpixels/blackframelistview.cpp b/src/imageplugins/hotpixels/blackframelistview.cpp new file mode 100644 index 00000000..1202b094 --- /dev/null +++ b/src/imageplugins/hotpixels/blackframelistview.cpp @@ -0,0 +1,176 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-05 + * Description : a ListView to display black frames + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#define THUMB_WIDTH 150 + +// TQt includes. + +#include <tqpainter.h> +#include <tqtooltip.h> + +// Local includes. + +#include "blackframelistview.h" +#include "blackframelistview.moc" + +namespace DigikamHotPixelsImagesPlugin +{ + +BlackFrameListView::BlackFrameListView(TQWidget* parent) + : TQListView(parent) +{ + addColumn(i18n("Preview")); + addColumn(i18n("Size")); + addColumn(i18n("This is a column which will contain the amount of HotPixels " + "found in the black frame file", "HP")); + setAllColumnsShowFocus(true); + setResizeMode(TQListView::LastColumn); + setSelectionMode(TQListView::Single); +} + +// -------------------------------------------------------------------------- + +BlackFrameListViewItem::BlackFrameListViewItem(BlackFrameListView* parent, const KURL &url) + : TQObject(parent), TQListViewItem(parent) +{ + m_parent = parent; + m_blackFrameURL = url; + m_parser = new BlackFrameParser(parent); + m_parser->parseBlackFrame(url); + + connect(m_parser, TQ_SIGNAL(parsed(TQValueList<HotPixel>)), + this, TQ_SLOT(slotParsed(TQValueList<HotPixel>))); + + connect(this, TQ_SIGNAL(parsed(TQValueList<HotPixel>, const KURL&)), + parent, TQ_SLOT(slotParsed(TQValueList<HotPixel>, const KURL&))); + + connect(m_parser, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SIGNAL(signalLoadingProgress(float))); + + connect(m_parser, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SIGNAL(signalLoadingComplete())); +} + +void BlackFrameListViewItem::activate() +{ + TQToolTip::add( m_parent, m_blackFrameDesc); + emit parsed(m_hotPixels, m_blackFrameURL); +} + +TQString BlackFrameListViewItem::text(int column)const +{ + switch (column) + { + case 0: + { + // First column includes the pixmap + break; + } + case 1: + { + // The image size. + if (!m_imageSize.isEmpty()) + return (TQString("%1x%2").arg(m_imageSize.width()).arg(m_imageSize.height())); + break; + } + case 2: + { + // The amount of hot pixels found in the black frame. + return (TQString::number(m_hotPixels.count())); + break; + } + } + + return TQString(); +} + +void BlackFrameListViewItem::paintCell(TQPainter* p, const TQColorGroup& cg, int column, int width, int align) +{ + //Let the normal listview item draw it all for now + TQListViewItem::paintCell(p, cg, column, width, align); +} + +void BlackFrameListViewItem::slotParsed(TQValueList<HotPixel> hotPixels) +{ + m_hotPixels = hotPixels; + m_image = m_parser->image(); + m_imageSize = m_image.size(); + m_thumb = thumb(TQSize(THUMB_WIDTH, THUMB_WIDTH/3*2)); + setPixmap(0, m_thumb); + + m_blackFrameDesc = TQString("<p><b>" + m_blackFrameURL.fileName() + "</b>:<p>"); + TQValueList <HotPixel>::Iterator end(m_hotPixels.end()); + for (TQValueList <HotPixel>::Iterator it = m_hotPixels.begin() ; it != end ; ++it) + m_blackFrameDesc.append( TQString("[%1,%2] ").arg((*it).x()).arg((*it).y()) ); + + emit parsed(m_hotPixels, m_blackFrameURL); +} + +TQPixmap BlackFrameListViewItem::thumb(const TQSize& size) +{ + TQPixmap thumb; + + //First scale it down to the size + thumb = m_image.smoothScale(size, TQImage::ScaleMin); + + //And draw the hot pixel positions on the thumb + TQPainter p(&thumb); + + //Take scaling into account + float xRatio, yRatio; + float hpThumbX, hpThumbY; + TQRect hpRect; + + xRatio = (float)size.width()/(float)m_image.width(); + yRatio = (float)size.height()/(float)m_image.height(); + + //Draw hot pixels one by one + TQValueList <HotPixel>::Iterator it; + TQValueList <HotPixel>::Iterator end(m_hotPixels.end()); + for (it=m_hotPixels.begin() ; it!=end ; ++it) + { + hpRect = (*it).rect; + hpThumbX = (hpRect.x()+hpRect.width()/2)*xRatio; + hpThumbY = (hpRect.y()+hpRect.height()/2)*yRatio; + + p.setPen(TQPen(TQt::black)); + p.drawLine((int)hpThumbX, (int)hpThumbY-1, (int)hpThumbX, (int)hpThumbY+1); + p.drawLine((int)hpThumbX-1, (int)hpThumbY, (int)hpThumbX+1, (int)hpThumbY); + p.setPen(TQPen(TQt::white)); + p.drawPoint((int)hpThumbX-1, (int)hpThumbY-1); + p.drawPoint((int)hpThumbX+1, (int)hpThumbY+1); + p.drawPoint((int)hpThumbX-1, (int)hpThumbY+1); + p.drawPoint((int)hpThumbX+1, (int)hpThumbY-1); + } + + return thumb; +} + +int BlackFrameListViewItem::width(const TQFontMetrics& fm,const TQListView* lv,int c)const +{ + if (c==0) return THUMB_WIDTH; + else return TQListViewItem::width(fm,lv,c); +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/blackframelistview.h b/src/imageplugins/hotpixels/blackframelistview.h new file mode 100644 index 00000000..977d226d --- /dev/null +++ b/src/imageplugins/hotpixels/blackframelistview.h @@ -0,0 +1,127 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-05 + * Description : a ListView to display black frames + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef BLACKFRAMELISTVIEW_H +#define BLACKFRAMELISTVIEW_H + +// TQt includes. + +#include <tqimage.h> +#include <tqstring.h> +#include <tqsize.h> +#include <tqpoint.h> +#include <tqvaluelist.h> +#include <tqlistview.h> + +// KDE includes. + +#include <kurl.h> +#include <tdelocale.h> + +// Local includes. + +#include "blackframeparser.h" +#include "hotpixel.h" + +namespace DigikamHotPixelsImagesPlugin +{ + +class BlackFrameListView : public TQListView +{ + TQ_OBJECT + + +public: + + BlackFrameListView(TQWidget* parent=0); + ~BlackFrameListView(){}; + +signals: + + void blackFrameSelected(TQValueList<HotPixel>, const KURL&); + +private slots: + + void slotParsed(TQValueList<HotPixel> hotPixels, const KURL& blackFrameURL) + { + emit blackFrameSelected(hotPixels, blackFrameURL); + }; +}; + +// -------------------------------------------------------------------------- + +class BlackFrameListViewItem : public TQObject, TQListViewItem +{ +TQ_OBJECT + + +public: + + BlackFrameListViewItem(BlackFrameListView* parent, const KURL &url); + ~BlackFrameListViewItem(){}; + + virtual TQString text(int column)const; + virtual void paintCell(TQPainter* p, const TQColorGroup& cg, int column, int width, int align); + virtual int width(const TQFontMetrics& fm, const TQListView* lv, int c)const; + +signals: + + void parsed(TQValueList<HotPixel>, const KURL&); + void signalLoadingProgress(float); + void signalLoadingComplete(); + +protected: + + void activate(); + +private: + + TQPixmap thumb(const TQSize& size); + +private slots: + + void slotParsed(TQValueList<HotPixel>); + +private: + + // Data contained within each listview item + TQImage m_thumb; + TQImage m_image; + + TQSize m_imageSize; + + TQValueList <HotPixel> m_hotPixels; + + TQString m_blackFrameDesc; + + KURL m_blackFrameURL; + + BlackFrameParser *m_parser; + + BlackFrameListView *m_parent; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // BLACKFRAMELISTVIEW_H diff --git a/src/imageplugins/hotpixels/blackframeparser.cpp b/src/imageplugins/hotpixels/blackframeparser.cpp new file mode 100644 index 00000000..7306f4e6 --- /dev/null +++ b/src/imageplugins/hotpixels/blackframeparser.cpp @@ -0,0 +1,211 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : black frames parser + * + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Part of the algorithm for finding the hot pixels was based on + * the code of jpegpixi, which was released under the GPL license, + * and is Copyright (C) 2003, 2004 Martin Dickopp + * + * 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. + * + * ============================================================ */ + +// Denominator for relative quantities. +#define DENOM (DENOM_STQRT * DENOM_STQRT) + +// Square root of denominator for relative quantities. +#define DENOM_STQRT 10000 + +// Convert relative to absolute numbers. Care must be taken not to overflow integers. +#define REL_TO_ABS(n,m) \ + ((((n) / DENOM_STQRT) * (m) + ((n) % DENOM_STQRT) * (m) / DENOM_STQRT) / DENOM_STQRT) + +// TQt includes. + +#include <tqimage.h> +#include <tqstringlist.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <tdeversion.h> +#include <tdeio/netaccess.h> +#include <tdeio/job.h> + +// Local includes. + +#include "blackframeparser.h" +#include "blackframeparser.moc" + +namespace DigikamHotPixelsImagesPlugin +{ + +BlackFrameParser::BlackFrameParser(TQObject *parent) + : TQObject(parent) +{ + m_imageLoaderThread = 0; +} + +BlackFrameParser::~BlackFrameParser() +{ + delete m_imageLoaderThread; +} + +void BlackFrameParser::parseHotPixels(const TQString &file) +{ + parseBlackFrame(KURL(file)); +} + +void BlackFrameParser::parseBlackFrame(const KURL &url) +{ +#if KDE_IS_VERSION(3,2,0) + TDEIO::NetAccess::download(url, m_localFile, kapp->activeWindow()); +#else + TDEIO::NetAccess::download(url, m_localFile); +#endif + + if (!m_imageLoaderThread) + { + m_imageLoaderThread = new LoadSaveThread(); + + connect(m_imageLoaderThread, TQ_SIGNAL(signalLoadingProgress(const LoadingDescription&, float)), + this, TQ_SLOT(slotLoadingProgress(const LoadingDescription&, float))); + + connect(m_imageLoaderThread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription&, const DImg&)), + this, TQ_SLOT(slotLoadImageFromUrlComplete(const LoadingDescription&, const DImg&))); + } + + LoadingDescription desc = LoadingDescription(m_localFile, DRawDecoding()); + m_imageLoaderThread->load(desc); +} + +void BlackFrameParser::slotLoadingProgress(const LoadingDescription&, float v) +{ + emit signalLoadingProgress(v); +} + +void BlackFrameParser::slotLoadImageFromUrlComplete(const LoadingDescription&, const DImg& img) +{ + DImg image(img); + m_Image = image.copyTQImage(); + blackFrameParsing(); + emit signalLoadingComplete(); +} + +void BlackFrameParser::parseBlackFrame(TQImage& img) +{ + m_Image = img; + blackFrameParsing(); +} + +// Parses black frames + +void BlackFrameParser::blackFrameParsing() +{ + // Now find the hot pixels and store them in a list + TQValueList<HotPixel> hpList; + + for (int y=0 ; y < m_Image.height() ; ++y) + { + for (int x=0 ; x < m_Image.width() ; ++x) + { + //Get each point in the image + TQRgb pixrgb = m_Image.pixel(x,y); + TQColor color; color.setRgb(pixrgb); + + // Find maximum component value. + int maxValue; + int threshold = DENOM/10; + const int threshold_value = REL_TO_ABS(threshold, 255); + maxValue = (color.red()>color.blue()) ? color.red() : color.blue(); + if (color.green() > maxValue) maxValue = color.green(); + + // If the component is bigger than the threshold, add the point + if (maxValue > threshold_value) + { + HotPixel point; + point.rect = TQRect (x, y, 1, 1); + //TODO:check this + point.luminosity = ((2 * DENOM) / 255 ) * maxValue / 2; + + hpList.append(point); + } + } + } + + //Now join points together into groups + consolidatePixels (hpList); + + //And notify + emit parsed(hpList); +} + +// Consolidate adjacent points into larger points. + +void BlackFrameParser::consolidatePixels (TQValueList<HotPixel>& list) +{ + if (list.isEmpty()) + return; + + /* Consolidate horizontally. */ + + TQValueList<HotPixel>::iterator it, prevPointIt; + + prevPointIt = list.begin(); + it = list.begin(); + ++it; + + HotPixel tmp; + HotPixel point; + HotPixel point_below; + TQValueList<HotPixel>::iterator end(list.end()); + for (; it != end; ++it ) + { + while (1) + { + point = (*it); + tmp = point; + + TQValueList<HotPixel>::Iterator point_below_it; + point_below_it = list.find (tmp); //find any intersecting hotp below tmp + if (point_below_it != list.end()) + { + point_below =* point_below_it; + validateAndConsolidate (&point, &point_below); + + point.rect.setX(MIN(point.x(), point_below.x())); + point.rect.setWidth(MAX(point.x() + point.width(), + point_below.x() + point_below.width()) - point.x()); + point.rect.setHeight(MAX(point.y() + point.height(), + point_below.y() + point_below.height()) - point.y()); + *it = point; + list.remove (point_below_it); //TODO: Check! this could remove it++? + } + else + break; + } + } +} + +void BlackFrameParser::validateAndConsolidate (HotPixel *a, HotPixel *b) +{ + a->luminosity = MAX (a->luminosity, b->luminosity); +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/blackframeparser.h b/src/imageplugins/hotpixels/blackframeparser.h new file mode 100644 index 00000000..f13ebdc4 --- /dev/null +++ b/src/imageplugins/hotpixels/blackframeparser.h @@ -0,0 +1,102 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : black frames parser + * + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Part of the algorithm for finding the hot pixels was based on + * the code of jpegpixi, which was released under the GPL license, + * and is Copyright (C) 2003, 2004 Martin Dickopp + * + * 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. + * + * ============================================================ */ + +#ifndef BLACKFRAMEPARSER_H +#define BLACKFRAMEPARSER_H + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +// TQt includes. + +#include <tqimage.h> +#include <tqobject.h> +#include <tqvaluelist.h> +#include <tqstring.h> +#include <tqrect.h> + +// KDE includes. + +#include <kurl.h> + +// Local includes. + +#include "dimg.h" +#include "loadsavethread.h" +#include "hotpixel.h" + +using namespace Digikam; + +namespace DigikamHotPixelsImagesPlugin +{ + +class BlackFrameParser: public TQObject +{ + TQ_OBJECT + + +public: + + BlackFrameParser(TQObject *parent); + ~BlackFrameParser(); + + void parseHotPixels(const TQString &file); + void parseBlackFrame(const KURL &url); + void parseBlackFrame(TQImage& img); + TQImage image(){return m_Image;} + +signals: + + void parsed(TQValueList<HotPixel>); + void signalLoadingProgress(float); + void signalLoadingComplete(); + +private slots: + + void slotLoadingProgress(const LoadingDescription&, float); + void slotLoadImageFromUrlComplete(const LoadingDescription&, const DImg&); + +private: + + void blackFrameParsing(); + void consolidatePixels(TQValueList<HotPixel>& list); + void validateAndConsolidate(HotPixel *a, HotPixel *b); + +private: + + TQString m_OutputString; + TQString m_localFile; + + TQImage m_Image; + + LoadSaveThread *m_imageLoaderThread; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // BLACKFRAMEPARSER_H diff --git a/src/imageplugins/hotpixels/digikamimageplugin_hotpixels.desktop b/src/imageplugins/hotpixels/digikamimageplugin_hotpixels.desktop new file mode 100644 index 00000000..5b12fe2c --- /dev/null +++ b/src/imageplugins/hotpixels/digikamimageplugin_hotpixels.desktop @@ -0,0 +1,50 @@ +[Desktop Entry] +Name=ImagePlugin_HotPixels +Name[bg]=Приставка за снимки - Горещи пиксели +Name[el]=ΠρόσθετοΕικόνας_ΈντοναΕικονοστοιχεία +Name[fi]=KuumatPikselit +Name[hr]=Vrući pikseli +Name[it]=PluginImmagini_PixelBruciati +Name[ms]=ImagePlugin_PikselPanas +Name[nl]=Afbeeldingsplugin_HotPixels +Name[sr]=Врући пиксели +Name[sr@Latn]=Vrući pikseli +Name[sv]=Insticksprogram för heta bildpunkter +Name[tr]=ResimEklentisi_Çekirdek +Name[xx]=xxImagePlugin_HotPixelsxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Hot pixel correction plugin for digiKam +Comment[ca]=Connector per al digiKam de correcció de píxels cremats +Comment[da]=Hot pixel rettelsesplugin for Digikam +Comment[de]=digiKam-Modul zur Korrektur von heißen (defekten) Pixeln +Comment[el]=Πρόσθετο διόρθωσης έντονων εικονοστοιχείων για το digiKam +Comment[es]=Plugin para digiKampara corregir los píxeles quemados de la imagen +Comment[et]=DigiKami kuumade pikslite korrigeerimise plugin +Comment[fa]=وصلۀ اصلاح تصویردانۀ Hot برای digiKam +Comment[fi]=Digitaalisen rakeisuushäiriön korjaus +Comment[gl]=Un plugin de digiKam para corrixir os pixels queimados da imaxe +Comment[hr]=digiKam dodatak za ispravljanje vrućih piksela +Comment[is]=Íforrit fyrir digiKam sem fjarlægir skemmda díla (hot pixels) +Comment[it]=Plugin di correzione dei pixel bruciati per digiKam +Comment[ja]=digiKam ホットピクセル除去プラグイン +Comment[ms]=Plugin pembetulan piksel panas untuk digiKam +Comment[nds]=digiKam-Moduul för't Richten vun hitte Pixels +Comment[nl]=Digikam-plugin voor het corrigeren van de hotpixels +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਹਾਟ ਪਿਕਸਲ ਸੋਧ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka do programu digiKam usuwająca "gorące piksele" +Comment[pt]=Um 'plugin' do digiKam para corrigir os pixels queimados da imagem +Comment[pt_BR]=Plugin de Correção de hot pixel para o digiKam +Comment[ru]=Модуль коррекции ярких пикселей для digiKam +Comment[sk]=digiKam plugin pre korekciu vypálených pixelov +Comment[sr]=digiKam-ов прикључак исправку врућих пиксела +Comment[sr@Latn]=digiKam-ov priključak ispravku vrućih piksela +Comment[sv]=Digikam insticksprogram för korrigering av heta bildpunkter +Comment[tr]=digiKam için beyaz dengesini düzeltme eklentisi +Comment[uk]=Втулок виправлення гарячих пікселів для Digikam +Comment[vi]=Phần bổ sung sửa điểm ảnh nóng cho digiKam +Comment[xx]=xxHot pixel correction plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_hotpixels +author=Unai Garro, ugarro at sourceforge dot net diff --git a/src/imageplugins/hotpixels/digikamimageplugin_hotpixels_ui.rc b/src/imageplugins/hotpixels/digikamimageplugin_hotpixels_ui.rc new file mode 100644 index 00000000..b80d7f5a --- /dev/null +++ b/src/imageplugins/hotpixels/digikamimageplugin_hotpixels_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="4" name="digikamimageplugin_hotpixels" > + + <MenuBar> + + <Menu name="Enhance" ><text>Enh&ance</text> + <Action name="imageplugin_hotpixels" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_hotpixels" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/hotpixels/hotpixel.h b/src/imageplugins/hotpixels/hotpixel.h new file mode 100644 index 00000000..bceb539f --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixel.h @@ -0,0 +1,74 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : Threaded image filter to fix hot pixels + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef HOTPIXEL_H +#define HOTPIXEL_H + +// TQt includes. + +#include <tqrect.h> + +namespace DigikamHotPixelsImagesPlugin +{ + +class HotPixel +{ + +public: + + TQRect rect; + int luminosity; + int y() const {return rect.y(); }; + int x() const {return rect.x(); }; + int width()const {return rect.width(); }; + int height()const {return rect.height();}; + + bool operator==(const HotPixel p) const + { + //we can say they're same hotpixel spot if they + //touch(next to) each other horizontally or vertically, not diagonal corners + //return (rect.intersects(p.rect)); + return (rect != p.rect) && (x() + width() >= p.x() && x() <= p.x() + p.width() + && y() + height() >= p.y() && y() <= p.y() + p.height()) + && !diagonal(rect, p.rect); + } + +private: + + bool diagonal(TQRect r1,TQRect r2) const + { + //locate next-to positions + + bool top = r1.y() + height()-1 == r2.y()-1; //r1 is on the top of r2 + bool left = r1.x() + width()-1 == r2.x()-1; //r1 is on the left of r2 + bool right = r1.x() == r2.x() + r2.width(); + bool bottom = r1.y() == r2.y() + r2.height(); + + return ((top && left) || (top && right) || (bottom && left) || (bottom && right)); + } +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // HOTPIXEL_H diff --git a/src/imageplugins/hotpixels/hotpixelfixer.cpp b/src/imageplugins/hotpixels/hotpixelfixer.cpp new file mode 100644 index 00000000..d29b8525 --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixelfixer.cpp @@ -0,0 +1,302 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : Threaded image filter to fix hot pixels + * + * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +// C++ includes. + +#include <cmath> +#include <cstdlib> + +// TQt includes. + +#include <tqcolor.h> +#include <tqregexp.h> +#include <tqstringlist.h> + +// Local includes. + +#include "dimg.h" +#include "ddebug.h" +#include "hotpixelfixer.h" + +#ifdef HAVE_FLOAT_H +#if HAVE_FLOAT_H +# include <float.h> +#endif +#endif + +#ifndef DBL_MIN +# define DBL_MIN 1e-37 +#endif +#ifndef DBL_MAX +# define DBL_MAX 1e37 +#endif + +namespace DigikamHotPixelsImagesPlugin +{ + +HotPixelFixer::HotPixelFixer(Digikam::DImg *orgImage, TQObject *parent, const TQValueList<HotPixel>& hpList, + int interpolationMethod) + : Digikam::DImgThreadedFilter(orgImage, parent, "HotPixels") +{ + m_hpList = hpList; + m_interpolationMethod = interpolationMethod; + mWeightList.clear(); + + initFilter(); +} + +HotPixelFixer::~HotPixelFixer() +{ +} + +void HotPixelFixer::filterImage(void) +{ + TQValueList <HotPixel>::ConstIterator it; + TQValueList <HotPixel>::ConstIterator end(m_hpList.end()); + for (it = m_hpList.begin() ; it != end ; ++it) + { + HotPixel hp = *it; + interpolate(m_orgImage, hp, m_interpolationMethod); + } + + m_destImage = m_orgImage; +} + +// Interpolates a pixel block +void HotPixelFixer::interpolate (Digikam::DImg &img, HotPixel &hp, int method) +{ + const int xPos = hp.x(); + const int yPos = hp.y(); + bool sixtBits = img.sixteenBit(); + + // Interpolate pixel. + switch (method) + { + case AVERAGE_INTERPOLATION: + { + // We implement the bidimendional one first. + // TODO: implement the rest of directions (V & H) here + + //case twodim: + // { + int sum_weight = 0; + double vr=0.0,vg=0.0,vb=0.0; + int x, y; + Digikam::DColor col; + + for (x = xPos; x < xPos+hp.width(); ++x) + { + if (validPoint(img,TQPoint(x,yPos-1))) + { + col=img.getPixelColor(x,yPos-1); + vr += col.red(); + vg += col.green(); + vb += col.blue(); + ++sum_weight; + } + if (validPoint(img,TQPoint(x,yPos+hp.height()))) + { + col=img.getPixelColor(x,yPos+hp.height()); + vr += col.red(); + vg += col.green(); + vb += col.blue(); + ++sum_weight; + } + } + + for (y = yPos; y < hp.height(); ++y) + { + if (validPoint(img,TQPoint(xPos-1,y))) + { + col=img.getPixelColor(xPos,y); + vr += col.red(); + vg += col.green(); + vb += col.blue(); + ++sum_weight; + } + if (validPoint(img,TQPoint(xPos+hp.width(),y))) + { + col=img.getPixelColor(xPos+hp.width(),y); + vr += col.red(); + vg += col.green(); + vb += col.blue(); + ++sum_weight; + } + } + + if (sum_weight > 0) + { + vr /= (double)sum_weight; + vg /= (double)sum_weight; + vb /= (double)sum_weight; + + + for (x = 0; x < hp.width(); ++x) + for (y = 0; y < hp.height(); ++y) + if (validPoint(img,TQPoint(xPos+x,yPos+y))) + { + int alpha=sixtBits ? 65535 : 255; + int ir=(int )round(vr),ig=(int) round(vg),ib=(int) round(vb); + img.setPixelColor(xPos+x,yPos+y,Digikam::DColor(ir,ig,ib,alpha,sixtBits)); + } + } + break; + } //Case average + + case LINEAR_INTERPOLATION: + //(Bi)linear interpolation. + weightPixels (img,hp,LINEAR_INTERPOLATION,TWODIM_DIRECTION,sixtBits ? 65535: 255); + break; + + case QUADRATIC_INTERPOLATION: + // (Bi)quadratic interpolation. + weightPixels (img,hp,QUADRATIC_INTERPOLATION,TWODIM_DIRECTION,sixtBits ? 65535 : 255); + break; + + case CUBIC_INTERPOLATION: + // (Bi)cubic interpolation. + weightPixels (img,hp,CUBIC_INTERPOLATION,TWODIM_DIRECTION,sixtBits ? 65535 : 255); + break; + } //switch +} + +void HotPixelFixer::weightPixels (Digikam::DImg &img, HotPixel &px, int method, Direction dir,int maxComponent) +{ + //TODO: implement direction here too + + for (int iComp = 0; iComp < 3; ++iComp) + { + // Obtain weight data block. + + Weights w; + int polynomeOrder=-1; + + switch (method) + { + case AVERAGE_INTERPOLATION: // Gilles: to prevent warnings from compiler. + break; + case LINEAR_INTERPOLATION: + polynomeOrder=1; + break; + case QUADRATIC_INTERPOLATION: + polynomeOrder=2; + break; + case CUBIC_INTERPOLATION: + polynomeOrder=3; + break; + } + if (polynomeOrder<0) return; + + // In the one-dimensional case, the width must be 1, + // and the size must be stored in height + + w.setWidth(dir == TWODIM_DIRECTION ? px.width() : 1); + w.setHeight(dir == HORIZONTAL_DIRECTION ? px.width() : px.height()); + w.setPolynomeOrder(polynomeOrder); + w.setTwoDim(dir == TWODIM_DIRECTION); + + //TODO: check this, it must not recalculate existing calculated weights + //for now I don't think it is finding the duplicates fine, so it uses + //the previous one always... + + //if (mWeightList.find(w)==mWeightList.end()) + //{ + w.calculateWeights(); + + // mWeightList.append(w); + + //} + + // Calculate weighted pixel sum. + for (int y = 0; y<px.height(); ++y) + { + for (int x = 0; x < px.width(); ++x) + { + if (validPoint (img,TQPoint(px.x()+x,px.y()+y))) + { + double sum_weight = 0.0, v = 0.0; + size_t i; + + for (i = 0; i < w.positions().count(); ++i) + { + // In the one-dimensional case, only the y coordinate is used. + const int xx = px.x()+(dir == VERTICAL_DIRECTION ? x : + dir== HORIZONTAL_DIRECTION ? w.positions()[i].y() : w.positions()[i].x()); + const int yy = px.y()+(dir == HORIZONTAL_DIRECTION ? y : + w.positions()[i].y()); + + if (validPoint (img,TQPoint(xx, yy))) + { + //TODO: check this. I think it is broken + double weight; + if (dir==VERTICAL_DIRECTION) + { + weight = w[i][y][0]; + } + else if (dir==HORIZONTAL_DIRECTION) + { + weight=w[i][0][x]; + } + else + { + weight=w[i][y][x]; + } + + if (iComp==0) v += weight * img.getPixelColor(xx, yy).red(); + else if (iComp==1) v += weight * img.getPixelColor(xx, yy).green(); + else v += weight * img.getPixelColor(xx, yy).blue(); + + sum_weight += weight; + } + } + + Digikam::DColor color=img.getPixelColor(px.x()+x,px.y()+y); + int component; + if (fabs (v) <= DBL_MIN) + component=0; + else if (sum_weight >= DBL_MIN) + { + component=(int) (v/sum_weight); + //Clamp value + if (component<0) component=0; + if (component>maxComponent) component=maxComponent; + } + else if (v >= 0.0) + component=maxComponent; + else + component=0; + + if (iComp==0) color.setRed(component); + else if (iComp==1) color.setGreen(component); + else color.setBlue(component); + + + img.setPixelColor(px.x()+x,px.y()+y,color); + } + } + } + } +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/hotpixelfixer.h b/src/imageplugins/hotpixels/hotpixelfixer.h new file mode 100644 index 00000000..2bf8131c --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixelfixer.h @@ -0,0 +1,98 @@ +/* ============================================================ + * Authors: Unai Garro <ugarro at users dot sourceforge dot net> + * Gilles Caulier <caulier dot gilles at free dot fr> + * Date : 2005-03-27 + * Description : Threaded image filter to fix hot pixels + * + * Copyright 2005-2007 by Unai Garro and Gilles Caulier + * + * The algorithm for fixing the hot pixels was based on + * the code of jpegpixi, which was released under the GPL license, + * and is Copyright (C) 2003, 2004 Martin Dickopp + * + * 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. + * + * ============================================================*/ + +#ifndef HOTPIXELFIXER_H +#define HOTPIXELFIXER_H + +// TQt includes. + +#include <tqimage.h> +#include <tqobject.h> +#include <tqvaluelist.h> +#include <tqrect.h> +#include <tqstring.h> + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +// Local includes. + +#include "hotpixel.h" +#include "weights.h" + +namespace DigikamHotPixelsImagesPlugin +{ + +class HotPixelFixer : public Digikam::DImgThreadedFilter +{ + +public: + + enum InterpolationMethod + { + AVERAGE_INTERPOLATION = 0, + LINEAR_INTERPOLATION = 1, + QUADRATIC_INTERPOLATION = 2, + CUBIC_INTERPOLATION = 3 + }; + + enum Direction + { + TWODIM_DIRECTION = 0, + VERTICAL_DIRECTION = 1, + HORIZONTAL_DIRECTION = 2 + }; + +public: + + HotPixelFixer(Digikam::DImg *orgImage, TQObject *parent, + const TQValueList<HotPixel>& hpList, int interpolationMethod); + ~HotPixelFixer(); + +private: + + virtual void filterImage(void); + + void interpolate (Digikam::DImg &img,HotPixel &hp, int method); + void weightPixels (Digikam::DImg &img, HotPixel &px, int method, Direction dir, int maxComponent); + + inline bool validPoint(Digikam::DImg &img, TQPoint p) + { + return (p.x()>=0 && p.y()>=0 && p.x()<(long) img.width() && p.y()<(long) img.height()); + }; + + TQValueList <Weights> mWeightList; + +private: + + int m_interpolationMethod; + + TQValueList<HotPixel> m_hpList; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // HOTPIXELFIXER_H diff --git a/src/imageplugins/hotpixels/hotpixelstool.cpp b/src/imageplugins/hotpixels/hotpixelstool.cpp new file mode 100644 index 00000000..fbcc6c9f --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixelstool.cpp @@ -0,0 +1,276 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcombobox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> +#include <tqpushbutton.h> +#include <tqpointarray.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeconfig.h> +#include <kimageio.h> +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdefiledialog.h> +#include <kprogress.h> +#include <kiconloader.h> +#include <kpushbutton.h> + +// LibKDcraw includes. + +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortooliface.h" +#include "editortoolsettings.h" +#include "imagedialog.h" +#include "blackframelistview.h" +#include "hotpixelstool.h" +#include "hotpixelstool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamHotPixelsImagesPlugin +{ + +HotPixelsTool::HotPixelsTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("hotpixels"); + setToolName(i18n("Hot Pixels")); + setToolIcon(SmallIcon("hotpixels")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Ok| + EditorToolSettings::Try| + EditorToolSettings::Cancel, + EditorToolSettings::PanIcon); + + TQGridLayout* grid = new TQGridLayout(m_gboxSettings->plainPage(), 3, 2); + + TQLabel *filterMethodLabel = new TQLabel(i18n("Filter:"), m_gboxSettings->plainPage()); + m_filterMethodCombo = new RComboBox(m_gboxSettings->plainPage()); + m_filterMethodCombo->insertItem(i18n("Average")); + m_filterMethodCombo->insertItem(i18n("Linear")); + m_filterMethodCombo->insertItem(i18n("Quadratic")); + m_filterMethodCombo->insertItem(i18n("Cubic")); + m_filterMethodCombo->setDefaultItem(HotPixelFixer::QUADRATIC_INTERPOLATION); + + m_blackFrameButton = new TQPushButton(i18n("Black Frame..."), m_gboxSettings->plainPage()); + TQWhatsThis::add(m_blackFrameButton, i18n("<p>Use this button to " + "add a new black frame file which will be used by the hot pixels removal filter.")); + + m_blackFrameListView = new BlackFrameListView(m_gboxSettings->plainPage()); + + grid->addMultiCellWidget(filterMethodLabel, 0, 0, 0, 0); + grid->addMultiCellWidget(m_filterMethodCombo, 0, 0, 1, 1); + grid->addMultiCellWidget(m_blackFrameButton, 0, 0, 2, 2); + grid->addMultiCellWidget(m_blackFrameListView, 1, 2, 0, 2); + grid->setRowStretch(3, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "hotpixels Tool", m_gboxSettings->panIconView(), + 0, ImagePanelWidget::SeparateViewDuplicate); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect(m_filterMethodCombo, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_blackFrameButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotAddBlackFrame())); + + connect(m_blackFrameListView, TQ_SIGNAL(blackFrameSelected(TQValueList<HotPixel>, const KURL&)), + this, TQ_SLOT(slotBlackFrame(TQValueList<HotPixel>, const KURL&))); +} + +HotPixelsTool::~HotPixelsTool() +{ +} + +void HotPixelsTool::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("hotpixels Tool"); + m_blackFrameURL = KURL(config->readEntry("Last Black Frame File", TQString())); + m_filterMethodCombo->setCurrentItem(config->readNumEntry("Filter Method", + m_filterMethodCombo->defaultItem())); + + if (m_blackFrameURL.isValid()) + { + EditorToolIface::editorToolIface()->setToolStartProgress(i18n("Loading: ")); + BlackFrameListViewItem *item = new BlackFrameListViewItem(m_blackFrameListView, m_blackFrameURL); + + connect(item, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SLOT(slotLoadingProgress(float))); + + connect(item, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SLOT(slotLoadingComplete())); + } +} + +void HotPixelsTool::slotLoadingProgress(float v) +{ + EditorToolIface::editorToolIface()->setToolProgress((int)(v*100)); +} + +void HotPixelsTool::slotLoadingComplete() +{ + EditorToolIface::editorToolIface()->setToolStopProgress(); +} + +void HotPixelsTool::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("hotpixels Tool"); + config->writeEntry("Last Black Frame File", m_blackFrameURL.url()); + config->writeEntry("Filter Method", m_filterMethodCombo->currentItem()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void HotPixelsTool::slotResetSettings() +{ + m_filterMethodCombo->blockSignals(true); + m_filterMethodCombo->slotReset(); + m_filterMethodCombo->blockSignals(false); +} + +void HotPixelsTool::slotAddBlackFrame() +{ + KURL url = ImageDialog::getImageURL(kapp->activeWindow(), m_blackFrameURL, i18n("Select Black Frame Image")); + + if (!url.isEmpty()) + { + // Load the selected file and insert into the list. + + m_blackFrameURL = url; + m_blackFrameListView->clear(); + BlackFrameListViewItem *item = new BlackFrameListViewItem(m_blackFrameListView, m_blackFrameURL); + + connect(item, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SLOT(slotLoadingProgress(float))); + + connect(item, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SLOT(slotLoadingComplete())); + } +} + +void HotPixelsTool::renderingFinished() +{ + m_filterMethodCombo->setEnabled(true); + m_blackFrameListView->setEnabled(true); +} + +void HotPixelsTool::prepareEffect() +{ + m_filterMethodCombo->setEnabled(false); + m_blackFrameListView->setEnabled(false); + + DImg image = m_previewWidget->getOriginalRegionImage(); + int interpolationMethod = m_filterMethodCombo->currentItem(); + + TQValueList<HotPixel> hotPixelsRegion; + TQRect area = m_previewWidget->getOriginalImageRegionToRender(); + TQValueList<HotPixel>::Iterator end(m_hotPixelsList.end()); + + for (TQValueList<HotPixel>::Iterator it = m_hotPixelsList.begin() ; it != end ; ++it ) + { + HotPixel hp = (*it); + + if ( area.contains( hp.rect ) ) + { + hp.rect.moveTopLeft(TQPoint( hp.rect.x()-area.x(), hp.rect.y()-area.y() )); + hotPixelsRegion.append(hp); + } + } + + setFilter(dynamic_cast<DImgThreadedFilter*>(new HotPixelFixer(&image, this, hotPixelsRegion, interpolationMethod))); +} + +void HotPixelsTool::prepareFinal() +{ + m_filterMethodCombo->setEnabled(false); + m_blackFrameListView->setEnabled(false); + + int interpolationMethod = m_filterMethodCombo->currentItem(); + + ImageIface iface(0, 0); + setFilter(dynamic_cast<DImgThreadedFilter*>(new HotPixelFixer(iface.getOriginalImg(), this,m_hotPixelsList,interpolationMethod))); +} + +void HotPixelsTool::putPreviewData() +{ + m_previewWidget->setPreviewImage(filter()->getTargetImage()); +} + +void HotPixelsTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Hot Pixels Correction"), filter()->getTargetImage().bits()); +} + +void HotPixelsTool::slotBlackFrame(TQValueList<HotPixel> hpList, const KURL& blackFrameURL) +{ + m_blackFrameURL = blackFrameURL; + m_hotPixelsList = hpList; + + TQPointArray pointList(m_hotPixelsList.size()); + TQValueList <HotPixel>::Iterator it; + int i = 0; + TQValueList <HotPixel>::Iterator end(m_hotPixelsList.end()); + + for (it = m_hotPixelsList.begin() ; it != end ; ++it, i++) + pointList.setPoint(i, (*it).rect.center()); + + m_previewWidget->setPanIconHighLightPoints(pointList); + + slotEffect(); +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/hotpixelstool.h b/src/imageplugins/hotpixels/hotpixelstool.h new file mode 100644 index 00000000..727c6387 --- /dev/null +++ b/src/imageplugins/hotpixels/hotpixelstool.h @@ -0,0 +1,113 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_HOTPIXELS_H +#define IMAGEEFFECT_HOTPIXELS_H + +#define MAX_PIXEL_DEPTH 4 + +// TQt includes. + +#include <tqvaluelist.h> + +// KDE includes. + +#include <kurl.h> + +// Digikam includes. + +#include "editortool.h" + +// Local includes. + +#include "hotpixelfixer.h" + +class TQPushButton; + +namespace KDcrawIface +{ +class RComboBox; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamHotPixelsImagesPlugin +{ + +class BlackFrameListView; + +class HotPixelsTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + HotPixelsTool(TQObject *parent); + ~HotPixelsTool(); + +private slots: + + void slotBlackFrame(TQValueList<HotPixel> hpList, const KURL& blackFrameURL); + void slotResetSettings(); + void slotAddBlackFrame(); + void slotLoadingProgress(float); + void slotLoadingComplete(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQPushButton *m_blackFrameButton; + + TQValueList<HotPixel> m_hotPixelsList; + + KURL m_blackFrameURL; + + BlackFrameListView *m_blackFrameListView; + + KDcrawIface::RComboBox *m_filterMethodCombo; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif /* IMAGEEFFECT_HOTPIXELS_H */ diff --git a/src/imageplugins/hotpixels/imageeffect_hotpixels.cpp b/src/imageplugins/hotpixels/imageeffect_hotpixels.cpp new file mode 100644 index 00000000..67e9a1b2 --- /dev/null +++ b/src/imageplugins/hotpixels/imageeffect_hotpixels.cpp @@ -0,0 +1,279 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcombobox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqwhatsthis.h> +#include <tqpushbutton.h> +#include <tqpointarray.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdeconfig.h> +#include <kimageio.h> +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdefiledialog.h> +#include <kprogress.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "imagedialog.h" +#include "blackframelistview.h" +#include "imageeffect_hotpixels.h" +#include "imageeffect_hotpixels.moc" + +namespace DigikamHotPixelsImagesPlugin +{ + +ImageEffect_HotPixels::ImageEffect_HotPixels(TQWidget* parent) + : CtrlPanelDlg(parent, i18n("Hot Pixels Correction"), + "hotpixels", false, false, false, + Digikam::ImagePannelWidget::SeparateViewDuplicate) +{ + // No need Abort button action. + showButton(User1, false); + + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Hot Pixels Correction"), + digikam_version, + I18N_NOOP("A digiKam image plugin for fixing dots produced by " + "hot/stuck/dead pixels from a CCD."), + TDEAboutData::License_GPL, + "(c) 2005-2006, Unai Garro\n(c) 2005-2008, Gilles Caulier", + 0, + "http://www.digikam.org"); + + about->addAuthor("Unai Garro", I18N_NOOP("Author and maintainer"), + "ugarro at sourceforge dot net"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Developer"), + "caulier dot gilles at gmail dot com"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout(gboxSettings, 3, 2, 0, spacingHint()); + + TQLabel *filterMethodLabel = new TQLabel(i18n("Filter:"), gboxSettings); + m_filterMethodCombo = new TQComboBox(gboxSettings); + m_filterMethodCombo->insertItem(i18n("Average")); + m_filterMethodCombo->insertItem(i18n("Linear")); + m_filterMethodCombo->insertItem(i18n("Quadratic")); + m_filterMethodCombo->insertItem(i18n("Cubic")); + + m_blackFrameButton = new TQPushButton(i18n("Black Frame..."), gboxSettings); + setButtonWhatsThis( Apply, i18n("<p>Use this button to add a new black frame file which will " + "be used by the hot pixels removal filter.") ); + + m_blackFrameListView = new BlackFrameListView(gboxSettings); + m_progressBar = new KProgress(100, gboxSettings); + m_progressBar->setValue(0); + m_progressBar->hide(); + + gridSettings->addMultiCellWidget(filterMethodLabel, 0, 0, 0, 0); + gridSettings->addMultiCellWidget(m_filterMethodCombo, 0, 0, 1, 1); + gridSettings->addMultiCellWidget(m_blackFrameButton, 0, 0, 2, 2); + gridSettings->addMultiCellWidget(m_blackFrameListView, 1, 2, 0, 2); + gridSettings->addMultiCellWidget(m_progressBar, 3, 3, 0, 2); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_filterMethodCombo, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffect())); + + connect(m_blackFrameButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotAddBlackFrame())); + + connect(m_blackFrameListView, TQ_SIGNAL(blackFrameSelected(TQValueList<HotPixel>, const KURL&)), + this, TQ_SLOT(slotBlackFrame(TQValueList<HotPixel>, const KURL&))); +} + +ImageEffect_HotPixels::~ImageEffect_HotPixels() +{ +} + +void ImageEffect_HotPixels::readUserSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("hotpixels Tool Dialog"); + m_blackFrameURL = KURL(config->readEntry("Last Black Frame File", TQString())); + m_filterMethodCombo->setCurrentItem(config->readNumEntry("Filter Method", + HotPixelFixer::QUADRATIC_INTERPOLATION)); + + if (m_blackFrameURL.isValid()) + { + BlackFrameListViewItem *item = new BlackFrameListViewItem(m_blackFrameListView, m_blackFrameURL); + + connect(item, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SLOT(slotLoadingProgress(float))); + + connect(item, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SLOT(slotLoadingComplete())); + } +} + +void ImageEffect_HotPixels::writeUserSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup("hotpixels Tool Dialog"); + config->writeEntry("Last Black Frame File", m_blackFrameURL.url()); + config->writeEntry("Filter Method", m_filterMethodCombo->currentItem()); + config->sync(); +} + +void ImageEffect_HotPixels::resetValues() +{ + m_filterMethodCombo->blockSignals(true); + m_filterMethodCombo->setCurrentItem(HotPixelFixer::QUADRATIC_INTERPOLATION); + m_filterMethodCombo->blockSignals(false); +} + +void ImageEffect_HotPixels::slotAddBlackFrame() +{ + KURL url = Digikam::ImageDialog::getImageURL(this, m_blackFrameURL, + i18n("Select Black Frame Image")); + + if (!url.isEmpty()) + { + // Load the selected file and insert into the list. + + m_blackFrameURL = url; + m_blackFrameListView->clear(); + BlackFrameListViewItem *item = new BlackFrameListViewItem(m_blackFrameListView, m_blackFrameURL); + + connect(item, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SLOT(slotLoadingProgress(float))); + + connect(item, TQ_SIGNAL(signalLoadingComplete()), + this, TQ_SLOT(slotLoadingComplete())); + } +} + +void ImageEffect_HotPixels::slotLoadingProgress(float v) +{ + m_progressBar->show(); + m_progressBar->setValue((int)(v*100)); +} + +void ImageEffect_HotPixels::slotLoadingComplete() +{ + m_progressBar->hide(); +} + +void ImageEffect_HotPixels::renderingFinished() +{ + m_filterMethodCombo->setEnabled(true); + m_blackFrameListView->setEnabled(true); + enableButton(Apply, true); +} + +void ImageEffect_HotPixels::prepareEffect() +{ + m_filterMethodCombo->setEnabled(false); + m_blackFrameListView->setEnabled(false); + enableButton(Apply, false); + + Digikam::DImg image = m_imagePreviewWidget->getOriginalRegionImage(); + int interpolationMethod = m_filterMethodCombo->currentItem(); + + TQValueList<HotPixel> hotPixelsRegion; + TQRect area = m_imagePreviewWidget->getOriginalImageRegionToRender(); + TQValueList<HotPixel>::Iterator end(m_hotPixelsList.end()); + + for (TQValueList<HotPixel>::Iterator it = m_hotPixelsList.begin() ; it != end ; ++it ) + { + HotPixel hp = (*it); + + if ( area.contains( hp.rect ) ) + { + hp.rect.moveTopLeft(TQPoint( hp.rect.x()-area.x(), hp.rect.y()-area.y() )); + hotPixelsRegion.append(hp); + } + } + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new HotPixelFixer(&image, this, hotPixelsRegion, interpolationMethod)); +} + +void ImageEffect_HotPixels::prepareFinal() +{ + m_filterMethodCombo->setEnabled(false); + m_blackFrameListView->setEnabled(false); + enableButton(Apply, false); + + int interpolationMethod = m_filterMethodCombo->currentItem(); + + Digikam::ImageIface iface(0, 0); + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>( + new HotPixelFixer(iface.getOriginalImg(), this,m_hotPixelsList,interpolationMethod)); +} + +void ImageEffect_HotPixels::putPreviewData() +{ + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); +} + +void ImageEffect_HotPixels::putFinalData() +{ + Digikam::ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Hot Pixels Correction"), m_threadedFilter->getTargetImage().bits()); +} + +void ImageEffect_HotPixels::slotBlackFrame(TQValueList<HotPixel> hpList, const KURL& blackFrameURL) +{ + m_blackFrameURL = blackFrameURL; + m_hotPixelsList = hpList; + + TQPointArray pointList(m_hotPixelsList.size()); + TQValueList <HotPixel>::Iterator it; + int i = 0; + TQValueList <HotPixel>::Iterator end(m_hotPixelsList.end()); + + for (it = m_hotPixelsList.begin() ; it != end ; ++it, i++) + pointList.setPoint(i, (*it).rect.center()); + + m_imagePreviewWidget->setPanIconHighLightPoints(pointList); + + slotEffect(); +} + +} // NameSpace DigikamHotPixelsImagesPlugin diff --git a/src/imageplugins/hotpixels/imageeffect_hotpixels.h b/src/imageplugins/hotpixels/imageeffect_hotpixels.h new file mode 100644 index 00000000..4a8b0868 --- /dev/null +++ b/src/imageplugins/hotpixels/imageeffect_hotpixels.h @@ -0,0 +1,104 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_HOTPIXELS_H +#define IMAGEEFFECT_HOTPIXELS_H + +#define MAX_PIXEL_DEPTH 4 + +// TQt includes. + +#include <tqvaluelist.h> + +// KDE includes. + +#include <kurl.h> + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +// Local includes. + +#include "hotpixelfixer.h" + +class TQComboBox; +class TQPushButton; + +class KProgress; + +namespace DigikamHotPixelsImagesPlugin +{ + +class BlackFrameListView; + +class ImageEffect_HotPixels : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_HotPixels(TQWidget *parent); + ~ImageEffect_HotPixels(); + +private slots: + + void slotLoadingProgress(float v); + void slotLoadingComplete(); + + void slotBlackFrame(TQValueList<HotPixel> hpList, const KURL& blackFrameURL); + void slotAddBlackFrame(); + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQComboBox *m_filterMethodCombo; + + TQPushButton *m_blackFrameButton; + + TQValueList<HotPixel> m_hotPixelsList; + + KURL m_blackFrameURL; + + KProgress *m_progressBar; + + BlackFrameListView *m_blackFrameListView; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif /* IMAGEEFFECT_HOTPIXELS_H */ diff --git a/src/imageplugins/hotpixels/imageplugin_hotpixels.cpp b/src/imageplugins/hotpixels/imageplugin_hotpixels.cpp new file mode 100644 index 00000000..864b59dc --- /dev/null +++ b/src/imageplugins/hotpixels/imageplugin_hotpixels.cpp @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "hotpixelstool.h" +#include "imageplugin_hotpixels.h" +#include "imageplugin_hotpixels.moc" + +using namespace DigikamHotPixelsImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_hotpixels, + KGenericFactory<ImagePlugin_HotPixels>("digikamimageplugin_hotpixels")); + +ImagePlugin_HotPixels::ImagePlugin_HotPixels(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_HotPixels") +{ + m_hotpixelsAction = new TDEAction(i18n("Hot Pixels..."), "hotpixels", 0, + this, TQ_SLOT(slotHotPixels()), + actionCollection(), "imageplugin_hotpixels"); + + setXMLFile("digikamimageplugin_hotpixels_ui.rc"); + + DDebug() << "ImagePlugin_HotPixels plugin loaded" << endl; +} + +ImagePlugin_HotPixels::~ImagePlugin_HotPixels() +{ +} + +void ImagePlugin_HotPixels::setEnabledActions(bool enable) +{ + m_hotpixelsAction->setEnabled(enable); +} + +void ImagePlugin_HotPixels::slotHotPixels() +{ + HotPixelsTool *tool = new HotPixelsTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/hotpixels/imageplugin_hotpixels.h b/src/imageplugins/hotpixels/imageplugin_hotpixels.h new file mode 100644 index 00000000..c639b830 --- /dev/null +++ b/src/imageplugins/hotpixels/imageplugin_hotpixels.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a digiKam image plugin for fixing dots produced by + * hot/stuck/dead pixels from a CCD. + * + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_HOTPIXELS_H +#define IMAGEPLUGIN_HOTPIXELS_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_HotPixels : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_HotPixels(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_HotPixels(); + + void setEnabledActions(bool enable); + +private slots: + + void slotHotPixels(); + +private: + + TDEAction *m_hotpixelsAction; +}; + +#endif /* IMAGEPLUGIN_HOTPIXELS_H */ diff --git a/src/imageplugins/hotpixels/weights.cpp b/src/imageplugins/hotpixels/weights.cpp new file mode 100644 index 00000000..e0d3f246 --- /dev/null +++ b/src/imageplugins/hotpixels/weights.cpp @@ -0,0 +1,283 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a class to calculate filter weights + * + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +// C++ includes. + +#include <cstring> + +// Local includes. + +#include "weights.h" + +namespace DigikamHotPixelsImagesPlugin +{ + +Weights::Weights(const Weights &w) +{ + (*this) = w; +} + +void Weights::operator=(const Weights &w) +{ + mHeight=w.height(); + mWidth=w.width(); + mPositions=(w.positions()); + mCoefficientNumber=w.coefficientNumber(); + mTwoDim=w.twoDim(); + mPolynomeOrder=w.polynomeOrder(); + + // Allocate memory and copy weights + // if the original one was calculated + + if (!w.weightMatrices()) return; + else + { + double*** origMatrices=w.weightMatrices(); + mWeightMatrices = new double**[mPositions.count()]; //allocate mPositions.count() matrices + + for (uint i=0; i<mPositions.count(); i++) + { + mWeightMatrices[i]=new double*[mHeight]; //allocate mHeight rows on each position + for (unsigned int j=0; j<mHeight; j++) + { + mWeightMatrices[i][j]=new double[mWidth]; //Allocate mWidth columns on each row + for (unsigned int k=0; k<mWidth; k++) + { + mWeightMatrices[i][j][k]=origMatrices[i][j][k]; + } + } + } + } +} + +void Weights::calculateWeights() +{ + mCoefficientNumber = (mTwoDim + ? ((size_t)mPolynomeOrder + 1) * ((size_t)mPolynomeOrder + 1) + : (size_t)mPolynomeOrder + 1); + double *matrix; /* num_coeff * num_coeff */ + double *vector0; /* mPositions.count() * num_coeff */ + double *vector1; /* mPositions.count() * num_coeff */ + size_t ix,iy,i,j; + int x, y; + + // Determine coordinates of pixels to be sampled + + if (mTwoDim) + { + + int iPolynomeOrder=(int) mPolynomeOrder; //lets avoid signed/unsigned comparison warnings + int iHeight = (int) height(); //" + int iWidth = (int) width(); //" + + for (y = -iPolynomeOrder; y < iHeight + iPolynomeOrder; ++y) + { + for (x = -iPolynomeOrder; x < iWidth + iPolynomeOrder; ++x) + { + if ((x < 0 && y < 0 && -x - y < iPolynomeOrder + 2) + || (x < 0 && y >= iHeight && -x + y - iHeight < iPolynomeOrder + 1) + || (x >= iWidth && y < 0 && x - y - iWidth < iPolynomeOrder + 1) + || (x >= iWidth && y >= iHeight && x + y - iWidth - iHeight < iPolynomeOrder) + || (x < 0 && y >= 0 && y < iHeight) || (x >= iWidth && y >= 0 && y < iHeight) + || (y < 0 && x >= 0 && x < iWidth ) || (y >= iHeight && x >= 0 && x < iWidth)) + { + TQPoint position(x,y); + mPositions.append(position); + } + } + } + } + else + { + // In the one-dimensional case, only the y coordinate and y size is used. */ + + for (y = -mPolynomeOrder; y < 0; ++y) + { + TQPoint position(0,y); + mPositions.append(position); + } + + for (y = (int) height(); y < (int) height() + (int) mPolynomeOrder; ++y) + { + TQPoint position(0,y); + mPositions.append(position); + } + } + + // Allocate memory. + + matrix = new double[mCoefficientNumber*mCoefficientNumber]; + vector0 = new double[mPositions.count() * mCoefficientNumber]; + vector1 = new double[mPositions.count() * mCoefficientNumber]; + + // Calculate coefficient matrix and vectors + + for (iy = 0; iy < mCoefficientNumber; ++iy) + { + for (ix = 0; ix < mCoefficientNumber; ++ix) + matrix [iy*mCoefficientNumber+ix] = 0.0; + + for (j = 0; j < mPositions.count(); ++j) + { + vector0 [iy * mPositions.count() + j] = polyTerm (iy, mPositions [j].x(), + mPositions [j].y(), mPolynomeOrder); + + for (ix = 0; ix < mCoefficientNumber; ++ix) + matrix [iy * mCoefficientNumber + ix] += (vector0 [iy * mPositions.count() + j] + * polyTerm (ix, mPositions [j].x(), mPositions[j].y(), mPolynomeOrder)); + } + } + + // Invert matrix. + + matrixInv (matrix, mCoefficientNumber); + + // Multiply inverse matrix with vector. + + for (iy = 0; iy < mCoefficientNumber; ++iy) + for (j = 0; j < mPositions.count(); ++j) + { + vector1 [iy * mPositions.count() + j] = 0.0; + + for (ix = 0; ix < mCoefficientNumber; ++ix) + vector1 [iy * mPositions.count() + j] += matrix [iy * mCoefficientNumber + ix] + * vector0 [ix * mPositions.count() + j]; + } + + // Store weights + + mWeightMatrices = new double**[mPositions.count()]; //allocate mPositions.count() matrices + + for (i=0; i<mPositions.count(); i++) + { + mWeightMatrices[i] = new double*[mHeight]; //allocate mHeight rows on each position + for (j=0; j<mHeight; j++) + mWeightMatrices[i][j] = new double[mWidth]; //Allocate mWidth columns on each row + } + + for (y = 0; y < (int) mHeight; ++y) + { + for (x = 0; x < (int) mWidth; ++x) + { + for (j = 0; j < mPositions.count(); ++j) + { + mWeightMatrices [j][y][x] = 0.0; + + for (iy = 0; iy < mCoefficientNumber; ++iy) + mWeightMatrices [j][y][x] += vector1 [iy * mPositions.count() + j] + * polyTerm (iy, x, y, mPolynomeOrder); + + mWeightMatrices [j][y][x] *= (double) mPositions.count(); + } + } + } + + delete[] vector1; + delete[] vector0; + delete[] matrix; +} + +bool Weights::operator==(const Weights& ws) const +{ + return (mHeight==ws.height() && + mWidth==ws.width() && + mPolynomeOrder==ws.polynomeOrder() && + mTwoDim==ws.twoDim() + ); +} + + //Invert a quadratic matrix. +void Weights::matrixInv (double *const a, const size_t size) +{ + double *const b = new double[size * size]; + size_t ix, iy, j; + + // Copy matrix to new location. + + memcpy (b, a, sizeof (double) * size * size); + + // Set destination matrix to unit matrix. + + for (iy = 0; iy < size; ++iy) + for (ix = 0; ix < size; ++ix) + a [iy * size + ix] = ix == iy ? 1.0 : 0.0; + + // Convert matrix to upper triangle form. + + for (iy = 0; iy < size - 1; ++iy) + { + for (j = iy + 1; j < size; ++j) + { + const double factor = b [j * size + iy] / b [iy * size + iy]; + + for (ix = 0; ix < size; ++ix) + { + b [j * size + ix] -= factor * b [iy * size + ix]; + a [j * size + ix] -= factor * a [iy * size + ix]; + } + } + } + + // Convert matrix to diagonal form. + + for (iy = size - 1; iy > 0; --iy) + { + for (j = 0; j < iy; ++j) + { + const double factor = b [j * size + iy] / b [iy * size + iy]; + + for (ix = 0; ix < size; ++ix) + a [j * size + ix] -= factor * a [iy * size + ix]; + } + } + + // Convert matrix to unit matrix. + + for (iy = 0; iy < size; ++iy) + for (ix = 0; ix < size; ++ix) + a [iy * size + ix] /= b [iy * size + iy]; + + delete [] b; +} + +// Calculates one term of the polynomial +double Weights::polyTerm (const size_t i_coeff, const int x, const int y, const int poly_order) +{ + const size_t x_power = i_coeff / ((size_t)poly_order + 1); + const size_t y_power = i_coeff % ((size_t)poly_order + 1); + int result; + size_t i; + + result = 1; + + for (i = 0; i < x_power; ++i) + result *= x; + + for (i = 0; i < y_power; ++i) + result *= y; + + return (double)result; +} + +} // NameSpace DigikamHotPixelsImagesPlugin + diff --git a/src/imageplugins/hotpixels/weights.h b/src/imageplugins/hotpixels/weights.h new file mode 100644 index 00000000..b82fde89 --- /dev/null +++ b/src/imageplugins/hotpixels/weights.h @@ -0,0 +1,90 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-27 + * Description : a class to calculate filter weights + * + * Copyright (C) 2005-2006 by Unai Garro <ugarro at users dot sourceforge dot net> + * + * 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. + * + * ============================================================ */ + +#ifndef WEIGHTS_H +#define WEIGHTS_H + +// TQt includes. + +#include <tqrect.h> +#include <tqvaluelist.h> + +namespace DigikamHotPixelsImagesPlugin +{ + +class Weights +{ +public: + + Weights(){}; + Weights(const Weights &w); + void operator=(const Weights &w); + + ~Weights() + { + if (!mWeightMatrices) return; + for (unsigned int i=0; i<mPositions.count(); i++) + { + for (unsigned int j=0; j<mHeight; j++) delete[] mWeightMatrices[i][j]; + } + } + + unsigned int height() const { return mHeight; }; + unsigned int polynomeOrder() const { return mPolynomeOrder; }; + bool twoDim() const { return mTwoDim; }; + unsigned int width() const { return mWidth; }; + + void setHeight(int h) { mHeight=h; }; + void setPolynomeOrder(int order) { mPolynomeOrder=order; }; + void setTwoDim(bool td) { mTwoDim=td; }; + void setWidth(int w) { mWidth=w; }; + + void calculateWeights(); + bool operator==(const Weights& ws) const; + double** operator[](int n) const { return mWeightMatrices[n]; }; + const TQValueList <TQPoint> positions() const { return mPositions; }; + +protected: + + int coefficientNumber() const { return mCoefficientNumber; }; + + double*** weightMatrices() const { return mWeightMatrices; }; + +private: + + double polyTerm (const size_t i_coeff, const int x, const int y, const int poly_order); + void matrixInv (double *const a, const size_t size); + +private: + + unsigned int mHeight,mWidth; + unsigned int mCoefficientNumber; + bool mTwoDim; + unsigned int mPolynomeOrder; + double *** mWeightMatrices; //Stores a list of weight matrices + TQValueList <TQPoint> mPositions; +}; + +} // NameSpace DigikamHotPixelsImagesPlugin + +#endif // WEIGHTS_H |