8#include "bilinear_expansion.h"
14FASTLED_NAMESPACE_BEGIN
17uint8_t bilinearInterpolate(uint8_t v00, uint8_t v10, uint8_t v01,
18 uint8_t v11, uint16_t dx, uint16_t dy);
20uint8_t bilinearInterpolatePowerOf2(uint8_t v00, uint8_t v10, uint8_t v01,
21 uint8_t v11, uint8_t dx, uint8_t dy);
24void bilinearExpandArbitrary(
const CRGB *input,
CRGB *output, uint16_t inputWidth,
25 uint16_t inputHeight,
XYMap xyMap) {
26 uint16_t n = xyMap.getTotal();
27 uint16_t outputWidth = xyMap.getWidth();
28 uint16_t outputHeight = xyMap.getHeight();
29 const uint16_t scale_factor = 256;
31 for (uint16_t y = 0; y < outputHeight; y++) {
32 for (uint16_t x = 0; x < outputWidth; x++) {
34 uint32_t fx = ((uint32_t)x * (inputWidth - 1) * scale_factor) /
36 uint32_t fy = ((uint32_t)y * (inputHeight - 1) * scale_factor) /
39 uint16_t ix = fx / scale_factor;
40 uint16_t iy = fy / scale_factor;
41 uint16_t dx = fx % scale_factor;
42 uint16_t dy = fy % scale_factor;
44 uint16_t ix1 = (ix + 1 < inputWidth) ? ix + 1 : ix;
45 uint16_t iy1 = (iy + 1 < inputHeight) ? iy + 1 : iy;
47 uint16_t i00 = iy * inputWidth + ix;
48 uint16_t i10 = iy * inputWidth + ix1;
49 uint16_t i01 = iy1 * inputWidth + ix;
50 uint16_t i11 = iy1 * inputWidth + ix1;
52 CRGB c00 = input[i00];
53 CRGB c10 = input[i10];
54 CRGB c01 = input[i01];
55 CRGB c11 = input[i11];
58 result.
r = bilinearInterpolate(c00.
r, c10.
r, c01.
r, c11.
r, dx, dy);
59 result.
g = bilinearInterpolate(c00.
g, c10.
g, c01.
g, c11.
g, dx, dy);
60 result.
b = bilinearInterpolate(c00.
b, c10.
b, c01.
b, c11.
b, dx, dy);
62 uint16_t idx = xyMap.mapToIndex(x, y);
69uint8_t bilinearInterpolate(uint8_t v00, uint8_t v10, uint8_t v01, uint8_t v11,
70 uint16_t dx, uint16_t dy) {
71 uint16_t dx_inv = 256 - dx;
72 uint16_t dy_inv = 256 - dy;
74 uint32_t w00 = (uint32_t)dx_inv * dy_inv;
75 uint32_t w10 = (uint32_t)dx * dy_inv;
76 uint32_t w01 = (uint32_t)dx_inv * dy;
77 uint32_t w11 = (uint32_t)dx * dy;
79 uint32_t sum = v00 * w00 + v10 * w10 + v01 * w01 + v11 * w11;
83 uint8_t result = (uint8_t)((sum + 32768) >> 16);
88void bilinearExpandPowerOf2(
const CRGB *input,
CRGB *output, uint8_t inputWidth, uint8_t inputHeight,
XYMap xyMap) {
89 uint8_t width = xyMap.getWidth();
90 uint8_t height = xyMap.getHeight();
91 if (width != xyMap.getWidth() || height != xyMap.getHeight()) {
95 uint16_t n = xyMap.getTotal();
97 for (uint8_t y = 0; y < height; y++) {
98 for (uint8_t x = 0; x < width; x++) {
101 uint16_t fx = ((uint16_t)x * (inputWidth - 1) * 256) / (width - 1);
103 ((uint16_t)y * (inputHeight - 1) * 256) / (height - 1);
105 uint8_t ix = fx >> 8;
106 uint8_t iy = fy >> 8;
107 uint8_t dx = fx & 0xFF;
108 uint8_t dy = fy & 0xFF;
110 uint8_t ix1 = (ix + 1 < inputWidth) ? ix + 1 : ix;
111 uint8_t iy1 = (iy + 1 < inputHeight) ? iy + 1 : iy;
113 uint16_t i00 = iy * inputWidth + ix;
114 uint16_t i10 = iy * inputWidth + ix1;
115 uint16_t i01 = iy1 * inputWidth + ix;
116 uint16_t i11 = iy1 * inputWidth + ix1;
118 CRGB c00 = input[i00];
119 CRGB c10 = input[i10];
120 CRGB c01 = input[i01];
121 CRGB c11 = input[i11];
124 result.
r = bilinearInterpolatePowerOf2(c00.
r, c10.
r, c01.
r, c11.
r, dx, dy);
125 result.
g = bilinearInterpolatePowerOf2(c00.
g, c10.
g, c01.
g, c11.
g, dx, dy);
126 result.
b = bilinearInterpolatePowerOf2(c00.
b, c10.
b, c01.
b, c11.
b, dx, dy);
128 uint16_t idx = xyMap.mapToIndex(x, y);
130 output[idx] = result;
136uint8_t bilinearInterpolatePowerOf2(uint8_t v00, uint8_t v10, uint8_t v01,
137 uint8_t v11, uint8_t dx, uint8_t dy) {
138 uint16_t dx_inv = 256 - dx;
139 uint16_t dy_inv = 256 - dy;
142 uint16_t w00 = (dx_inv * dy_inv) >> 8;
143 uint16_t w10 = (dx * dy_inv) >> 8;
144 uint16_t w01 = (dx_inv * dy) >> 8;
145 uint16_t w11 = (dx * dy) >> 8;
148 uint16_t weight_sum = w00 + w10 + w01 + w11;
151 uint16_t sum = v00 * w00 + v10 * w10 + v01 * w01 + v11 * w11;
154 uint8_t result = (sum + (weight_sum >> 1)) / weight_sum;
165#include "bilinear_expansion.h"
167#include "namespace.h"
171FASTLED_NAMESPACE_BEGIN
174uint8_t bilinearInterpolateFloat(uint8_t v00, uint8_t v10, uint8_t v01,
175 uint8_t v11,
float dx,
float dy) {
176 float dx_inv = 1.0f - dx;
177 float dy_inv = 1.0f - dy;
180 float w00 = dx_inv * dy_inv;
181 float w10 = dx * dy_inv;
182 float w01 = dx_inv * dy;
186 float sum = v00 * w00 + v10 * w10 + v01 * w01 + v11 * w11;
189 uint8_t result =
static_cast<uint8_t
>(sum + 0.5f);
195void bilinearExpandArbitraryFloat(
const CRGB *input,
CRGB *output,
196 uint16_t inputWidth, uint16_t inputHeight,
198 uint16_t n = xyMap.getTotal();
199 uint16_t outputWidth = xyMap.getWidth();
200 uint16_t outputHeight = xyMap.getHeight();
202 for (uint16_t y = 0; y < outputHeight; y++) {
203 for (uint16_t x = 0; x < outputWidth; x++) {
205 float fx =
static_cast<float>(x) * (inputWidth - 1) / (outputWidth - 1);
206 float fy =
static_cast<float>(y) * (inputHeight - 1) / (outputHeight - 1);
208 uint16_t ix =
static_cast<uint16_t
>(fx);
209 uint16_t iy =
static_cast<uint16_t
>(fy);
213 uint16_t ix1 = (ix + 1 < inputWidth) ? ix + 1 : ix;
214 uint16_t iy1 = (iy + 1 < inputHeight) ? iy + 1 : iy;
216 uint16_t i00 = iy * inputWidth + ix;
217 uint16_t i10 = iy * inputWidth + ix1;
218 uint16_t i01 = iy1 * inputWidth + ix;
219 uint16_t i11 = iy1 * inputWidth + ix1;
221 CRGB c00 = input[i00];
222 CRGB c10 = input[i10];
223 CRGB c01 = input[i01];
224 CRGB c11 = input[i11];
227 result.
r = bilinearInterpolateFloat(c00.
r, c10.
r, c01.
r, c11.
r, dx, dy);
228 result.
g = bilinearInterpolateFloat(c00.
g, c10.
g, c01.
g, c11.
g, dx, dy);
229 result.
b = bilinearInterpolateFloat(c00.
b, c10.
b, c01.
b, c11.
b, dx, dy);
231 uint16_t idx = xyMap.mapToIndex(x, y);
233 output[idx] = result;
240void bilinearExpandFloat(
const CRGB *input,
CRGB *output,
241 uint8_t inputWidth, uint8_t inputHeight,
243 uint8_t outputWidth = xyMap.getWidth();
244 uint8_t outputHeight = xyMap.getHeight();
245 if (outputWidth != xyMap.getWidth() || outputHeight != xyMap.getHeight()) {
249 uint16_t n = xyMap.getTotal();
251 for (uint8_t y = 0; y < outputHeight; y++) {
252 for (uint8_t x = 0; x < outputWidth; x++) {
254 float fx =
static_cast<float>(x) * (inputWidth - 1) / (outputWidth - 1);
255 float fy =
static_cast<float>(y) * (inputHeight - 1) / (outputHeight - 1);
257 uint8_t ix =
static_cast<uint8_t
>(fx);
258 uint8_t iy =
static_cast<uint8_t
>(fy);
262 uint8_t ix1 = (ix + 1 < inputWidth) ? ix + 1 : ix;
263 uint8_t iy1 = (iy + 1 < inputHeight) ? iy + 1 : iy;
265 uint16_t i00 = iy * inputWidth + ix;
266 uint16_t i10 = iy * inputWidth + ix1;
267 uint16_t i01 = iy1 * inputWidth + ix;
268 uint16_t i11 = iy1 * inputWidth + ix1;
270 CRGB c00 = input[i00];
271 CRGB c10 = input[i10];
272 CRGB c01 = input[i01];
273 CRGB c11 = input[i11];
276 result.
r = bilinearInterpolateFloat(c00.
r, c10.
r, c01.
r, c11.
r, dx, dy);
277 result.
g = bilinearInterpolateFloat(c00.
g, c10.
g, c01.
g, c11.
g, dx, dy);
278 result.
b = bilinearInterpolateFloat(c00.
b, c10.
b, c01.
b, c11.
b, dx, dy);
280 uint16_t idx = xyMap.mapToIndex(x, y);
282 output[idx] = result;
uint8_t r
Red channel value.
uint8_t g
Green channel value.
uint8_t b
Blue channel value.
Representation of an RGB pixel (Red, Green, Blue)