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/antivignetting/antivignetting.cpp

150 lines
4.8 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2005-05-25
* Description : Antivignetting threaded image filter.
*
* Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* Original AntiVignetting algorithm copyrighted 2003 by
* John Walker from 'pnmctrfilt' implementation. See
* http://www.fourmilab.ch/netpbm/pnmctrfilt for more
* information.
*
* 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>
// Local includes.
#include "dimg.h"
#include "dimgimagefilters.h"
#include "antivignetting.h"
namespace DigikamAntiVignettingImagesPlugin
{
AntiVignetting::AntiVignetting(Digikam::DImg *orgImage, TQObject *parent, double density,
double power, double radius, int xshift, int yshift, bool normalize)
: Digikam::DImgThreadedFilter(orgImage, parent, "AntiVignetting")
{
m_density = density;
m_power = power;
m_radius = radius;
m_xshift = xshift;
m_yshift = yshift;
m_normalize = normalize;
initFilter();
}
// This method is inspired from John Walker 'pnmctrfilt' algorithm code.
void AntiVignetting::filterImage(void)
{
int progress;
int col, row, xd, td, yd, p;
int i, xsize, ysize, diagonal, erad, xctr, yctr;
double *ldens;
uchar* NewBits = m_destImage.bits();
uchar* data = m_orgImage.bits();
unsigned short* NewBits16 = (unsigned short*)m_destImage.bits();
unsigned short* data16 = (unsigned short*)m_orgImage.bits();
int Width = m_orgImage.width();
int Height = m_orgImage.height();
// Determine the radius of the filter. This is the half diagonal
// measure of the image multiplied by the command line radius factor.
xsize = (Height + 1) / 2;
ysize = (Width + 1) / 2;
erad = (int)((sqrt((xsize * xsize) + (ysize * ysize)) + 0.5) * m_radius);
// Build the in-memory table which maps distance from the
// center of the image (as adjusted by the X and Y offset,
// if any) to the density of the filter at this remove. This
// table needs to be as large as the diagonal from the
// (possibly offset) center to the most distant corner
// of the image.
xsize = ((Height + 1) / 2) + abs(m_xshift);
ysize = ((Width + 1) / 2) + abs(m_yshift);
diagonal = ((int) (sqrt((xsize * xsize) + (ysize * ysize)) + 0.5)) + 1;
ldens = new double[diagonal];
for (i = 0 ; !m_cancel && (i < diagonal) ; i++)
{
if ( i >= erad )
ldens[i] = 1;
else
ldens[i] = (1.0 + (m_density - 1) * pow(1.0 - (((double) i) / (erad - 1)), m_power));
}
xctr = ((Height + 1) / 2) + m_xshift;
yctr = ((Width + 1) / 2) + m_yshift;
for (row = 0 ; !m_cancel && (row < Width) ; row++)
{
yd = abs(yctr - row);
for (col = 0 ; !m_cancel && (col < Height) ; col++)
{
p = (col * Width + row)*4;
xd = abs(xctr - col);
td = (int) (sqrt((xd * xd) + (yd * yd)) + 0.5);
if (!m_orgImage.sixteenBit()) // 8 bits image
{
NewBits[ p ] = (uchar)(data[ p ] / ldens[td]);
NewBits[p+1] = (uchar)(data[p+1] / ldens[td]);
NewBits[p+2] = (uchar)(data[p+2] / ldens[td]);
NewBits[p+3] = data[p+3];
}
else // 16 bits image.
{
NewBits16[ p ] = (unsigned short)(data16[ p ] / ldens[td]);
NewBits16[p+1] = (unsigned short)(data16[p+1] / ldens[td]);
NewBits16[p+2] = (unsigned short)(data16[p+2] / ldens[td]);
NewBits16[p+3] = data16[p+3];
}
}
// Update the progress bar in dialog.
progress = (int)(((double)row * 100.0) / Width);
if (progress%5 == 0)
postProgress( progress );
}
// Normalize colors for a best rendering.
if (m_normalize)
{
Digikam::DImgImageFilters filters;
filters.normalizeImage(m_destImage.bits(), Width, Height, m_destImage.sixteenBit());
}
delete [] ldens;
}
} // NameSpace DigikamAntiVignettingImagesPlugin