summaryrefslogtreecommitdiffstats
path: root/src/imageplugins/hotpixels/hotpixelfixer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imageplugins/hotpixels/hotpixelfixer.cpp')
-rw-r--r--src/imageplugins/hotpixels/hotpixelfixer.cpp302
1 files changed, 302 insertions, 0 deletions
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