Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 38d9ed5

Browse files
committed
Fix accurate interpolator for affine nearest-neighbor
The interpolator was previously written to minimize bias with each step, effectively equivalent to rounding half even. However, rendering alignment requires there to be bias equivalent to rounding half up.
1 parent 529da92 commit 38d9ed5

2 files changed

Lines changed: 17 additions & 6 deletions

File tree

lib/matplotlib/tests/test_image.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,6 +1677,8 @@ def test__resample_valid_output():
16771677
@pytest.mark.parametrize("data, interpolation, expected",
16781678
[(np.array([[0.1, 0.3, 0.2]]), mimage.NEAREST,
16791679
np.array([[0.1, 0.1, 0.1, 0.3, 0.3, 0.3, 0.3, 0.2, 0.2, 0.2]])),
1680+
(np.array([[0.1, 0.2, 0.3, 0.4, 0.5, 0.6]]), mimage.NEAREST,
1681+
np.array([[0.1, 0.2, 0.2, 0.3, 0.4, 0.4, 0.5, 0.6, 0.6]])),
16801682
(np.array([[0.1, 0.3, 0.2]]), mimage.BILINEAR,
16811683
np.array([[0.1, 0.1, 0.15, 0.21, 0.27, 0.285, 0.255, 0.225, 0.2, 0.2]])),
16821684
(np.array([[0.1, 0.9]]), mimage.BILINEAR,

src/agg_workaround.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class accurate_interpolator_affine_nn
8080
void begin(double x, double y, unsigned len)
8181
{
8282
m_len = len - 1;
83+
m_cur = 0;
8384

8485
m_stx1 = x;
8586
m_sty1 = y;
@@ -98,6 +99,7 @@ class accurate_interpolator_affine_nn
9899
void resynchronize(double xe, double ye, unsigned len)
99100
{
100101
m_len = len - 1;
102+
m_cur = 0;
101103

102104
m_trans->transform(&xe, &ye);
103105
m_stx2 = xe * subpixel_scale;
@@ -107,23 +109,30 @@ class accurate_interpolator_affine_nn
107109
//----------------------------------------------------------------
108110
void operator++()
109111
{
110-
m_stx1 += (m_stx2 - m_stx1) / m_len;
111-
m_sty1 += (m_sty2 - m_sty1) / m_len;
112-
m_len--;
112+
m_cur++;
113113
}
114114

115115
//----------------------------------------------------------------
116116
void coordinates(int* x, int* y) const
117117
{
118118
// Truncate instead of round because this interpolator needs to
119119
// match the definitions for nearest-neighbor interpolation
120-
*x = int(m_stx1);
121-
*y = int(m_sty1);
120+
if (m_cur == m_len)
121+
{
122+
*x = int(m_stx2);
123+
*y = int(m_sty2);
124+
}
125+
else
126+
{
127+
// Add a tiny fudge amount to account for numerical precision loss
128+
*x = int(m_stx1 + (m_stx2 - m_stx1) * m_cur / m_len + 1e-8);
129+
*y = int(m_sty1 + (m_sty2 - m_sty1) * m_cur / m_len + 1e-8);
130+
}
122131
}
123132

124133
private:
125134
trans_type* m_trans;
126-
unsigned m_len;
135+
unsigned m_len, m_cur;
127136
double m_stx1, m_sty1, m_stx2, m_sty2;
128137
};
129138
#endif

0 commit comments

Comments
 (0)