You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/imageplugins/hotpixels/hotpixelfixer.cpp

303 lines
9.8 KiB

/* ============================================================
*
* 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 TQUADRATIC_INTERPOLATION:
// (Bi)quadratic interpolation.
weightPixels (img,hp,TQUADRATIC_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 TQUADRATIC_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