File indexing completed on 2024-05-12 15:58:12
0001 /* 0002 * SPDX-FileCopyrightText: 2005, 2008 Cyrille Berger <cberger@cberger.net> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_convolution_kernel.h" 0008 0009 #include <math.h> 0010 0011 #include <QImage> 0012 #include <kis_mask_generator.h> 0013 0014 struct Q_DECL_HIDDEN KisConvolutionKernel::Private { 0015 qreal offset; 0016 qreal factor; 0017 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> data; 0018 }; 0019 0020 KisConvolutionKernel::KisConvolutionKernel(quint32 _width, quint32 _height, qreal _offset, qreal _factor) : d(new Private) 0021 { 0022 d->offset = _offset; 0023 d->factor = _factor; 0024 setSize(_width, _height); 0025 } 0026 0027 KisConvolutionKernel::~KisConvolutionKernel() 0028 { 0029 delete d; 0030 } 0031 0032 quint32 KisConvolutionKernel::width() const 0033 { 0034 return d->data.cols(); 0035 } 0036 0037 quint32 KisConvolutionKernel::height() const 0038 { 0039 return d->data.rows(); 0040 } 0041 0042 void KisConvolutionKernel::setSize(quint32 width, quint32 height) 0043 { 0044 d->data.resize(height, width); 0045 } 0046 0047 0048 qreal KisConvolutionKernel::offset() const 0049 { 0050 return d->offset; 0051 } 0052 0053 qreal KisConvolutionKernel::factor() const 0054 { 0055 return d->factor; 0056 } 0057 0058 void KisConvolutionKernel::setFactor(qreal factor) 0059 { 0060 d->factor = factor; 0061 } 0062 0063 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic>& KisConvolutionKernel::data() 0064 { 0065 return d->data; 0066 } 0067 0068 const Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic>* KisConvolutionKernel::data() const 0069 { 0070 return &(d->data); 0071 } 0072 0073 KisConvolutionKernelSP KisConvolutionKernel::fromQImage(const QImage& image) 0074 { 0075 KisConvolutionKernelSP kernel = new KisConvolutionKernel(image.width(), image.height(), 0, 0); 0076 0077 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic>& data = kernel->data(); 0078 const quint8* itImage = image.constBits(); 0079 qreal factor = 0; 0080 0081 for (int r = 0; r < image.height(); r++) { 0082 for (int c = 0; c < image.width(); c++, itImage += 4) 0083 { 0084 uint value = 255 - (*itImage + *(itImage + 1) + *(itImage + 2)) / 3; 0085 data(r, c) = value; 0086 factor += value; 0087 } 0088 } 0089 0090 kernel->setFactor(factor); 0091 return kernel; 0092 } 0093 0094 KisConvolutionKernelSP KisConvolutionKernel::fromMaskGenerator(KisMaskGenerator* kmg, qreal angle) 0095 { 0096 Q_UNUSED(angle); 0097 0098 qint32 width = (int)(kmg->width() + 0.5); 0099 qint32 height = (int)(kmg->height() + 0.5); 0100 0101 KisConvolutionKernelSP kernel = new KisConvolutionKernel(width, height, 0, 0); 0102 0103 qreal cosa = cos(angle); 0104 qreal sina = sin(angle); 0105 qreal xc = 0.5 * width - 0.5; 0106 qreal yc = 0.5 * height - 0.5; 0107 0108 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic>& data = kernel->data(); 0109 qreal factor = 0; 0110 0111 // dbgImage << ppVar(xc) << ppVar(yc); 0112 for (int r = 0; r < height; ++r) { 0113 for (int c = 0; c < width; ++c) { 0114 qreal x_ = (c - xc); 0115 qreal y_ = (r - yc); 0116 qreal x = cosa * x_ - sina * y_; 0117 qreal y = sina * x_ + cosa * y_; 0118 // dbgImage << ppVar(x) << ppVar(y) << ppVar(x_) << ppVar(y_) << ppVar( kmg->interpolatedValueAt( x,y) ); 0119 uint value = 255 - kmg->valueAt(x, y); 0120 data(r, c) = value; 0121 factor += value; 0122 } 0123 } 0124 kernel->setFactor(factor); 0125 return kernel; 0126 } 0127 0128 KisConvolutionKernelSP KisConvolutionKernel::fromMatrix(Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix, qreal offset, qreal factor) 0129 { 0130 KisConvolutionKernelSP kernel = new KisConvolutionKernel(matrix.cols(), matrix.rows(), offset, factor); 0131 kernel->data() = matrix; 0132 0133 return kernel; 0134 } 0135 0136 0137 0138 0139 #if 0 0140 double xr = (x /*- m_xcenter*/); 0141 double yr = (y /*- m_ycenter*/); 0142 double n = norme(xr * m_xcoef, yr * m_ycoef); 0143 if (n > 1) 0144 { 0145 return 255; 0146 } else 0147 { 0148 double normeFade = norme(xr * m_xfadecoef, yr * m_yfadecoef); 0149 if (normeFade > 1) { 0150 double xle, yle; 0151 // xle stands for x-coordinate limit exterior 0152 // yle stands for y-coordinate limit exterior 0153 // we are computing the coordinate on the external ellipse in order to compute 0154 // the fade value 0155 if (xr == 0) { 0156 xle = 0; 0157 yle = yr > 0 ? 1 / m_ycoef : -1 / m_ycoef; 0158 } else { 0159 double c = yr / (double)xr; 0160 xle = sqrt(1 / norme(m_xcoef, c * m_ycoef)); 0161 xle = xr > 0 ? xle : -xle; 0162 yle = xle * c; 0163 } 0164 // On the internal limit of the fade area, normeFade is equal to 1 0165 double normeFadeLimitE = norme(xle * m_xfadecoef, yle * m_yfadecoef); 0166 return (uchar)(255 *(normeFade - 1) / (normeFadeLimitE - 1)); 0167 } else { 0168 return 0; 0169 } 0170 } 0171 #endif 0172 0173 #include "kis_debug.h" 0174 0175 QDebug operator<<(QDebug debug, const KisConvolutionKernel &c) 0176 { 0177 debug.nospace() << "[" << c.width() << "," << c.height() << "]{"; 0178 for (unsigned int i = 0; i < c.width(); ++i) { 0179 debug.nospace() << " {"; 0180 for (unsigned int j = 0; j < c.height(); ++j) { 0181 debug.nospace() << (*(c.data()))(j, i) << " "; 0182 } 0183 debug.nospace() << " }"; 0184 } 0185 debug.nospace() << c.factor() << " " << c.offset() << " }"; 0186 return debug.space(); 0187 }