Krita Source Code Documentation
Loading...
Searching...
No Matches
KisGaussianKernel Class Reference

#include <kis_gaussian_kernel.h>

Static Public Member Functions

static void applyDilate (KisPaintDeviceSP device, const QRect &rect, qreal radius, const QBitArray &channelFlags, KoUpdater *progressUpdater, bool createTransaction=false)
 
static void applyErodeU8 (KisPaintDeviceSP device, const QRect &rect, qreal radius, const QBitArray &channelFlags, KoUpdater *progressUpdater, bool createTransaction=false)
 
static void applyGaussian (KisPaintDeviceSP device, const QRect &rect, qreal xRadius, qreal yRadius, const QBitArray &channelFlags, KoUpdater *updater, bool createTransaction=false, KisConvolutionBorderOp borderOp=BORDER_REPEAT)
 
static void applyLoG (KisPaintDeviceSP device, const QRect &rect, qreal radius, qreal coeff, const QBitArray &channelFlags, KoUpdater *progressUpdater)
 
static void applyTightLoG (KisPaintDeviceSP device, const QRect &rect, qreal radius, qreal coeff, const QBitArray &channelFlags, KoUpdater *progressUpdater)
 
static Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > createDilateMatrix (qreal radius)
 
static KisConvolutionKernelSP createHorizontalKernel (qreal radius)
 
static Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > createHorizontalMatrix (qreal radius)
 
static Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > createLoGMatrix (qreal radius, qreal coeff, bool zeroCentered, bool includeWrappedArea)
 
static KisConvolutionKernelSP createUniform2DKernel (qreal xRadius, qreal yRadius)
 
static KisConvolutionKernelSP createVerticalKernel (qreal radius)
 
static Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > createVerticalMatrix (qreal radius)
 
static int kernelSizeFromRadius (qreal radius)
 
static qreal sigmaFromRadius (qreal radius)
 

Detailed Description

Definition at line 18 of file kis_gaussian_kernel.h.

Member Function Documentation

◆ applyDilate()

void KisGaussianKernel::applyDilate ( KisPaintDeviceSP device,
const QRect & rect,
qreal radius,
const QBitArray & channelFlags,
KoUpdater * progressUpdater,
bool createTransaction = false )
static

Definition at line 344 of file kis_gaussian_kernel.cpp.

345{
347
348 QPoint srcTopLeft = rect.topLeft();
349
350 KisConvolutionPainter painter(device);
351 painter.setChannelFlags(channelFlags);
352 painter.setProgress(progressUpdater);
353
354 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix = createDilateMatrix(radius);
357 0,
358 1.0);
359
360 QScopedPointer<KisTransaction> transaction;
361 if (createTransaction && painter.needsTransaction(kernel)) {
362 transaction.reset(new KisTransaction(device));
363 }
364
365 painter.applyMatrix(kernel, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT);
366}
The KisConvolutionPainter class applies a convolution kernel to a paint device.
static Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > createDilateMatrix(qreal radius)
const KoColorSpace * colorSpace() const
virtual quint32 pixelSize() const =0
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
static KisConvolutionKernelSP fromMatrix(Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > matrix, qreal offset, qreal factor)

References KisConvolutionPainter::applyMatrix(), BORDER_REPEAT, KisPaintDevice::colorSpace(), createDilateMatrix(), KisConvolutionKernel::fromMatrix(), KIS_SAFE_ASSERT_RECOVER_RETURN, KisConvolutionPainter::needsTransaction(), KoColorSpace::pixelSize(), KisPainter::setChannelFlags(), and KisPainter::setProgress().

◆ applyErodeU8()

void KisGaussianKernel::applyErodeU8 ( KisPaintDeviceSP device,
const QRect & rect,
qreal radius,
const QBitArray & channelFlags,
KoUpdater * progressUpdater,
bool createTransaction = false )
static

Definition at line 370 of file kis_gaussian_kernel.cpp.

