File indexing completed on 2024-12-22 04:15:13

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Miroslav Talasek <miroslav.talasek@seznam.cz>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_wavelet_kernel.h"
0008 
0009 #include "kis_convolution_kernel.h"
0010 #include <kis_convolution_painter.h>
0011 #include <QRect>
0012 
0013 
0014 
0015 int KisWaveletKernel::kernelSizeFromRadius(qreal radius)
0016 {
0017     return 2 * ceil(radius) + 1;
0018 }
0019 
0020 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic>
0021 KisWaveletKernel::createHorizontalMatrix(qreal radius)
0022 {
0023     int kernelSize = kernelSizeFromRadius(radius);
0024     Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix(1, kernelSize);
0025 
0026     /**
0027      * The kernel size should always be odd, then the position of the
0028      * central pixel can be easily calculated
0029      */
0030     KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1);
0031     const int center = kernelSize / 2;
0032 
0033     for (int x = 0; x < kernelSize; x++) {
0034         if (x == 0 || x == kernelSize - 1)
0035             matrix(0, x) = 0.25;
0036         else if (x == center)
0037             matrix(0, x) = 0.5;
0038         else
0039             matrix(0, x) = 0;
0040     }
0041 
0042     return matrix;
0043 }
0044 
0045 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic>
0046 KisWaveletKernel::createVerticalMatrix(qreal radius)
0047 {
0048     int kernelSize = kernelSizeFromRadius(radius);
0049     Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix(kernelSize, 1);
0050 
0051 
0052     /**
0053      * The kernel size should always be odd, then the position of the
0054      * central pixel can be easily calculated
0055      */
0056     KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1);
0057     const int center = kernelSize / 2;
0058 
0059     for (int y = 0; y < kernelSize; y++) {
0060         if (y == 0 || y == kernelSize - 1)
0061             matrix(y, 0) = 0.25;
0062         else if (y == center)
0063             matrix(y, 0) = 0.5;
0064         else
0065             matrix(y, 0) = 0;
0066     }
0067 
0068     return matrix;
0069 }
0070 
0071 KisConvolutionKernelSP
0072 KisWaveletKernel::createHorizontalKernel(qreal radius)
0073 {
0074     Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix = createHorizontalMatrix(radius);
0075     return KisConvolutionKernel::fromMatrix(matrix, 0, matrix.sum());
0076 }
0077 
0078 KisConvolutionKernelSP
0079 KisWaveletKernel::createVerticalKernel(qreal radius)
0080 {
0081     Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix = createVerticalMatrix(radius);
0082     return KisConvolutionKernel::fromMatrix(matrix, 0, matrix.sum());
0083 }
0084 
0085 void KisWaveletKernel::applyWavelet(KisPaintDeviceSP device,
0086                                       const QRect& rect,
0087                                       qreal xRadius, qreal yRadius,
0088                                       const QBitArray &channelFlags,
0089                                       KoUpdater *progressUpdater)
0090 {
0091     QPoint srcTopLeft = rect.topLeft();
0092 
0093     if (xRadius > 0.0 && yRadius > 0.0) {
0094         KisPaintDeviceSP interm = new KisPaintDevice(device->colorSpace());
0095         interm->prepareClone(device);
0096 
0097         KisConvolutionKernelSP kernelHoriz = KisWaveletKernel::createHorizontalKernel(xRadius);
0098         KisConvolutionKernelSP kernelVertical = KisWaveletKernel::createVerticalKernel(yRadius);
0099 
0100         qreal verticalCenter = qreal(kernelVertical->height()) / 2.0;
0101 
0102         KisConvolutionPainter horizPainter(interm);
0103         horizPainter.setChannelFlags(channelFlags);
0104         horizPainter.setProgress(progressUpdater);
0105         horizPainter.applyMatrix(kernelHoriz, device,
0106                                  srcTopLeft - QPoint(0, ceil(verticalCenter)),
0107                                  srcTopLeft - QPoint(0, ceil(verticalCenter)),
0108                                  rect.size() + QSize(0, 2 * ceil(verticalCenter)), BORDER_REPEAT);
0109 
0110         KisConvolutionPainter verticalPainter(device);
0111         verticalPainter.setChannelFlags(channelFlags);
0112         verticalPainter.setProgress(progressUpdater);
0113         verticalPainter.applyMatrix(kernelVertical, interm, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT);
0114 
0115     } else if (xRadius > 0.0) {
0116         KisConvolutionPainter painter(device);
0117         painter.setChannelFlags(channelFlags);
0118         painter.setProgress(progressUpdater);
0119 
0120         KisConvolutionKernelSP kernelHoriz = KisWaveletKernel::createHorizontalKernel(xRadius);
0121         painter.applyMatrix(kernelHoriz, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT);
0122 
0123     } else if (yRadius > 0.0) {
0124         KisConvolutionPainter painter(device);
0125         painter.setChannelFlags(channelFlags);
0126         painter.setProgress(progressUpdater);
0127 
0128         KisConvolutionKernelSP kernelVertical = KisWaveletKernel::createVerticalKernel(yRadius);
0129         painter.applyMatrix(kernelVertical, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT);
0130     }
0131 }