Commit 57c3194c authored by Agata Cacko's avatar Agata Cacko

Fix results of Nearest Neighbour filter

Summary:
Before this patch the NN filter would create intermediate colors
in some circumstances, especially when scaling with the scale <50%.
Now the filter will choose one of the colors around instead of
blending colors around to get the result color.

BUG:401788

Test Plan:
- added tests to test the behaviour of NN filter
- testing on the image: http://www.bealecorner.org/red/test-patterns/star-chart-bars144-600dpi.png
- testing on the image from bug report

Reviewers: dkazakov, #krita

Reviewed By: dkazakov, #krita

Tags: #krita

Differential Revision: https://phabricator.kde.org/D20246
parent 0cf7c069
...@@ -26,19 +26,22 @@ ...@@ -26,19 +26,22 @@
#include <QGlobalStatic> #include <QGlobalStatic>
#include "kis_debug.h" #include "kis_debug.h"
#include <QtMath>
Q_GLOBAL_STATIC(KisFilterStrategyRegistry, s_instance) Q_GLOBAL_STATIC(KisFilterStrategyRegistry, s_instance)
qreal KisHermiteFilterStrategy::valueAt(qreal t) const qreal KisHermiteFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
{ {
Q_UNUSED(weightsPositionScale);
/* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
if (t < 0.0) t = -t; if (t < 0.0) t = -t;
if (t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0); if (t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
return(0.0); return(0.0);
} }
qint32 KisHermiteFilterStrategy::intValueAt(qint32 t) const qint32 KisHermiteFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const
{ {
Q_UNUSED(weightsPositionScale);
/* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
if (t < 0) t = -t; if (t < 0) t = -t;
if (t < 256) { if (t < 256) {
...@@ -55,8 +58,9 @@ qint32 KisHermiteFilterStrategy::intValueAt(qint32 t) const ...@@ -55,8 +58,9 @@ qint32 KisHermiteFilterStrategy::intValueAt(qint32 t) const
return(0); return(0);
} }
qint32 KisBicubicFilterStrategy::intValueAt(qint32 t) const qint32 KisBicubicFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const
{ {
Q_UNUSED(weightsPositionScale);
/* f(t) = 1.5|t|^3 - 2.5|t|^2 + 1, -1 <= t <= 1 */ /* f(t) = 1.5|t|^3 - 2.5|t|^2 + 1, -1 <= t <= 1 */
if (t < 0) t = -t; if (t < 0) t = -t;
if (t < 256) { if (t < 256) {
...@@ -85,29 +89,42 @@ qint32 KisBicubicFilterStrategy::intValueAt(qint32 t) const ...@@ -85,29 +89,42 @@ qint32 KisBicubicFilterStrategy::intValueAt(qint32 t) const
return(0); return(0);
} }
qreal KisBoxFilterStrategy::valueAt(qreal t) const qreal KisBoxFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
{ {
if ((t > -0.5) && (t <= 0.5)) return(1.0); if ((t >= -0.5 * weightsPositionScale) && (t < 0.5 * weightsPositionScale)) return(1.0);
return(0.0); return(0.0);
} }
qint32 KisBoxFilterStrategy::intValueAt(qint32 t) const qint32 KisBoxFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const
{ {
/* f(t) = 1, -0.5 < t <= 0.5 */ /* f(t) = 1, -0.5 < t <= 0.5 */
if ((t > -128) && (t <= 128)) if ((t >= -128 * weightsPositionScale) && (t < 128 * weightsPositionScale))
return 255; return 255;
return 0; return 0;
} }
qreal KisBilinearFilterStrategy::valueAt(qreal t) const
qreal KisBoxFilterStrategy::support(qreal weightsPositionScale)
{
return supportVal*weightsPositionScale;
}
qint32 KisBoxFilterStrategy::intSupport(qreal weightsPositionScale)
{
return qCeil(intSupportVal*weightsPositionScale);
}
qreal KisBilinearFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
{ {
Q_UNUSED(weightsPositionScale);
if (t < 0.0) t = -t; if (t < 0.0) t = -t;
if (t < 1.0) return(1.0 - t); if (t < 1.0) return(1.0 - t);
return(0.0); return(0.0);
} }
qint32 KisBilinearFilterStrategy::intValueAt(qint32 t) const qint32 KisBilinearFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const
{ {
Q_UNUSED(weightsPositionScale);
/* f(t) = |t|, -1 <= t <= 1 */ /* f(t) = |t|, -1 <= t <= 1 */
if (t < 0) t = -t; if (t < 0) t = -t;
if (t < 256) { if (t < 256) {
...@@ -119,8 +136,9 @@ qint32 KisBilinearFilterStrategy::intValueAt(qint32 t) const ...@@ -119,8 +136,9 @@ qint32 KisBilinearFilterStrategy::intValueAt(qint32 t) const
} }
qreal KisBellFilterStrategy::valueAt(qreal t) const qreal KisBellFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
{ {
Q_UNUSED(weightsPositionScale);
if (t < 0) t = -t; if (t < 0) t = -t;
if (t < .5) return(.75 - (t * t)); if (t < .5) return(.75 - (t * t));
if (t < 1.5) { if (t < 1.5) {
...@@ -130,8 +148,9 @@ qreal KisBellFilterStrategy::valueAt(qreal t) const ...@@ -130,8 +148,9 @@ qreal KisBellFilterStrategy::valueAt(qreal t) const
return(0.0); return(0.0);
} }
qreal KisBSplineFilterStrategy::valueAt(qreal t) const qreal KisBSplineFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
{ {
Q_UNUSED(weightsPositionScale);
qreal tt; qreal tt;
if (t < 0) t = -t; if (t < 0) t = -t;
...@@ -145,8 +164,9 @@ qreal KisBSplineFilterStrategy::valueAt(qreal t) const ...@@ -145,8 +164,9 @@ qreal KisBSplineFilterStrategy::valueAt(qreal t) const
return(0.0); return(0.0);
} }
qreal KisLanczos3FilterStrategy::valueAt(qreal t) const qreal KisLanczos3FilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
{ {
Q_UNUSED(weightsPositionScale);
if (t < 0) t = -t; if (t < 0) t = -t;
if (t < 3.0) return(sinc(t) * sinc(t / 3.0)); if (t < 3.0) return(sinc(t) * sinc(t / 3.0));
return(0.0); return(0.0);
...@@ -160,8 +180,9 @@ qreal KisLanczos3FilterStrategy::sinc(qreal x) const ...@@ -160,8 +180,9 @@ qreal KisLanczos3FilterStrategy::sinc(qreal x) const
return(1.0); return(1.0);
} }
qreal KisMitchellFilterStrategy::valueAt(qreal t) const qreal KisMitchellFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
{ {
Q_UNUSED(weightsPositionScale);
const qreal B = 1.0 / 3.0; const qreal B = 1.0 / 3.0;
const qreal C = 1.0 / 3.0; const qreal C = 1.0 / 3.0;
qreal tt; qreal tt;
......
...@@ -39,16 +39,20 @@ public: ...@@ -39,16 +39,20 @@ public:
QString name() { QString name() {
return m_id.name(); return m_id.name();
} }
virtual qreal valueAt(qreal /*t*/) const { virtual qreal valueAt(qreal t, qreal weightsPositionScale) const {
Q_UNUSED(t);
Q_UNUSED(weightsPositionScale);
return 0; return 0;
} }
virtual qint32 intValueAt(qint32 t) const { virtual qint32 intValueAt(qint32 t, qreal weightsPositionScale) const {
return qint32(255*valueAt(t / 256.0)); return qint32(255*valueAt(t / 256.0, weightsPositionScale));
} }
qreal support() { virtual qreal support(qreal weightsPositionScale) {
Q_UNUSED(weightsPositionScale);
return supportVal; return supportVal;
} }
qint32 intSupport() { virtual qint32 intSupport(qreal weightsPositionScale) {
Q_UNUSED(weightsPositionScale);
return intSupportVal; return intSupportVal;
} }
virtual QString description() { virtual QString description() {
...@@ -69,8 +73,8 @@ public: ...@@ -69,8 +73,8 @@ public:
} }
~KisHermiteFilterStrategy() override {} ~KisHermiteFilterStrategy() override {}
qint32 intValueAt(qint32 t) const override; qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override;
qreal valueAt(qreal t) const override; qreal valueAt(qreal t, qreal weightsPositionScale) const override;
}; };
class KRITAIMAGE_EXPORT KisBicubicFilterStrategy : public KisFilterStrategy class KRITAIMAGE_EXPORT KisBicubicFilterStrategy : public KisFilterStrategy
...@@ -85,7 +89,7 @@ public: ...@@ -85,7 +89,7 @@ public:
return i18n("Adds pixels using the color of surrounding pixels. Produces smoother tonal gradations than Bilinear."); return i18n("Adds pixels using the color of surrounding pixels. Produces smoother tonal gradations than Bilinear.");
} }
qint32 intValueAt(qint32 t) const override; qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override;
}; };
class KRITAIMAGE_EXPORT KisBoxFilterStrategy : public KisFilterStrategy class KRITAIMAGE_EXPORT KisBoxFilterStrategy : public KisFilterStrategy
{ {
...@@ -99,8 +103,12 @@ public: ...@@ -99,8 +103,12 @@ public:
return i18n("Replicate pixels in the image. Preserves all the original detail, but can produce jagged effects."); return i18n("Replicate pixels in the image. Preserves all the original detail, but can produce jagged effects.");
} }
qint32 intValueAt(qint32 t) const override; virtual qreal support(qreal weightsPositionScale) override;
qreal valueAt(qreal t) const override; virtual qint32 intSupport(qreal weightsPositionScale) override;
qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override;
qreal valueAt(qreal t, qreal weightsPositionScale) const override;
}; };
class KRITAIMAGE_EXPORT KisBilinearFilterStrategy : public KisFilterStrategy class KRITAIMAGE_EXPORT KisBilinearFilterStrategy : public KisFilterStrategy
...@@ -115,8 +123,8 @@ public: ...@@ -115,8 +123,8 @@ public:
return i18n("Adds pixels averaging the color values of surrounding pixels. Produces medium quality results when the image is scaled from half to two times the original size."); return i18n("Adds pixels averaging the color values of surrounding pixels. Produces medium quality results when the image is scaled from half to two times the original size.");
} }
qint32 intValueAt(qint32 t) const override; qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override;
qreal valueAt(qreal t) const override; qreal valueAt(qreal t, qreal weightsPositionScale) const override;
}; };
class KRITAIMAGE_EXPORT KisBellFilterStrategy : public KisFilterStrategy class KRITAIMAGE_EXPORT KisBellFilterStrategy : public KisFilterStrategy
...@@ -127,7 +135,7 @@ public: ...@@ -127,7 +135,7 @@ public:
} }
~KisBellFilterStrategy() override {} ~KisBellFilterStrategy() override {}
qreal valueAt(qreal t) const override; qreal valueAt(qreal t, qreal weightsPositionScale) const override;
}; };
class KRITAIMAGE_EXPORT KisBSplineFilterStrategy : public KisFilterStrategy class KRITAIMAGE_EXPORT KisBSplineFilterStrategy : public KisFilterStrategy
...@@ -138,7 +146,7 @@ public: ...@@ -138,7 +146,7 @@ public:
} }
~KisBSplineFilterStrategy() override {} ~KisBSplineFilterStrategy() override {}
qreal valueAt(qreal t) const override; qreal valueAt(qreal t, qreal weightsPositionScale) const override;
}; };
class KRITAIMAGE_EXPORT KisLanczos3FilterStrategy : public KisFilterStrategy class KRITAIMAGE_EXPORT KisLanczos3FilterStrategy : public KisFilterStrategy
...@@ -153,7 +161,7 @@ public: ...@@ -153,7 +161,7 @@ public:
return i18n("Offers similar results than Bicubic, but maybe a little bit sharper. Can produce light and dark halos along strong edges."); return i18n("Offers similar results than Bicubic, but maybe a little bit sharper. Can produce light and dark halos along strong edges.");
} }
qreal valueAt(qreal t) const override; qreal valueAt(qreal t, qreal weightsPositionScale) const override;
private: private:
qreal sinc(qreal x) const; qreal sinc(qreal x) const;
}; };
...@@ -166,7 +174,7 @@ public: ...@@ -166,7 +174,7 @@ public:
} }
~KisMitchellFilterStrategy() override {} ~KisMitchellFilterStrategy() override {}
qreal valueAt(qreal t) const override; qreal valueAt(qreal t, qreal weightsPositionScale) const override;
}; };
class KRITAIMAGE_EXPORT KisFilterStrategyRegistry : public KoGenericRegistry<KisFilterStrategy *> class KRITAIMAGE_EXPORT KisFilterStrategyRegistry : public KoGenericRegistry<KisFilterStrategy *>
......
...@@ -131,6 +131,7 @@ public: ...@@ -131,6 +131,7 @@ public:
KisFixedPoint dst_c = l_to_c(dst_l); KisFixedPoint dst_c = l_to_c(dst_l);
KisFixedPoint dst_c_in_src = dstToSrc(dst_c.toFloat(), line); KisFixedPoint dst_c_in_src = dstToSrc(dst_c.toFloat(), line);
// gives the nearest center of the pixel in src ( x e (0, 1> => f(x) = 0.5, x e (1, 2> => f(x) = 1.5 etc. )
KisFixedPoint next_c_in_src = (dst_c_in_src - qreal(0.5)).toIntCeil() + qreal(0.5); KisFixedPoint next_c_in_src = (dst_c_in_src - qreal(0.5)).toIntCeil() + qreal(0.5);
BlendSpan span; BlendSpan span;
...@@ -219,8 +220,12 @@ public: ...@@ -219,8 +220,12 @@ public:
if (dstStart >= dstEnd) return LinePos(dstStart, 0); if (dstStart >= dstEnd) return LinePos(dstStart, 0);
if (leftSrcBorder >= rightSrcBorder) return LinePos(dstStart, 0); if (leftSrcBorder >= rightSrcBorder) return LinePos(dstStart, 0);
if (leftSrcBorder > srcLine.start()) return LinePos(dstStart, 0); if (leftSrcBorder > srcLine.start()) {
if (srcLine.end() > rightSrcBorder) return LinePos(dstStart, 9); leftSrcBorder = srcLine.start();
}
if (srcLine.end() > rightSrcBorder) {
rightSrcBorder = srcLine.end();
}
int pixelSize = m_src->pixelSize(); int pixelSize = m_src->pixelSize();
KoMixColorsOp *mixOp = m_src->colorSpace()->mixColorsOp(); KoMixColorsOp *mixOp = m_src->colorSpace()->mixColorsOp();
......
...@@ -167,12 +167,13 @@ public: ...@@ -167,12 +167,13 @@ public:
KisFixedPoint supportDst; KisFixedPoint supportDst;
if (realScale < 1.0) { if (realScale < 1.0) {
supportSrc.from256Frac(filterStrategy->intSupport() / realScale);
supportDst.from256Frac(filterStrategy->intSupport());
m_weightsPositionScale = KisFixedPoint(realScale); m_weightsPositionScale = KisFixedPoint(realScale);
supportSrc.from256Frac(filterStrategy->intSupport(m_weightsPositionScale.toFloat()) / realScale);
supportDst.from256Frac(filterStrategy->intSupport(m_weightsPositionScale.toFloat()));
} else { } else {
supportSrc.from256Frac(filterStrategy->intSupport()); supportSrc.from256Frac(filterStrategy->intSupport(m_weightsPositionScale.toFloat()));
supportDst.from256Frac(filterStrategy->intSupport()); supportDst.from256Frac(filterStrategy->intSupport(m_weightsPositionScale.toFloat()));
} }
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) {
...@@ -203,7 +204,7 @@ public: ...@@ -203,7 +204,7 @@ public:
int sum = 0; int sum = 0;
for (int j = 0; j < span; j++) { for (int j = 0; j < span; j++) {
int t = filterStrategy->intValueAt(scaledIter.to256Frac()); int t = filterStrategy->intValueAt(scaledIter.to256Frac(), m_weightsPositionScale.toFloat());
m_filterWeights[i].weight[j] = t; m_filterWeights[i].weight[j] = t;
sum += t; sum += t;
......
...@@ -216,7 +216,7 @@ void KisTransformWorker::transformPass(KisPaintDevice *src, KisPaintDevice *dst, ...@@ -216,7 +216,7 @@ void KisTransformWorker::transformPass(KisPaintDevice *src, KisPaintDevice *dst,
KisFilterWeightsApplicator::LinePos dstPos; KisFilterWeightsApplicator::LinePos dstPos;
KisFilterWeightsApplicator::LinePos srcPos(srcStart, srcLen); KisFilterWeightsApplicator::LinePos srcPos(srcStart, srcLen);
dstPos = applicator.processLine<T>(srcPos, i, &buf, filterStrategy->support()); dstPos = applicator.processLine<T>(srcPos, i, &buf, filterStrategy->support(buf.weightsPositionScale().toFloat()));
dstBounds.unite(dstPos); dstBounds.unite(dstPos);
progressHelper.step(); progressHelper.step();
......
...@@ -198,34 +198,54 @@ void checkRA(KisPaintDeviceSP dev, int x0, int len, quint8 r[], quint8 a[], bool ...@@ -198,34 +198,54 @@ void checkRA(KisPaintDeviceSP dev, int x0, int len, quint8 r[], quint8 a[], bool
} }
} }
void testLineImpl(qreal scale, qreal dx, quint8 expR[], quint8 expA[], int x0, int len, bool clampToEdge, bool horizontal) void testLineImpl(qreal scale, qreal dx, quint8 expR[], quint8 expA[], int x0, int len, bool clampToEdge, bool horizontal, KisFilterStrategy *filter = 0, KisPaintDeviceSP dev = 0)
{ {
int startPos = 0;
int endPos = 4;
const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
KisPaintDeviceSP dev = new KisPaintDevice(cs); if (!filter) {
KisFilterStrategy *filter = new KisBilinearFilterStrategy(); filter = new KisBilinearFilterStrategy();
}
if (!dev) {
dev = new KisPaintDevice(cs);
KisFilterWeightsBuffer buf(filter, qAbs(scale)); for (int i = 0; i < 4; i++) {
KisFilterWeightsApplicator applicator(dev, dev, scale, 0.0, dx, clampToEdge); int x = horizontal ? i : 0;
int y = horizontal ? 0 : i;
dev->setPixel(x,y,QColor(10 + i * 10, 20 + i * 10, 40 + i * 10));
}
for (int i = 0; i < 4; i++) { {
int x = horizontal ? i : 0; quint8 r[] = { 0, 10, 20, 30, 40, 0, 0};
int y = horizontal ? 0 : i; quint8 a[] = { 0,255,255,255,255, 0, 0};
dev->setPixel(x,y,QColor(10 + i * 10, 20 + i * 10, 40 + i * 10)); checkRA(dev, -1, 6, r, a, horizontal);
} }
startPos = 0;
endPos = 4;
{ } else {
quint8 r[] = { 0, 10, 20, 30, 40, 0, 0}; QRect rc = dev->exactBounds();
quint8 a[] = { 0,255,255,255,255, 0, 0}; if (horizontal) {
checkRA(dev, -1, 6, r, a, horizontal); startPos = rc.left();
endPos = rc.left() + rc.width();
} else {
startPos = rc.top();
endPos = rc.top() + rc.height();
}
} }
KisFilterWeightsApplicator::LinePos srcPos(0,4); KisFilterWeightsBuffer buf(filter, qAbs(scale));
KisFilterWeightsApplicator applicator(dev, dev, scale, 0.0, dx, clampToEdge);
KisFilterWeightsApplicator::LinePos srcPos(startPos, endPos);
KisFilterWeightsApplicator::LinePos dstPos; KisFilterWeightsApplicator::LinePos dstPos;
if (horizontal) { if (horizontal) {
dstPos = applicator.processLine<KisHLineIteratorSP>(srcPos,0,&buf, filter->support()); dstPos = applicator.processLine<KisHLineIteratorSP>(srcPos,0,&buf, filter->support(buf.weightsPositionScale().toFloat()));
} else { } else {
dstPos = applicator.processLine<KisVLineIteratorSP>(srcPos,0,&buf, filter->support()); dstPos = applicator.processLine<KisVLineIteratorSP>(srcPos,0,&buf, filter->support(buf.weightsPositionScale().toFloat()));
} }
QRect rc = dev->exactBounds(); QRect rc = dev->exactBounds();
...@@ -242,10 +262,10 @@ void testLineImpl(qreal scale, qreal dx, quint8 expR[], quint8 expA[], int x0, i ...@@ -242,10 +262,10 @@ void testLineImpl(qreal scale, qreal dx, quint8 expR[], quint8 expA[], int x0, i
checkRA(dev, x0, len, expR, expA, horizontal); checkRA(dev, x0, len, expR, expA, horizontal);
} }
void testLine(qreal scale, qreal dx, quint8 expR[], quint8 expA[], int x0, int len, bool clampToEdge = false) void testLine(qreal scale, qreal dx, quint8 expR[], quint8 expA[], int x0, int len, bool clampToEdge = false, KisFilterStrategy* filter = 0, KisPaintDeviceSP dev = 0)
{ {
testLineImpl(scale, dx, expR, expA, x0, len, clampToEdge, true); testLineImpl(scale, dx, expR, expA, x0, len, clampToEdge, true, filter, dev);
testLineImpl(scale, dx, expR, expA, x0, len, clampToEdge, false); testLineImpl(scale, dx, expR, expA, x0, len, clampToEdge, false, filter, dev);
} }
void KisFilterWeightsApplicatorTest::testProcessLine_Scale_1_0_Aligned() void KisFilterWeightsApplicatorTest::testProcessLine_Scale_1_0_Aligned()
...@@ -435,6 +455,173 @@ void KisFilterWeightsApplicatorTest::testProcessLine_Scale_0_5_Shift_0_125_Mirro ...@@ -435,6 +455,173 @@ void KisFilterWeightsApplicatorTest::testProcessLine_Scale_0_5_Shift_0_125_Mirro
testLine(scale, dx, r, a, -6, 10); testLine(scale, dx, r, a, -6, 10);
} }
void KisFilterWeightsApplicatorTest::testProcessLine_NearestNeighbourFilter_2x()
{
qreal scale = 2.0;
qreal dx = 0;
quint8 r[] = {0, 10, 10, 20, 20, 30, 30, 40, 40, 0, 0};
quint8 a[] = {0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0};
KisFilterStrategy* filter = new KisBoxFilterStrategy();
testLine(scale, dx, r, a, -1, 11, true, filter);
}
void KisFilterWeightsApplicatorTest::testProcessLine_NearestNeighbourFilter_1x()
{
qreal scale = 1.0;
qreal dx = 0;
quint8 r[] = { 0, 10, 20, 30, 40, 0, 0};
quint8 a[] = { 0,255,255,255,255, 0, 0};
KisFilterStrategy* filter = new KisBoxFilterStrategy();
testLine(scale, dx, r, a, -1, 7, false, filter);
}
void KisFilterWeightsApplicatorTest::testProcessLine_NearestNeighbourFilter_05x()
{
qreal scale = 0.5;
qreal dx = 0;
quint8 r[] = { 0, 10, 30, 0, 0, 0, 0};
quint8 a[] = { 0,255,255, 0, 0, 0, 0};
KisFilterStrategy* filter = new KisBoxFilterStrategy();
testLine(scale, dx, r, a, -1, 7, false, filter);
}
void KisFilterWeightsApplicatorTest::testProcessLine_NearestNeighbourFilter_077x()
{
qreal scale = 0.77;
qreal dx = 0;
quint8 r[] = { 0, 10, 20, 40, 0, 0, 0};
quint8 a[] = { 0,255,255, 255, 0, 0, 0};
KisFilterStrategy* filter = new KisBoxFilterStrategy();
testLine(scale, dx, r, a, -1, 7, false, filter);
}
void KisFilterWeightsApplicatorTest::testProcessLine_NearestNeighbourFilter_074x()
{
qreal scale = 0.74;
qreal dx = 0;
quint8 r[] = { 0, 10, 30, 40, 0, 0, 0};
quint8 a[] = { 0,255,255, 255, 0, 0, 0};
KisFilterStrategy* filter = new KisBoxFilterStrategy();
testLine(scale, dx, r, a, -1, 7, false, filter);
}
void KisFilterWeightsApplicatorTest::testProcessLine_NearestNeighbourFilter_075x()
{
qreal scale = 0.75;
qreal dx = 0;
quint8 r[] = { 0, 10, 20, 40, 0, 0, 0};
quint8 a[] = { 0,255,255, 255, 0, 0, 0};
KisFilterStrategy* filter = new KisBoxFilterStrategy();
testLine(scale, dx, r, a, -1, 7, false, filter);
}
void KisFilterWeightsApplicatorTest::testProcessLine_NearestNeighbourFilter_15x()
{
qreal scale = 1.5;
qreal dx = 0;
quint8 r[] = { 0, 10, 10, 20, 30, 30, 40};
quint8 a[] = { 0,255,255, 255, 255, 255, 255};
KisFilterStrategy* filter = new KisBoxFilterStrategy();
testLine(scale, dx, r, a, -1, 7, false, filter);
}
KisPaintDeviceSP prepareUniformPaintDevice(int pixelsNumber, bool horizontal)
{
const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
KisPaintDeviceSP dev = new KisPaintDevice(cs);
for (int i = 0; i < pixelsNumber; i++) {
int x = horizontal ? i : 0;
int y = horizontal ? 0 : i;
QColor c = QColor(10, 0, 0, 255);
dev->setPixel(x, y, c);
}
return dev;
}
void prepareUniformPixels(quint8 r[], quint8 a[], int pixelsNumber, bool horizontal)
{
for (int i = 0; i < pixelsNumber; i++) {
QColor c = QColor(10, 0, 0, 255);
r[i] = c.red();
a[i] = c.alpha();
}
}
void KisFilterWeightsApplicatorTest::testProcessLine_NearestNeighbourFilter_0098x_horizontal()
{
int before = 5075;
int after = 500;
qreal scale = before/after;
qreal dx = 0;
bool horizontal = true;
KisPaintDeviceSP dev = prepareUniformPaintDevice(before, horizontal);
quint8 *r = new quint8[after];
quint8 *a = new quint8[after];
prepareUniformPixels(r, a, after, horizontal);
KisFilterStrategy* filter = new KisBoxFilterStrategy();
testLineImpl(scale, dx, r, a, 0, after, false, horizontal, filter, dev);
}
void KisFilterWeightsApplicatorTest::testProcessLine_NearestNeighbourFilter_0098x_vertical()
{
int before = 4725;
int after = 466;
qreal scale = before/after;
qreal dx = 0;
bool horizontal = false;
KisPaintDeviceSP dev = prepareUniformPaintDevice(before, horizontal);
quint8 *r = new quint8[after];
quint8 *a = new quint8[after];
prepareUniformPixels(r, a, after, horizontal);
KisFilterStrategy* filter = new KisBoxFilterStrategy();
testLineImpl(scale, dx, r, a, 0, after, false, horizontal, filter, dev);
}
void KisFilterWeightsApplicatorTest::benchmarkProcesssLine() void KisFilterWeightsApplicatorTest::benchmarkProcesssLine()
{ {
const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
...@@ -454,7 +641,7 @@ void KisFilterWeightsApplicatorTest::benchmarkProcesssLine() ...@@ -454,7 +641,7 @@ void KisFilterWeightsApplicatorTest::benchmarkProcesssLine()
KisFilterWeightsApplicator::LinePos linePos(0,32767); KisFilterWeightsApplicator::LinePos linePos(0,32767);
QBENCHMARK { QBENCHMARK {