371{
373
374 {
375 KisSequentialIterator dstIt(device, rect);
376 while (dstIt.nextPixel()) {
377 quint8 *dstPtr = dstIt.rawData();
378 *dstPtr = 255 - *dstPtr;
379 }
380 }
381
382 applyDilate(device, rect, radius, channelFlags, progressUpdater, createTransaction);
383
384 {
385 KisSequentialIterator dstIt(device, rect);
386 while (dstIt.nextPixel()) {
387 quint8 *dstPtr = dstIt.rawData();
388 *dstPtr = 255 - *dstPtr;
389 }
390 }
391}
static void applyDilate(KisPaintDeviceSP device, const QRect &rect, qreal radius, const QBitArray &channelFlags, KoUpdater *progressUpdater, bool createTransaction=false)

References applyDilate(), KisPaintDevice::colorSpace(), KIS_SAFE_ASSERT_RECOVER_RETURN, KisSequentialIteratorBase< IteratorPolicy, SourcePolicy, ProgressPolicy >::nextPixel(), KoColorSpace::pixelSize(), and KisSequentialIteratorBase< IteratorPolicy, SourcePolicy, ProgressPolicy >::rawData().

◆ applyGaussian()

void KisGaussianKernel::applyGaussian ( KisPaintDeviceSP device,
const QRect & rect,
qreal xRadius,
qreal yRadius,
const QBitArray & channelFlags,
KoUpdater * updater,
bool createTransaction = false,
KisConvolutionBorderOp borderOp = BORDER_REPEAT )
static

Definition at line 102 of file kis_gaussian_kernel.cpp.

109{
110 QPoint srcTopLeft = rect.topLeft();
111
112
115 painter.setChannelFlags(channelFlags);
116 painter.setProgress(progressUpdater);
117
119
120 QScopedPointer<KisTransaction> transaction;
121 if (createTransaction && painter.needsTransaction(kernel2D)) {
122 transaction.reset(new KisTransaction(device));
123 }
124
125 painter.applyMatrix(kernel2D, device, srcTopLeft, srcTopLeft, rect.size(), borderOp);
126
127 } else if (xRadius > 0.0 && yRadius > 0.0) {
128 KisPaintDeviceSP interm = new KisPaintDevice(device->colorSpace());
129 interm->prepareClone(device);
130
133
134 qreal verticalCenter = qreal(kernelVertical->height()) / 2.0;
135
136 KisConvolutionPainter horizPainter(interm);
137 horizPainter.setChannelFlags(channelFlags);
138 horizPainter.setProgress(progressUpdater);
139 horizPainter.applyMatrix(kernelHoriz, device,
140 srcTopLeft - QPoint(0, ceil(verticalCenter)),
141 srcTopLeft - QPoint(0, ceil(verticalCenter)),
142 rect.size() + QSize(0, 2 * ceil(verticalCenter)), borderOp);
143
144
145 KisConvolutionPainter verticalPainter(device);
146 verticalPainter.setChannelFlags(channelFlags);
147 verticalPainter.setProgress(progressUpdater);
148 verticalPainter.applyMatrix(kernelVertical, interm, srcTopLeft, srcTopLeft, rect.size(), borderOp);
149
150 } else if (xRadius > 0.0) {
151 KisConvolutionPainter painter(device);
152 painter.setChannelFlags(channelFlags);
153 painter.setProgress(progressUpdater);
154
156
157 QScopedPointer<KisTransaction> transaction;
158 if (createTransaction && painter.needsTransaction(kernelHoriz)) {
159 transaction.reset(new KisTransaction(device));
160 }
161
162 painter.applyMatrix(kernelHoriz, device, srcTopLeft, srcTopLeft, rect.size(), borderOp);
163
164 } else if (yRadius > 0.0) {
165 KisConvolutionPainter painter(device);
166 painter.setChannelFlags(channelFlags);
167 painter.setProgress(progressUpdater);
168
170
171 QScopedPointer<KisTransaction> transaction;
172 if (createTransaction && painter.needsTransaction(kernelVertical)) {
173 transaction.reset(new KisTransaction(device));
174 }
175
176 painter.applyMatrix(kernelVertical, device, srcTopLeft, srcTopLeft, rect.size(), borderOp);
177 }
178}
static KisConvolutionKernelSP createVerticalKernel(qreal radius)
static KisConvolutionKernelSP createUniform2DKernel(qreal xRadius, qreal yRadius)
static KisConvolutionKernelSP createHorizontalKernel(qreal radius)
void prepareClone(KisPaintDeviceSP src)

