8#ifndef KIS_CONVOLUTION_WORKER_FFT_H
9#define KIS_CONVOLUTION_WORKER_FFT_H
39template<
class _IteratorFactory_>
57 const QRect &dataRect)
override
63 dstPos += r.topLeft() - srcPos;
68 if (areaSize.width() == 0 || areaSize.height() == 0)
74 const quint32 halfKernelWidth = (kernel->
width() - 1) / 2;
75 const quint32 halfKernelHeight = (kernel->
height() - 1) / 2;
77 m_fftWidth = areaSize.width() + 4 * halfKernelWidth;
78 m_fftHeight = areaSize.height() + 2 * halfKernelHeight;
100 *i = (fftw_complex *)fftw_malloc(
sizeof(fftw_complex) *
m_fftLength);
103 const double kernelFactor = kernel->
factor() ? kernel->
factor() : 1;
110 QRect(srcPos.x() - halfKernelWidth,
111 srcPos.y() - halfKernelHeight,
121 const float progressPerFFT = (100 - 30) / (
double)(convChannelList.count() * 2 + 1);
124 fftw_plan fftwPlanForward, fftwPlanBackward;
131 fftw_execute(fftwPlanForward);
137 fftw_execute_dft_r2c(fftwPlanForward, (
double*)(*k), *k);
143 fftw_execute_dft_c2r(fftwPlanBackward, *k, (
double*)*k);
149 fftw_destroy_plan(fftwPlanForward);
150 fftw_destroy_plan(fftwPlanBackward);
155 cacheRowStride, halfKernelWidth, halfKernelHeight,
216 const int cacheRowStride,
218 const QRect &dataRect) {
220 typename _IteratorFactory_::HLineConstIterator hitSrc =
221 _IteratorFactory_::createHLineConstIterator(src,
227 const auto channelPtrBegin = channelPtr.begin();
228 const auto channelPtrEnd = channelPtr.end();
231 for (
auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++iFFt) {
237 const auto cacheRowStartBegin = cacheRowStart.begin();
239 for (
int y = 0; y <
rect.height(); ++y) {
241 memcpy(cacheRowStart.data(), channelPtr.data(), channelCount *
sizeof(
double*));
243 for (
int x = 0; x <
rect.width(); ++x) {
244 const quint8 *data = hitSrc->oldRawData();
250 for (
auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++k) {
264 auto iRowStart = cacheRowStartBegin;
265 for (
auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++iRowStart) {
266 *i = *iRowStart + cacheRowStride;
275 if (*
value > highBound) {
277 }
else if (!(*
value >= lowBound)) {
284 const quint32 channel,
286 double* channelValuePtr,
287 bool *dstValueIsNull) {
288 qreal channelPixelValue;
294 return channelPixelValue;
297 template <
bool additionalMultiplierActive>
299 const quint32 channel,
301 double* channelValuePtr,
302 const qreal additionalMultiplier = 0.0) {
303 qreal channelPixelValue;
305 if (additionalMultiplierActive) {
306 channelPixelValue = *channelValuePtr * info.
fftScale * additionalMultiplier + info.
absoluteOffset[channel];
315 return channelPixelValue;
319 const int cacheRowStride,
320 const int halfKernelWidth,
321 const int halfKernelHeight,
323 const QRect &dataRect) {
325 typename _IteratorFactory_::HLineIterator hitDst =
330 int initialOffset = cacheRowStride * halfKernelHeight + halfKernelWidth;
334 const auto channelPtrBegin = channelPtr.begin();
335 const auto channelPtrEnd = channelPtr.end();
338 for (
auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++iFFt) {
339 *i = (
double*)*iFFt + initialOffset;
344 const auto cacheRowStartBegin = cacheRowStart.begin();
346 for (
int y = 0; y <
rect.height(); ++y) {
348 memcpy(cacheRowStart.data(), channelPtr.data(), channelCount *
sizeof(
double*));
350 for (
int x = 0; x <
rect.width(); ++x) {
351 quint8 *dstPtr = hitDst->rawData();
354 bool alphaIsNullInDstSpace =
false;
361 &alphaIsNullInDstSpace);
363 if (!alphaIsNullInDstSpace &&
364 alphaValue > std::numeric_limits<qreal>::epsilon()) {
366 qreal alphaValueInv = 1.0 / alphaValue;
369 for (
auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++k) {
371 writeOneChannelFromCache<true>(dstPtr,
381 for (
auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++k) {
392 for (
auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++k) {
393 writeOneChannelFromCache<false>(dstPtr,
404 auto iRowStart = cacheRowStartBegin;
405 for (
auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++iRowStart) {
406 *i = *iRowStart + cacheRowStride;
418 QPoint offset((kernel->
width() - 1) / 2, (kernel->
height() - 1) / 2);
423 quint32 absXpos, absYpos;
425 for (quint32 y = 0; y < kernel->
height(); y++)
427 absYpos = y + yShift;
431 for (quint32 x = 0; x < kernel->
width(); x++)
433 absXpos = x + xShift;
445 fftw_complex *channelPtr = channel;
446 fftw_complex *kernelPtr = kernel;
450 for (quint32 pixelPos = 0; pixelPos <
m_fftLength; ++pixelPos)
452 tmp[0] = ((*channelPtr)[0] * (*kernelPtr)[0]) - ((*channelPtr)[1] * (*kernelPtr)[1]);
453 tmp[1] = ((*channelPtr)[0] * (*kernelPtr)[1]) + ((*channelPtr)[1] * (*kernelPtr)[0]);
455 (*channelPtr)[0] =
tmp[0];
456 (*channelPtr)[1] =
tmp[1];
466 quint32 optW = w, optH = h;
468 while ((optW % 2 != 0) || (optW % 3 != 0) || (optW % 5 != 0) || (optW % 7 != 0))
471 while ((optH % 2 != 0) || (optH % 3 != 0) || (optH % 5 != 0) || (optH % 7 != 0))
474 quint32 optAreaW = optW * h;
475 quint32 optAreaH = optH * w;
477 if (optAreaW < optAreaH) {
488 QString filename(QDir::homePath() +
"/log_" + f +
".txt");
489 dbgKrita <<
"Log File Name: " << filename;
490 QFile file (filename);
491 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
498 QTextStream in(&file);
504 QString num = QString::number(channel[y *
m_fftWidth + x]);
505 while (num.length() < 15)
float value(const T *src, size_t ch)
void fillCacheFromDevice(KisPaintDeviceSP src, const QRect &rect, const int cacheRowStride, const FFTInfo &info, const QRect &dataRect)
void optimumDimensions(quint32 &w, quint32 &h)
KisConvolutionWorkerFFT(KisPainter *painter, KoUpdater *progress)
void fftFillKernelMatrix(const KisConvolutionKernelSP kernel, fftw_complex *m_kernelFFT)
void writeResultToDevice(const QRect &rect, const int cacheRowStride, const int halfKernelWidth, const int halfKernelHeight, const FFTInfo &info, const QRect &dataRect)
void fftLogMatrix(double *channel, const QString &f)
fftw_complex * m_kernelFFT
void execute(const KisConvolutionKernelSP kernel, const KisPaintDeviceSP src, QPoint srcPos, QPoint dstPos, QSize areaSize, const QRect &dataRect) override
void limitValue(qreal *value, qreal lowBound, qreal highBound)
void addToProgress(float amount)
~KisConvolutionWorkerFFT()
QVector< fftw_complex * > m_channelFFT
qreal writeAlphaFromCache(quint8 *dstPtr, const quint32 channel, const FFTInfo &info, double *channelValuePtr, bool *dstValueIsNull)
void fftMultiply(fftw_complex *channel, fftw_complex *kernel)
qreal writeOneChannelFromCache(quint8 *dstPtr, const quint32 channel, const FFTInfo &info, double *channelValuePtr, const qreal additionalMultiplier=0.0)
QList< KoChannelInfo * > convolvableChannelList(const KisPaintDeviceSP src)
const KoColorSpace * colorSpace() const
@ ALPHA
The channel represents the opacity of a pixel.
void setProgress(int percent)
void setUtf8OnStream(QTextStream &stream)
Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > data
QVector< PtrFromDouble > fromDoubleFuncPtr
QVector< qreal > minClamp
QList< KoChannelInfo * > convChannelList
QVector< qreal > maxClamp
FFTInfo(qreal _fftScale, const QList< KoChannelInfo * > &_convChannelList, const KisConvolutionKernelSP kernel, const KoColorSpace *)
QVector< PtrToDouble > toDoubleFuncPtr
QVector< qreal > absoluteOffset
QVector< PtrFromDoubleCheckNull > fromDoubleCheckNullFuncPtr
QRect selectedRect() const