Coverage Report

Created: 2025-11-16 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/Simd/src/Simd/SimdBaseShiftBilinear.cpp
Line
Count
Source
1
/*
2
* Simd Library (http://ermig1979.github.io/Simd).
3
*
4
* Copyright (c) 2011-2017 Yermalayeu Ihar.
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a copy
7
* of this software and associated documentation files (the "Software"), to deal
8
* in the Software without restriction, including without limitation the rights
9
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
* copies of the Software, and to permit persons to whom the Software is
11
* furnished to do so, subject to the following conditions:
12
*
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
15
*
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* SOFTWARE.
23
*/
24
#include "Simd/SimdMath.h"
25
#include "Simd/SimdBase.h"
26
27
namespace Simd
28
{
29
    namespace Base
30
    {
31
        SIMD_INLINE int Interpolate(int s[2][2], int k[2][2])
32
0
        {
33
0
            return (s[0][0] * k[0][0] + s[0][1] * k[0][1] +
34
0
                s[1][0] * k[1][0] + s[1][1] * k[1][1] + BILINEAR_ROUND_TERM) >> BILINEAR_SHIFT;
35
0
        }
36
37
        SIMD_INLINE int Interpolate(const unsigned char *src, size_t dx, size_t dy, int k[2][2])
38
0
        {
39
0
            return (src[0] * k[0][0] + src[dx] * k[0][1] +
40
0
                src[dy] * k[1][0] + src[dx + dy] * k[1][1] + BILINEAR_ROUND_TERM) >> BILINEAR_SHIFT;
41
0
        }
42
43
        SIMD_INLINE int Interpolate(const unsigned char *src, size_t dr, int k[2])
44
0
        {
45
0
            return (src[0] * k[0] + src[dr] * k[1] + LINEAR_ROUND_TERM) >> LINEAR_SHIFT;
46
0
        }
47
48
        void MixBorder(const uint8_t * src, size_t srcStride, size_t width, size_t height, size_t channelCount,
49
            const uint8_t * bkg, size_t bkgStride, ptrdiff_t iDx, ptrdiff_t iDy, int fDx, int fDy, uint8_t * dst, size_t dstStride)
50
0
        {
51
0
            size_t bkgWidth = Abs(iDx) - (iDx < 0 && fDx ? 1 : 0);
52
0
            size_t bkgHeight = Abs(iDy) - (iDy < 0 && fDy ? 1 : 0);
53
54
0
            size_t mainWidth = width - bkgWidth - (fDx ? 1 : 0);
55
0
            size_t mainHeight = height - bkgHeight - (fDy ? 1 : 0);
56
57
0
            int k[2][2];
58
0
            k[0][0] = (FRACTION_RANGE - fDx)*(FRACTION_RANGE - fDy);
59
0
            k[0][1] = fDx*(FRACTION_RANGE - fDy);
60
0
            k[1][0] = (FRACTION_RANGE - fDx)*fDy;
61
0
            k[1][1] = fDx*fDy;
62
63
0
            if (fDx)
64
0
            {
65
0
                const uint8_t * ps[2][2];
66
0
                size_t xOffset = (iDx >= 0 ? width - 1 - iDx : -iDx - 1)*channelCount;
67
0
                size_t bkgOffset = (iDy > 0 ? 0 : -iDy)*bkgStride + xOffset;
68
0
                size_t dstOffset = (iDy > 0 ? 0 : -iDy)*dstStride + xOffset;
69
70
0
                if (iDx < 0)
71
0
                {
72
0
                    ps[0][0] = bkg + bkgOffset;
73
0
                    ps[0][1] = src + (iDy < 0 ? 0 : iDy)*srcStride;
74
0
                    ps[1][0] = bkg + bkgOffset;
75
0
                    ps[1][1] = src + ((iDy < 0 ? 0 : iDy) + (fDy ? 1 : 0))*srcStride;
76
0
                }
77
0
                else
78
0
                {
79
0
                    ps[0][0] = src + (iDy < 0 ? 0 : iDy)*srcStride + (width - 1)*channelCount;
80
0
                    ps[0][1] = bkg + bkgOffset;
81
0
                    ps[1][0] = src + ((iDy < 0 ? 0 : iDy) + (fDy ? 1 : 0))*srcStride + (width - 1)*channelCount;
82
0
                    ps[1][1] = bkg + bkgOffset;
83
0
                }
84
85
0
                for (size_t row = 0; row < mainHeight; ++row)
86
0
                {
87
0
                    for (size_t channel = 0; channel < channelCount; channel++)
88
0
                    {
89
0
                        int s[2][2];
90
0
                        s[0][0] = ps[0][0][channel];
91
0
                        s[0][1] = ps[0][1][channel];
92
0
                        s[1][0] = ps[1][0][channel];
93
0
                        s[1][1] = ps[1][1][channel];
94
0
                        dst[dstOffset + channel] = Interpolate(s, k);
95
0
                    }
96
0
                    ps[0][0] += srcStride;
97
0
                    ps[0][1] += bkgStride;
98
0
                    ps[1][0] += srcStride;
99
0
                    ps[1][1] += bkgStride;
100
0
                    dstOffset += dstStride;
101
0
                }
102
0
            }
103
104
0
            if (fDy)
105
0
            {
106
0
                const uint8_t * ps[2][2];
107
0
                size_t bkgOffset = (iDy >= 0 ? height - 1 - iDy : -iDy - 1)*bkgStride + (iDx > 0 ? 0 : -iDx)*channelCount;
108
0
                size_t dstOffset = (iDy >= 0 ? height - 1 - iDy : -iDy - 1)*dstStride + (iDx > 0 ? 0 : -iDx)*channelCount;
109
110
0
                if (iDy < 0)
111
0
                {
112
0
                    ps[0][0] = bkg + bkgOffset;
113
0
                    ps[0][1] = bkg + bkgOffset;
114
0
                    ps[1][0] = src + (iDx < 0 ? 0 : iDx)*channelCount;
115
0
                    ps[1][1] = src + ((iDx < 0 ? 0 : iDx) + (fDx ? 1 : 0))*channelCount;
116
0
                }
117
0
                else
118
0
                {
119
0
                    ps[0][0] = src + (height - 1)*srcStride + (iDx < 0 ? 0 : iDx)*channelCount;
120
0
                    ps[0][1] = src + (height - 1)*srcStride + ((iDx < 0 ? 0 : iDx) + (fDx ? 1 : 0))*channelCount;
121
0
                    ps[1][0] = bkg + bkgOffset;
122
0
                    ps[1][1] = bkg + bkgOffset;
123
0
                }
124
125
0
                for (size_t col = 0; col < mainWidth; ++col)
126
0
                {
127
0
                    for (size_t channel = 0; channel < channelCount; channel++)
128
0
                    {
129
0
                        int s[2][2];
130
0
                        s[0][0] = ps[0][0][channel];
131
0
                        s[0][1] = ps[0][1][channel];
132
0
                        s[1][0] = ps[1][0][channel];
133
0
                        s[1][1] = ps[1][1][channel];
134
0
                        dst[dstOffset + channel] = Interpolate(s, k);
135
0
                    }
136
0
                    ps[0][0] += channelCount;
137
0
                    ps[0][1] += channelCount;
138
0
                    ps[1][0] += channelCount;
139
0
                    ps[1][1] += channelCount;
140
0
                    dstOffset += channelCount;
141
0
                }
142
0
            }
143
144
0
            if (fDx && fDy)
145
0
            {
146
0
                const uint8_t * ps[2][2];
147
0
                size_t xOffset = (iDx >= 0 ? width - 1 - iDx : -iDx - 1)*channelCount;
148
0
                size_t bkgOffset = (iDy >= 0 ? height - 1 - iDy : -iDy - 1)*bkgStride + xOffset;
149
0
                size_t dstOffset = (iDy >= 0 ? height - 1 - iDy : -iDy - 1)*dstStride + xOffset;
150
151
0
                ps[0][0] = (iDx >= 0 && iDy >= 0) ? (src + (height - 1)*srcStride + (width - 1)*channelCount) : bkg + bkgOffset;
152
0
                ps[0][1] = (iDx < 0 && iDy >= 0) ? (src + (height - 1)*srcStride) : bkg + bkgOffset;
153
0
                ps[1][0] = (iDx >= 0 && iDy < 0) ? (src + (width - 1)*channelCount) : bkg + bkgOffset;
154
0
                ps[1][1] = (iDx < 0 && iDy < 0) ? (src) : bkg + bkgOffset;
155
156
0
                for (size_t channel = 0; channel < channelCount; channel++)
157
0
                {
158
0
                    int s[2][2];
159
0
                    s[0][0] = ps[0][0][channel];
160
0
                    s[0][1] = ps[0][1][channel];
161
0
                    s[1][0] = ps[1][0][channel];
162
0
                    s[1][1] = ps[1][1][channel];
163
0
                    dst[dstOffset + channel] = Interpolate(s, k);
164
0
                }
165
0
            }
166
0
        }
167
168
        void CommonShiftAction(
169
            const uint8_t * & src, size_t srcStride, size_t & width, size_t & height, size_t channelCount,
170
            const uint8_t * bkg, size_t bkgStride, const double * shiftX, const double * shiftY,
171
            size_t cropLeft, size_t cropTop, size_t cropRight, size_t cropBottom, uint8_t * & dst, size_t dstStride,
172
            int & fDx, int & fDy)
173
0
        {
174
0
            assert(cropLeft <= cropRight && cropTop <= cropBottom && cropRight <= width && cropBottom <= height);
175
0
            assert(*shiftX < cropRight - cropLeft && *shiftY < cropBottom - cropTop);
176
177
0
            Base::CopyFrame(src, srcStride, width, height, channelCount, cropLeft, cropTop, cropRight, cropBottom, dst, dstStride);
178
179
0
            dst += dstStride*cropTop + cropLeft*channelCount;
180
0
            src += srcStride*cropTop + cropLeft*channelCount;
181
0
            bkg += bkgStride*cropTop + cropLeft*channelCount;
182
0
            width = cropRight - cropLeft;
183
0
            height = cropBottom - cropTop;
184
185
0
            ptrdiff_t iDx = (ptrdiff_t)floor(*shiftX + FRACTION_ROUND_TERM);
186
0
            ptrdiff_t iDy = (ptrdiff_t)floor(*shiftY + FRACTION_ROUND_TERM);
187
0
            fDx = (int)floor((*shiftX + FRACTION_ROUND_TERM - iDx)*FRACTION_RANGE);
188
0
            fDy = (int)floor((*shiftY + FRACTION_ROUND_TERM - iDy)*FRACTION_RANGE);
189
190
0
            ptrdiff_t left = (iDx < 0 ? (-iDx - (fDx ? 1 : 0)) : 0);
191
0
            ptrdiff_t top = (iDy < 0 ? (-iDy - (fDy ? 1 : 0)) : 0);
192
0
            ptrdiff_t right = (iDx < 0 ? width : width - iDx);
193
0
            ptrdiff_t bottom = (iDy < 0 ? height : height - iDy);
194
195
0
            Base::CopyFrame(bkg, bkgStride, width, height, channelCount, left, top, right, bottom, dst, dstStride);
196
197
0
            MixBorder(src, srcStride, width, height, channelCount, bkg, bkgStride, iDx, iDy, fDx, fDy, dst, dstStride);
198
199
0
            src += Simd::Max((ptrdiff_t)0, iDy)*srcStride + Simd::Max((ptrdiff_t)0, iDx)*channelCount;
200
0
            dst += Simd::Max((ptrdiff_t)0, -iDy)*dstStride + Simd::Max((ptrdiff_t)0, -iDx)*channelCount;
201
202
0
            width = width - Abs(iDx) + (iDx < 0 && fDx ? 1 : 0) - (fDx ? 1 : 0);
203
0
            height = height - Abs(iDy) + (iDy < 0 && fDy ? 1 : 0) - (fDy ? 1 : 0);
204
0
        }
205
206
        void ShiftBilinear(const uint8_t * src, size_t srcStride, size_t width, size_t height, size_t channelCount,
207
            int fDx, int fDy, uint8_t * dst, size_t dstStride)
208
0
        {
209
0
            size_t size = width*channelCount;
210
0
            if (fDy)
211
0
            {
212
0
                if (fDx)
213
0
                {
214
0
                    int k[2][2];
215
0
                    k[0][0] = (FRACTION_RANGE - fDx)*(FRACTION_RANGE - fDy);
216
0
                    k[0][1] = fDx*(FRACTION_RANGE - fDy);
217
0
                    k[1][0] = (FRACTION_RANGE - fDx)*fDy;
218
0
                    k[1][1] = fDx*fDy;
219
0
                    for (size_t row = 0; row < height; ++row)
220
0
                    {
221
0
                        for (size_t col = 0; col < size; col++)
222
0
                        {
223
0
                            dst[col] = Interpolate(src + col, channelCount, srcStride, k);
224
0
                        }
225
0
                        src += srcStride;
226
0
                        dst += dstStride;
227
0
                    }
228
0
                }
229
0
                else
230
0
                {
231
0
                    int k[2];
232
0
                    k[0] = FRACTION_RANGE - fDy;
233
0
                    k[1] = fDy;
234
0
                    for (size_t row = 0; row < height; ++row)
235
0
                    {
236
0
                        for (size_t col = 0; col < size; col++)
237
0
                        {
238
0
                            dst[col] = Interpolate(src + col, srcStride, k);
239
0
                        }
240
0
                        src += srcStride;
241
0
                        dst += dstStride;
242
0
                    }
243
0
                }
244
0
            }
245
0
            else
246
0
            {
247
0
                if (fDx)
248
0
                {
249
0
                    int k[2];
250
0
                    k[0] = FRACTION_RANGE - fDx;
251
0
                    k[1] = fDx;
252
0
                    for (size_t row = 0; row < height; ++row)
253
0
                    {
254
0
                        for (size_t col = 0; col < size; col++)
255
0
                        {
256
0
                            dst[col] = Interpolate(src + col, channelCount, k);
257
0
                        }
258
0
                        src += srcStride;
259
0
                        dst += dstStride;
260
0
                    }
261
0
                }
262
0
                else
263
0
                {
264
0
                    for (size_t row = 0; row < height; ++row)
265
0
                    {
266
0
                        memcpy(dst, src, size);
267
0
                        src += srcStride;
268
0
                        dst += dstStride;
269
0
                    }
270
0
                }
271
0
            }
272
0
        }
273
274
        void ShiftBilinear(
275
            const uint8_t * src, size_t srcStride, size_t width, size_t height, size_t channelCount,
276
            const uint8_t * bkg, size_t bkgStride, const double * shiftX, const double * shiftY,
277
            size_t cropLeft, size_t cropTop, size_t cropRight, size_t cropBottom, uint8_t * dst, size_t dstStride)
278
0
        {
279
0
            int fDx, fDy;
280
0
            CommonShiftAction(src, srcStride, width, height, channelCount, bkg, bkgStride, shiftX, shiftY,
281
0
                cropLeft, cropTop, cropRight, cropBottom, dst, dstStride, fDx, fDy);
282
283
0
            ShiftBilinear(src, srcStride, width, height, channelCount, fDx, fDy, dst, dstStride);
284
0
        }
285
    }
286
}
287