References KisConvolutionPainter::applyMatrix(), KisPaintDevice::colorSpace(), createHorizontalKernel(), createUniform2DKernel(), createVerticalKernel(), KisConvolutionPainter::FFTW, KisConvolutionKernel::height(), KisConvolutionPainter::needsTransaction(), KisPaintDevice::prepareClone(), KisPainter::setChannelFlags(), KisPainter::setProgress(), and KisConvolutionPainter::supportsFFTW().

◆ applyLoG()

void KisGaussianKernel::applyLoG ( KisPaintDeviceSP device,
const QRect & rect,
qreal radius,
qreal coeff,
const QBitArray & channelFlags,
KoUpdater * progressUpdater )
static

Definition at line 264 of file kis_gaussian_kernel.cpp.

269{
270 QPoint srcTopLeft = rect.topLeft();
271
272 KisConvolutionPainter painter(device);
273 painter.setChannelFlags(channelFlags);
274 painter.setProgress(progressUpdater);
275
276 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix =
277 createLoGMatrix(radius, coeff, false, true);
280 0,
281 0);
282
283 painter.applyMatrix(kernel, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT);
284}
static Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > createLoGMatrix(qreal radius, qreal coeff, bool zeroCentered, bool includeWrappedArea)

References KisConvolutionPainter::applyMatrix(), BORDER_REPEAT, createLoGMatrix(), KisConvolutionKernel::fromMatrix(), KisPainter::setChannelFlags(), and KisPainter::setProgress().

◆ applyTightLoG()

void KisGaussianKernel::applyTightLoG ( KisPaintDeviceSP device,
const QRect & rect,
qreal radius,
qreal coeff,
const QBitArray & channelFlags,
KoUpdater * progressUpdater )
static

Definition at line 286 of file kis_gaussian_kernel.cpp.

291{
292 QPoint srcTopLeft = rect.topLeft();
293
294 KisConvolutionPainter painter(device);
295 painter.setChannelFlags(channelFlags);
296 painter.setProgress(progressUpdater);
297
298 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix =
299 createLoGMatrix(radius, coeff, true, false);
302 0,
303 0);
304
305 painter.applyMatrix(kernel, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT);
306}

References KisConvolutionPainter::applyMatrix(), BORDER_REPEAT, createLoGMatrix(), KisConvolutionKernel::fromMatrix(), KisPainter::setChannelFlags(), and KisPainter::setProgress().

◆ createDilateMatrix()

Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > KisGaussianKernel::createDilateMatrix ( qreal radius)
static

The kernel size should always be odd, then the position of the central pixel can be easily calculated

Definition at line 308 of file kis_gaussian_kernel.cpp.

309{
310 const int kernelSize = 2 * std::ceil(radius) + 1;
311 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix(kernelSize, kernelSize);
312
313 const qreal fadeStart = qMax(1.0, radius - 1.0);
314
319 KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1);
320 const int center = kernelSize / 2;
321
322 for (int y = 0; y < kernelSize; y++) {
323 const qreal yDistance = center - y;
324 for (int x = 0; x < kernelSize; x++) {
325 const qreal xDistance = center - x;
326
327 const qreal distance = std::sqrt(pow2(xDistance) + pow2(yDistance));
328
329 qreal value = 1.0;
330
331 if (distance > radius + 1e-3) {
332 value = 0.0;
333 } else if (distance > fadeStart) {
334 value = qMax(0.0, radius - distance);
335 }
336
337 matrix(x, y) = value;
338 }
339 }
340
341 return matrix;
342}
float value(const T *src, size_t ch)
qreal distance(const QPointF &p1, const QPointF &p2)
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
T pow2(const T &x)
Definition kis_global.h:166

