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 }