/* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-05-25 * Description : Oil Painting threaded image filter. * * Copyright (C) 2005-2007 by Gilles Caulier * Copyright (C) 2006-2007 by Marcel Wiesweg * * Original OilPaint algorithm copyrighted 2004 by * Pieter Z. Voloshyn . * * 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 #include // Local includes. #include "ddebug.h" #include "dimg.h" #include "dimggaussianblur.h" #include "dimgimagefilters.h" #include "oilpaint.h" namespace DigikamOilPaintImagesPlugin { OilPaint::OilPaint(Digikam::DImg *orgImage, TQObject *parent, int brushSize, int smoothness) : Digikam::DImgThreadedFilter(orgImage, parent, "OilPaint") { m_brushSize = brushSize; m_smoothness = smoothness; initFilter(); } void OilPaint::filterImage(void) { oilpaintImage(m_orgImage, m_destImage, m_brushSize, m_smoothness); } // This method have been ported from Pieter Z. Voloshyn algorithm code. /* Function to apply the OilPaint effect. * * data => The image data in RGBA mode. * w => Width of image. * h => Height of image. * BrushSize => Brush size. * Smoothness => Smooth value. * * Theory => Using MostFrequentColor function we take the main color in * a matrix and simply write at the original position. */ void OilPaint::oilpaintImage(Digikam::DImg &orgImage, Digikam::DImg &destImage, int BrushSize, int Smoothness) { int progress; Digikam::DColor mostFrequentColor; int w,h; mostFrequentColor.setSixteenBit(orgImage.sixteenBit()); w = (int)orgImage.width(); h = (int)orgImage.height(); uchar *dest = destImage.bits(); int bytesDepth = orgImage.bytesDepth(); uchar *dptr; // Allocate some arrays to be used. // Do this here once for all to save a few million new / delete operations m_intensityCount = new uchar[Smoothness + 1]; m_averageColorR = new uint[Smoothness + 1]; m_averageColorG = new uint[Smoothness + 1]; m_averageColorB = new uint[Smoothness + 1]; for (int h2 = 0; !m_cancel && (h2 < h); h2++) { for (int w2 = 0; !m_cancel && (w2 < w); w2++) { mostFrequentColor = MostFrequentColor(orgImage, w2, h2, BrushSize, Smoothness); dptr = dest + w2*bytesDepth + (w*h2*bytesDepth); mostFrequentColor.setPixel(dptr); } progress = (int) (((double)h2 * 100.0) / h); if ( progress%5 == 0 ) postProgress( progress ); } // free all the arrays delete [] m_intensityCount; delete [] m_averageColorR; delete [] m_averageColorG; delete [] m_averageColorB; } // This method have been ported from Pieter Z. Voloshyn algorithm code. /* Function to determine the most frequent color in a matrix * * Bits => Bits array * Width => Image width * Height => Image height * X => Position horizontal * Y => Position vertical * Radius => Is the radius of the matrix to be analized * Intensity => Intensity to calcule * * Theory => This function creates a matrix with the analized pixel in * the center of this matrix and find the most frequenty color */ Digikam::DColor OilPaint::MostFrequentColor(Digikam::DImg &src, int X, int Y, int Radius, int Intensity) { int i, w, h, I, Width, Height; uint red, green, blue; uchar *dest = src.bits(); int bytesDepth = src.bytesDepth(); uchar *sptr; bool sixteenBit = src.sixteenBit(); Digikam::DColor mostFrequentColor; double Scale = Intensity / (sixteenBit ? 65535.0 : 255.0); Width = (int)src.width(); Height = (int)src.height(); // Erase the array memset(m_intensityCount, 0, (Intensity + 1) * sizeof (uchar)); for (w = X - Radius; w <= X + Radius; w++) { for (h = Y - Radius; h <= Y + Radius; h++) { // This condition helps to identify when a point doesn't exist if ((w >= 0) && (w < Width) && (h >= 0) && (h < Height)) { sptr = dest + w*bytesDepth + (Width*h*bytesDepth); Digikam::DColor color(sptr, sixteenBit); red = (uint)color.red(); green = (uint)color.green(); blue = (uint)color.blue(); I = lround(GetIntensity (red, green, blue) * Scale); m_intensityCount[I]++; if (m_intensityCount[I] == 1) { m_averageColorR[I] = red; m_averageColorG[I] = green; m_averageColorB[I] = blue; } else { m_averageColorR[I] += red; m_averageColorG[I] += green; m_averageColorB[I] += blue; } } } } I = 0; int MaxInstance = 0; for (i = 0 ; i <= Intensity ; i++) { if (m_intensityCount[i] > MaxInstance) { I = i; MaxInstance = m_intensityCount[i]; } } // get Alpha channel value from original (unchanged) mostFrequentColor = src.getPixelColor(X, Y); // Overwrite RGB values to destination. mostFrequentColor.setRed(m_averageColorR[I] / MaxInstance); mostFrequentColor.setGreen(m_averageColorG[I] / MaxInstance); mostFrequentColor.setBlue(m_averageColorB[I] / MaxInstance); return mostFrequentColor; } } // NameSpace DigikamOilPaintImagesPlugin