References distance(), KIS_ASSERT_RECOVER_NOOP, pow2(), and value().

◆ createHorizontalKernel()

KisConvolutionKernelSP KisGaussianKernel::createHorizontalKernel ( qreal radius)
static

Definition at line 78 of file kis_gaussian_kernel.cpp.

79{
80 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix = createHorizontalMatrix(radius);
81 return KisConvolutionKernel::fromMatrix(matrix, 0, matrix.sum());
82}
static Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > createHorizontalMatrix(qreal radius)

References createHorizontalMatrix(), and KisConvolutionKernel::fromMatrix().

◆ createHorizontalMatrix()

Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > KisGaussianKernel::createHorizontalMatrix ( qreal radius)
static

The kernel size should always be odd, then the position of the central pixel can be easily calculated

Definition at line 28 of file kis_gaussian_kernel.cpp.

29{
30 int kernelSize = kernelSizeFromRadius(radius);
31 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix(1, kernelSize);
32
33 const qreal sigma = sigmaFromRadius(radius);
34 const qreal multiplicand = 1 / (sqrt(2 * M_PI * sigma * sigma));
35 const qreal exponentMultiplicand = 1 / (2 * sigma * sigma);
36
41 KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1);
42 const int center = kernelSize / 2;
43
44 for (int x = 0; x < kernelSize; x++) {
45 qreal xDistance = center - x;
46 matrix(0, x) = multiplicand * exp( -xDistance * xDistance * exponentMultiplicand );
47 }
48
49 return matrix;
50}
static qreal sigmaFromRadius(qreal radius)
static int kernelSizeFromRadius(qreal radius)
#define M_PI
Definition kis_global.h:111

References kernelSizeFromRadius(), KIS_ASSERT_RECOVER_NOOP, M_PI, and sigmaFromRadius().

◆ createLoGMatrix()

Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > KisGaussianKernel::createLoGMatrix ( qreal radius,
qreal coeff,
bool zeroCentered,
bool includeWrappedArea )
static

The kernel size should always be odd, then the position of the central pixel can be easily calculated

Definition at line 181 of file kis_gaussian_kernel.cpp.

182{
183 int kernelSize = 2 * (includeWrappedArea ? 2 : 1) * std::ceil(radius) + 1;
184 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix(kernelSize, kernelSize);
185
186 const qreal sigma = radius/* / sqrt(2)*/;
187 const qreal multiplicand = -1.0 / (M_PI * pow2(pow2(sigma)));
188 const qreal exponentMultiplicand = 1 / (2 * pow2(sigma));
189
194 KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1);
195 const int center = kernelSize / 2;
196
197 for (int y = 0; y < kernelSize; y++) {
198 const qreal yDistance = center - y;
199 for (int x = 0; x < kernelSize; x++) {
200 const qreal xDistance = center - x;
201 const qreal distance = pow2(xDistance) + pow2(yDistance);
202 const qreal normalizedDistance = exponentMultiplicand * distance;
203
204 matrix(x, y) = multiplicand *
205 (1.0 - normalizedDistance) *
206 exp(-normalizedDistance);
207 }
208 }
209
210 qreal lateral = matrix.sum() - matrix(center, center);
211 matrix(center, center) = -lateral;
212
213 qreal totalSum = 0;
214
215 if (zeroCentered) {
216 for (int y = 0; y < kernelSize; y++) {
217 for (int x = 0; x < kernelSize; x++) {
218 const qreal value = matrix(x, y);
219 totalSum += value;
220 }
221 }
222 }
223
224 qreal positiveSum = 0;
225 qreal sideSum = 0;
226 qreal quarterSum = 0;
227 totalSum = 0;
228
229 const qreal offset = totalSum / pow2(qreal(kernelSize));
230
231 for (int y = 0; y < kernelSize; y++) {
232 for (int x = 0; x < kernelSize; x++) {
233 qreal value = matrix(x, y);
234 value -= offset;
235 matrix(x, y) = value;
236
237 if (value > 0) {
238 positiveSum += value;
239 }
240 if (x > center) {
241 sideSum += value;
242 }
243 if (x > center && y > center) {
244 quarterSum += value;
245 }
246 totalSum += value;
247 }
248 }
249
250
251 const qreal scale = coeff * 2.0 / positiveSum;
252 matrix *= scale;
253 positiveSum *= scale;
254 sideSum *= scale;
255 quarterSum *= scale;
256
257 //qDebug() << ppVar(positiveSum) << ppVar(sideSum) << ppVar(quarterSum);
258 Q_UNUSED(sideSum);
259 Q_UNUSED(quarterSum);
260
261 return matrix;
262}

References distance(), KIS_ASSERT_RECOVER_NOOP, M_PI, pow2(), and value().

◆ createUniform2DKernel()

KisConvolutionKernelSP KisGaussianKernel::createUniform2DKernel ( qreal xRadius,
qreal yRadius )
static

Definition at line 92 of file kis_gaussian_kernel.cpp.

93{
94 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> h = createHorizontalMatrix(xRadius);
95 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> v = createVerticalMatrix(yRadius);
96
97 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> uni = v * h;
98 return KisConvolutionKernel::fromMatrix(uni, 0, uni.sum());
99}
qreal v
static Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > createVerticalMatrix(qreal radius)

References createHorizontalMatrix(), createVerticalMatrix(), KisConvolutionKernel::fromMatrix(), and v.

◆ createVerticalKernel()

KisConvolutionKernelSP KisGaussianKernel::createVerticalKernel ( qreal radius)
static

Definition at line 85 of file kis_gaussian_kernel.cpp.

86{
87 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix = createVerticalMatrix(radius);
88 return KisConvolutionKernel::fromMatrix(matrix, 0, matrix.sum());
89}

References createVerticalMatrix(), and KisConvolutionKernel::fromMatrix().

◆ createVerticalMatrix()

Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > KisGaussianKernel::createVerticalMatrix ( qreal radius)
static

The kernel size should always be odd, then the position of the central pixel can be easily calculated

Definition at line 53 of file kis_gaussian_kernel.cpp.

54{
55 int kernelSize = kernelSizeFromRadius(radius);
56 Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> matrix(kernelSize, 1);
57
58 const qreal sigma = sigmaFromRadius(radius);
59 const qreal multiplicand = 1 / (sqrt(2 * M_PI * sigma * sigma));
60 const qreal exponentMultiplicand = 1 / (2 * sigma * sigma);
61
66 KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1);
67 const int center = kernelSize / 2;
68
69 for (int y = 0; y < kernelSize; y++) {
70 qreal yDistance = center - y;
71 matrix(y, 0) = multiplicand * exp( -yDistance * yDistance * exponentMultiplicand );
72 }
73
74 return matrix;
75}

References kernelSizeFromRadius(), KIS_ASSERT_RECOVER_NOOP, M_PI, and sigmaFromRadius().

◆ kernelSizeFromRadius()

int KisGaussianKernel::kernelSizeFromRadius ( qreal radius)
static

Definition at line 21 of file kis_gaussian_kernel.cpp.

22{
23 return 6 * ceil(sigmaFromRadius(radius)) + 1;
24}

References sigmaFromRadius().

◆ sigmaFromRadius()

qreal KisGaussianKernel::sigmaFromRadius ( qreal radius)
static

Definition at line 16 of file kis_gaussian_kernel.cpp.

17{
18 return 0.3 * radius + 0.3;
19}

The documentation for this class was generated from the following files: